blob: 5ea59ca20ffa621c12fbffe63aeda0d52211e207 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070044import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020045import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
47import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070051import android.content.IIntentReceiver;
52import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.pm.ActivityInfo;
54import android.content.pm.ApplicationInfo;
55import android.content.pm.ConfigurationInfo;
56import android.content.pm.IPackageDataObserver;
57import android.content.pm.IPackageManager;
58import android.content.pm.InstrumentationInfo;
59import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070060import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.content.pm.ProviderInfo;
62import android.content.pm.ResolveInfo;
63import android.content.pm.ServiceInfo;
64import android.content.res.Configuration;
65import android.graphics.Bitmap;
66import android.net.Uri;
67import android.os.Binder;
68import android.os.Bundle;
69import android.os.Environment;
70import android.os.FileUtils;
71import android.os.Handler;
72import android.os.IBinder;
73import android.os.IPermissionController;
74import android.os.Looper;
75import android.os.Message;
76import android.os.Parcel;
77import android.os.ParcelFileDescriptor;
78import android.os.PowerManager;
79import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070080import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.RemoteException;
82import android.os.ServiceManager;
83import android.os.SystemClock;
84import android.os.SystemProperties;
85import android.provider.Checkin;
86import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020087import android.server.data.CrashData;
88import android.server.data.StackTraceElementData;
89import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.text.TextUtils;
91import android.util.Config;
92import android.util.EventLog;
93import android.util.Log;
94import android.util.PrintWriterPrinter;
95import android.util.SparseArray;
96import android.view.Gravity;
97import android.view.LayoutInflater;
98import android.view.View;
99import android.view.WindowManager;
100import android.view.WindowManagerPolicy;
101
102import dalvik.system.Zygote;
103
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200104import java.io.ByteArrayInputStream;
105import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import java.io.File;
107import java.io.FileDescriptor;
108import java.io.FileInputStream;
109import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200110import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.PrintWriter;
112import java.lang.IllegalStateException;
113import java.lang.ref.WeakReference;
114import java.util.ArrayList;
115import java.util.HashMap;
116import java.util.HashSet;
117import java.util.Iterator;
118import java.util.List;
119import java.util.Locale;
120import java.util.Map;
121
122public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
123 static final String TAG = "ActivityManager";
124 static final boolean DEBUG = false;
125 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
126 static final boolean DEBUG_SWITCH = localLOGV || false;
127 static final boolean DEBUG_TASKS = localLOGV || false;
128 static final boolean DEBUG_PAUSE = localLOGV || false;
129 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
130 static final boolean DEBUG_TRANSITION = localLOGV || false;
131 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700132 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 static final boolean DEBUG_SERVICE = localLOGV || false;
134 static final boolean DEBUG_VISBILITY = localLOGV || false;
135 static final boolean DEBUG_PROCESSES = localLOGV || false;
136 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700138 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean VALIDATE_TOKENS = false;
140 static final boolean SHOW_ACTIVITY_START_TIME = true;
141
142 // Control over CPU and battery monitoring.
143 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
144 static final boolean MONITOR_CPU_USAGE = true;
145 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
146 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
147 static final boolean MONITOR_THREAD_CPU_USAGE = false;
148
149 // Event log tags
150 static final int LOG_CONFIGURATION_CHANGED = 2719;
151 static final int LOG_CPU = 2721;
152 static final int LOG_AM_FINISH_ACTIVITY = 30001;
153 static final int LOG_TASK_TO_FRONT = 30002;
154 static final int LOG_AM_NEW_INTENT = 30003;
155 static final int LOG_AM_CREATE_TASK = 30004;
156 static final int LOG_AM_CREATE_ACTIVITY = 30005;
157 static final int LOG_AM_RESTART_ACTIVITY = 30006;
158 static final int LOG_AM_RESUME_ACTIVITY = 30007;
159 static final int LOG_ANR = 30008;
160 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
161 static final int LOG_AM_PROCESS_BOUND = 30010;
162 static final int LOG_AM_PROCESS_DIED = 30011;
163 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
164 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
165 static final int LOG_AM_PROCESS_START = 30014;
166 static final int LOG_AM_PROCESS_BAD = 30015;
167 static final int LOG_AM_PROCESS_GOOD = 30016;
168 static final int LOG_AM_LOW_MEMORY = 30017;
169 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
170 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
171 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
172 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
173 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
174 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
175 static final int LOG_AM_CREATE_SERVICE = 30030;
176 static final int LOG_AM_DESTROY_SERVICE = 30031;
177 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
178 static final int LOG_AM_DROP_PROCESS = 30033;
179 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
180 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
181 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
182
183 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
184 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
185
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700187 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 private static final String SYSTEM_SECURE = "ro.secure";
190
191 // This is the maximum number of application processes we would like
192 // to have running. Due to the asynchronous nature of things, we can
193 // temporarily go beyond this limit.
194 static final int MAX_PROCESSES = 2;
195
196 // Set to false to leave processes running indefinitely, relying on
197 // the kernel killing them as resources are required.
198 static final boolean ENFORCE_PROCESS_LIMIT = false;
199
200 // This is the maximum number of activities that we would like to have
201 // running at a given time.
202 static final int MAX_ACTIVITIES = 20;
203
204 // Maximum number of recent tasks that we can remember.
205 static final int MAX_RECENT_TASKS = 20;
206
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700207 // Amount of time after a call to stopAppSwitches() during which we will
208 // prevent further untrusted switches from happening.
209 static final long APP_SWITCH_DELAY_TIME = 5*1000;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 // How long until we reset a task when the user returns to it. Currently
212 // 30 minutes.
213 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
214
215 // Set to true to disable the icon that is shown while a new activity
216 // is being started.
217 static final boolean SHOW_APP_STARTING_ICON = true;
218
219 // How long we wait until giving up on the last activity to pause. This
220 // is short because it directly impacts the responsiveness of starting the
221 // next activity.
222 static final int PAUSE_TIMEOUT = 500;
223
224 /**
225 * How long we can hold the launch wake lock before giving up.
226 */
227 static final int LAUNCH_TIMEOUT = 10*1000;
228
229 // How long we wait for a launched process to attach to the activity manager
230 // before we decide it's never going to come up for real.
231 static final int PROC_START_TIMEOUT = 10*1000;
232
233 // How long we wait until giving up on the last activity telling us it
234 // is idle.
235 static final int IDLE_TIMEOUT = 10*1000;
236
237 // How long to wait after going idle before forcing apps to GC.
238 static final int GC_TIMEOUT = 5*1000;
239
240 // How long we wait until giving up on an activity telling us it has
241 // finished destroying itself.
242 static final int DESTROY_TIMEOUT = 10*1000;
243
244 // How long we allow a receiver to run before giving up on it.
245 static final int BROADCAST_TIMEOUT = 10*1000;
246
247 // How long we wait for a service to finish executing.
248 static final int SERVICE_TIMEOUT = 20*1000;
249
250 // How long a service needs to be running until restarting its process
251 // is no longer considered to be a relaunch of the service.
252 static final int SERVICE_RESTART_DURATION = 5*1000;
253
254 // Maximum amount of time for there to be no activity on a service before
255 // we consider it non-essential and allow its process to go on the
256 // LRU background list.
257 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
258
259 // How long we wait until we timeout on key dispatching.
260 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
261
262 // The minimum time we allow between crashes, for us to consider this
263 // application to be bad and stop and its services and reject broadcasts.
264 static final int MIN_CRASH_INTERVAL = 60*1000;
265
266 // How long we wait until we timeout on key dispatching during instrumentation.
267 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
268
269 // OOM adjustments for processes in various states:
270
271 // This is a process without anything currently running in it. Definitely
272 // the first to go! Value set in system/rootdir/init.rc on startup.
273 // This value is initalized in the constructor, careful when refering to
274 // this static variable externally.
275 static int EMPTY_APP_ADJ;
276
277 // This is a process with a content provider that does not have any clients
278 // attached to it. If it did have any clients, its adjustment would be the
279 // one for the highest-priority of those processes.
280 static int CONTENT_PROVIDER_ADJ;
281
282 // This is a process only hosting activities that are not visible,
283 // so it can be killed without any disruption. Value set in
284 // system/rootdir/init.rc on startup.
285 final int HIDDEN_APP_MAX_ADJ;
286 static int HIDDEN_APP_MIN_ADJ;
287
The Android Open Source Project4df24232009-03-05 14:34:35 -0800288 // This is a process holding the home application -- we want to try
289 // avoiding killing it, even if it would normally be in the background,
290 // because the user interacts with it so much.
291 final int HOME_APP_ADJ;
292
Christopher Tate6fa95972009-06-05 18:43:55 -0700293 // This is a process currently hosting a backup operation. Killing it
294 // is not entirely fatal but is generally a bad idea.
295 final int BACKUP_APP_ADJ;
296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 // This is a process holding a secondary server -- killing it will not
298 // have much of an impact as far as the user is concerned. Value set in
299 // system/rootdir/init.rc on startup.
300 final int SECONDARY_SERVER_ADJ;
301
302 // This is a process only hosting activities that are visible to the
303 // user, so we'd prefer they don't disappear. Value set in
304 // system/rootdir/init.rc on startup.
305 final int VISIBLE_APP_ADJ;
306
307 // This is the process running the current foreground app. We'd really
308 // rather not kill it! Value set in system/rootdir/init.rc on startup.
309 final int FOREGROUND_APP_ADJ;
310
311 // This is a process running a core server, such as telephony. Definitely
312 // don't want to kill it, but doing so is not completely fatal.
313 static final int CORE_SERVER_ADJ = -12;
314
315 // The system process runs at the default adjustment.
316 static final int SYSTEM_ADJ = -16;
317
318 // Memory pages are 4K.
319 static final int PAGE_SIZE = 4*1024;
320
321 // Corresponding memory levels for above adjustments.
322 final int EMPTY_APP_MEM;
323 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800324 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700325 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 final int SECONDARY_SERVER_MEM;
327 final int VISIBLE_APP_MEM;
328 final int FOREGROUND_APP_MEM;
329
330 final int MY_PID;
331
332 static final String[] EMPTY_STRING_ARRAY = new String[0];
333
334 enum ActivityState {
335 INITIALIZING,
336 RESUMED,
337 PAUSING,
338 PAUSED,
339 STOPPING,
340 STOPPED,
341 FINISHING,
342 DESTROYING,
343 DESTROYED
344 }
345
346 /**
347 * The back history of all previous (and possibly still
348 * running) activities. It contains HistoryRecord objects.
349 */
350 final ArrayList mHistory = new ArrayList();
351
352 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700353 * Description of a request to start a new activity, which has been held
354 * due to app switches being disabled.
355 */
356 class PendingActivityLaunch {
357 HistoryRecord r;
358 HistoryRecord sourceRecord;
359 Uri[] grantedUriPermissions;
360 int grantedMode;
361 boolean onlyIfNeeded;
362 }
363
364 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
365 = new ArrayList<PendingActivityLaunch>();
366
367 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 * List of all active broadcasts that are to be executed immediately
369 * (without waiting for another broadcast to finish). Currently this only
370 * contains broadcasts to registered receivers, to avoid spinning up
371 * a bunch of processes to execute IntentReceiver components.
372 */
373 final ArrayList<BroadcastRecord> mParallelBroadcasts
374 = new ArrayList<BroadcastRecord>();
375
376 /**
377 * List of all active broadcasts that are to be executed one at a time.
378 * The object at the top of the list is the currently activity broadcasts;
379 * those after it are waiting for the top to finish..
380 */
381 final ArrayList<BroadcastRecord> mOrderedBroadcasts
382 = new ArrayList<BroadcastRecord>();
383
384 /**
385 * Set when we current have a BROADCAST_INTENT_MSG in flight.
386 */
387 boolean mBroadcastsScheduled = false;
388
389 /**
390 * Set to indicate whether to issue an onUserLeaving callback when a
391 * newly launched activity is being brought in front of us.
392 */
393 boolean mUserLeaving = false;
394
395 /**
396 * When we are in the process of pausing an activity, before starting the
397 * next one, this variable holds the activity that is currently being paused.
398 */
399 HistoryRecord mPausingActivity = null;
400
401 /**
402 * Current activity that is resumed, or null if there is none.
403 */
404 HistoryRecord mResumedActivity = null;
405
406 /**
407 * Activity we have told the window manager to have key focus.
408 */
409 HistoryRecord mFocusedActivity = null;
410
411 /**
412 * This is the last activity that we put into the paused state. This is
413 * used to determine if we need to do an activity transition while sleeping,
414 * when we normally hold the top activity paused.
415 */
416 HistoryRecord mLastPausedActivity = null;
417
418 /**
419 * List of activities that are waiting for a new activity
420 * to become visible before completing whatever operation they are
421 * supposed to do.
422 */
423 final ArrayList mWaitingVisibleActivities = new ArrayList();
424
425 /**
426 * List of activities that are ready to be stopped, but waiting
427 * for the next activity to settle down before doing so. It contains
428 * HistoryRecord objects.
429 */
430 final ArrayList<HistoryRecord> mStoppingActivities
431 = new ArrayList<HistoryRecord>();
432
433 /**
434 * List of intents that were used to start the most recent tasks.
435 */
436 final ArrayList<TaskRecord> mRecentTasks
437 = new ArrayList<TaskRecord>();
438
439 /**
440 * List of activities that are ready to be finished, but waiting
441 * for the previous activity to settle down before doing so. It contains
442 * HistoryRecord objects.
443 */
444 final ArrayList mFinishingActivities = new ArrayList();
445
446 /**
447 * All of the applications we currently have running organized by name.
448 * The keys are strings of the application package name (as
449 * returned by the package manager), and the keys are ApplicationRecord
450 * objects.
451 */
452 final ProcessMap<ProcessRecord> mProcessNames
453 = new ProcessMap<ProcessRecord>();
454
455 /**
456 * The last time that various processes have crashed.
457 */
458 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
459
460 /**
461 * Set of applications that we consider to be bad, and will reject
462 * incoming broadcasts from (which the user has no control over).
463 * Processes are added to this set when they have crashed twice within
464 * a minimum amount of time; they are removed from it when they are
465 * later restarted (hopefully due to some user action). The value is the
466 * time it was added to the list.
467 */
468 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
469
470 /**
471 * All of the processes we currently have running organized by pid.
472 * The keys are the pid running the application.
473 *
474 * <p>NOTE: This object is protected by its own lock, NOT the global
475 * activity manager lock!
476 */
477 final SparseArray<ProcessRecord> mPidsSelfLocked
478 = new SparseArray<ProcessRecord>();
479
480 /**
481 * All of the processes that have been forced to be foreground. The key
482 * is the pid of the caller who requested it (we hold a death
483 * link on it).
484 */
485 abstract class ForegroundToken implements IBinder.DeathRecipient {
486 int pid;
487 IBinder token;
488 }
489 final SparseArray<ForegroundToken> mForegroundProcesses
490 = new SparseArray<ForegroundToken>();
491
492 /**
493 * List of records for processes that someone had tried to start before the
494 * system was ready. We don't start them at that point, but ensure they
495 * are started by the time booting is complete.
496 */
497 final ArrayList<ProcessRecord> mProcessesOnHold
498 = new ArrayList<ProcessRecord>();
499
500 /**
501 * List of records for processes that we have started and are waiting
502 * for them to call back. This is really only needed when running in
503 * single processes mode, in which case we do not have a unique pid for
504 * each process.
505 */
506 final ArrayList<ProcessRecord> mStartingProcesses
507 = new ArrayList<ProcessRecord>();
508
509 /**
510 * List of persistent applications that are in the process
511 * of being started.
512 */
513 final ArrayList<ProcessRecord> mPersistentStartingProcesses
514 = new ArrayList<ProcessRecord>();
515
516 /**
517 * Processes that are being forcibly torn down.
518 */
519 final ArrayList<ProcessRecord> mRemovedProcesses
520 = new ArrayList<ProcessRecord>();
521
522 /**
523 * List of running applications, sorted by recent usage.
524 * The first entry in the list is the least recently used.
525 * It contains ApplicationRecord objects. This list does NOT include
526 * any persistent application records (since we never want to exit them).
527 */
528 final ArrayList<ProcessRecord> mLRUProcesses
529 = new ArrayList<ProcessRecord>();
530
531 /**
532 * List of processes that should gc as soon as things are idle.
533 */
534 final ArrayList<ProcessRecord> mProcessesToGc
535 = new ArrayList<ProcessRecord>();
536
537 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800538 * This is the process holding what we currently consider to be
539 * the "home" activity.
540 */
541 private ProcessRecord mHomeProcess;
542
543 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 * List of running activities, sorted by recent usage.
545 * The first entry in the list is the least recently used.
546 * It contains HistoryRecord objects.
547 */
548 private final ArrayList mLRUActivities = new ArrayList();
549
550 /**
551 * Set of PendingResultRecord objects that are currently active.
552 */
553 final HashSet mPendingResultRecords = new HashSet();
554
555 /**
556 * Set of IntentSenderRecord objects that are currently active.
557 */
558 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
559 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
560
561 /**
562 * Intent broadcast that we have tried to start, but are
563 * waiting for its application's process to be created. We only
564 * need one (instead of a list) because we always process broadcasts
565 * one at a time, so no others can be started while waiting for this
566 * one.
567 */
568 BroadcastRecord mPendingBroadcast = null;
569
570 /**
571 * Keeps track of all IIntentReceivers that have been registered for
572 * broadcasts. Hash keys are the receiver IBinder, hash value is
573 * a ReceiverList.
574 */
575 final HashMap mRegisteredReceivers = new HashMap();
576
577 /**
578 * Resolver for broadcast intents to registered receivers.
579 * Holds BroadcastFilter (subclass of IntentFilter).
580 */
581 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
582 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
583 @Override
584 protected boolean allowFilterResult(
585 BroadcastFilter filter, List<BroadcastFilter> dest) {
586 IBinder target = filter.receiverList.receiver.asBinder();
587 for (int i=dest.size()-1; i>=0; i--) {
588 if (dest.get(i).receiverList.receiver.asBinder() == target) {
589 return false;
590 }
591 }
592 return true;
593 }
594 };
595
596 /**
597 * State of all active sticky broadcasts. Keys are the action of the
598 * sticky Intent, values are an ArrayList of all broadcasted intents with
599 * that action (which should usually be one).
600 */
601 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
602 new HashMap<String, ArrayList<Intent>>();
603
604 /**
605 * All currently running services.
606 */
607 final HashMap<ComponentName, ServiceRecord> mServices =
608 new HashMap<ComponentName, ServiceRecord>();
609
610 /**
611 * All currently running services indexed by the Intent used to start them.
612 */
613 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
614 new HashMap<Intent.FilterComparison, ServiceRecord>();
615
616 /**
617 * All currently bound service connections. Keys are the IBinder of
618 * the client's IServiceConnection.
619 */
620 final HashMap<IBinder, ConnectionRecord> mServiceConnections
621 = new HashMap<IBinder, ConnectionRecord>();
622
623 /**
624 * List of services that we have been asked to start,
625 * but haven't yet been able to. It is used to hold start requests
626 * while waiting for their corresponding application thread to get
627 * going.
628 */
629 final ArrayList<ServiceRecord> mPendingServices
630 = new ArrayList<ServiceRecord>();
631
632 /**
633 * List of services that are scheduled to restart following a crash.
634 */
635 final ArrayList<ServiceRecord> mRestartingServices
636 = new ArrayList<ServiceRecord>();
637
638 /**
639 * List of services that are in the process of being stopped.
640 */
641 final ArrayList<ServiceRecord> mStoppingServices
642 = new ArrayList<ServiceRecord>();
643
644 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700645 * Backup/restore process management
646 */
647 String mBackupAppName = null;
648 BackupRecord mBackupTarget = null;
649
650 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 * List of PendingThumbnailsRecord objects of clients who are still
652 * waiting to receive all of the thumbnails for a task.
653 */
654 final ArrayList mPendingThumbnails = new ArrayList();
655
656 /**
657 * List of HistoryRecord objects that have been finished and must
658 * still report back to a pending thumbnail receiver.
659 */
660 final ArrayList mCancelledThumbnails = new ArrayList();
661
662 /**
663 * All of the currently running global content providers. Keys are a
664 * string containing the provider name and values are a
665 * ContentProviderRecord object containing the data about it. Note
666 * that a single provider may be published under multiple names, so
667 * there may be multiple entries here for a single one in mProvidersByClass.
668 */
669 final HashMap mProvidersByName = new HashMap();
670
671 /**
672 * All of the currently running global content providers. Keys are a
673 * string containing the provider's implementation class and values are a
674 * ContentProviderRecord object containing the data about it.
675 */
676 final HashMap mProvidersByClass = new HashMap();
677
678 /**
679 * List of content providers who have clients waiting for them. The
680 * application is currently being launched and the provider will be
681 * removed from this list once it is published.
682 */
683 final ArrayList mLaunchingProviders = new ArrayList();
684
685 /**
686 * Global set of specific Uri permissions that have been granted.
687 */
688 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
689 = new SparseArray<HashMap<Uri, UriPermission>>();
690
691 /**
692 * Thread-local storage used to carry caller permissions over through
693 * indirect content-provider access.
694 * @see #ActivityManagerService.openContentUri()
695 */
696 private class Identity {
697 public int pid;
698 public int uid;
699
700 Identity(int _pid, int _uid) {
701 pid = _pid;
702 uid = _uid;
703 }
704 }
705 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
706
707 /**
708 * All information we have collected about the runtime performance of
709 * any user id that can impact battery performance.
710 */
711 final BatteryStatsService mBatteryStatsService;
712
713 /**
714 * information about component usage
715 */
716 final UsageStatsService mUsageStatsService;
717
718 /**
719 * Current configuration information. HistoryRecord objects are given
720 * a reference to this object to indicate which configuration they are
721 * currently running in, so this object must be kept immutable.
722 */
723 Configuration mConfiguration = new Configuration();
724
725 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700726 * Hardware-reported OpenGLES version.
727 */
728 final int GL_ES_VERSION;
729
730 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 * List of initialization arguments to pass to all processes when binding applications to them.
732 * For example, references to the commonly used services.
733 */
734 HashMap<String, IBinder> mAppBindArgs;
735
736 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700737 * Temporary to avoid allocations. Protected by main lock.
738 */
739 final StringBuilder mStringBuilder = new StringBuilder(256);
740
741 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 * Used to control how we initialize the service.
743 */
744 boolean mStartRunning = false;
745 ComponentName mTopComponent;
746 String mTopAction;
747 String mTopData;
748 boolean mSystemReady = false;
749 boolean mBooting = false;
750
751 Context mContext;
752
753 int mFactoryTest;
754
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700755 boolean mCheckedForSetup;
756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700758 * The time at which we will allow normal application switches again,
759 * after a call to {@link #stopAppSwitches()}.
760 */
761 long mAppSwitchesAllowedTime;
762
763 /**
764 * This is set to true after the first switch after mAppSwitchesAllowedTime
765 * is set; any switches after that will clear the time.
766 */
767 boolean mDidAppSwitch;
768
769 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 * Set while we are wanting to sleep, to prevent any
771 * activities from being started/resumed.
772 */
773 boolean mSleeping = false;
774
775 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700776 * Set if we are shutting down the system, similar to sleeping.
777 */
778 boolean mShuttingDown = false;
779
780 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 * Set when the system is going to sleep, until we have
782 * successfully paused the current activity and released our wake lock.
783 * At that point the system is allowed to actually sleep.
784 */
785 PowerManager.WakeLock mGoingToSleep;
786
787 /**
788 * We don't want to allow the device to go to sleep while in the process
789 * of launching an activity. This is primarily to allow alarm intent
790 * receivers to launch an activity and get that to run before the device
791 * goes back to sleep.
792 */
793 PowerManager.WakeLock mLaunchingActivity;
794
795 /**
796 * Task identifier that activities are currently being started
797 * in. Incremented each time a new task is created.
798 * todo: Replace this with a TokenSpace class that generates non-repeating
799 * integers that won't wrap.
800 */
801 int mCurTask = 1;
802
803 /**
804 * Current sequence id for oom_adj computation traversal.
805 */
806 int mAdjSeq = 0;
807
808 /**
809 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
810 * is set, indicating the user wants processes started in such a way
811 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
812 * running in each process (thus no pre-initialized process, etc).
813 */
814 boolean mSimpleProcessManagement = false;
815
816 /**
817 * System monitoring: number of processes that died since the last
818 * N procs were started.
819 */
820 int[] mProcDeaths = new int[20];
821
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700822 /**
823 * This is set if we had to do a delayed dexopt of an app before launching
824 * it, to increasing the ANR timeouts in that case.
825 */
826 boolean mDidDexOpt;
827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 String mDebugApp = null;
829 boolean mWaitForDebugger = false;
830 boolean mDebugTransient = false;
831 String mOrigDebugApp = null;
832 boolean mOrigWaitForDebugger = false;
833 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700834 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700836 final RemoteCallbackList<IActivityWatcher> mWatchers
837 = new RemoteCallbackList<IActivityWatcher>();
838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 /**
840 * Callback of last caller to {@link #requestPss}.
841 */
842 Runnable mRequestPssCallback;
843
844 /**
845 * Remaining processes for which we are waiting results from the last
846 * call to {@link #requestPss}.
847 */
848 final ArrayList<ProcessRecord> mRequestPssList
849 = new ArrayList<ProcessRecord>();
850
851 /**
852 * Runtime statistics collection thread. This object's lock is used to
853 * protect all related state.
854 */
855 final Thread mProcessStatsThread;
856
857 /**
858 * Used to collect process stats when showing not responding dialog.
859 * Protected by mProcessStatsThread.
860 */
861 final ProcessStats mProcessStats = new ProcessStats(
862 MONITOR_THREAD_CPU_USAGE);
863 long mLastCpuTime = 0;
864 long mLastWriteTime = 0;
865
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700866 long mInitialStartTime = 0;
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 /**
869 * Set to true after the system has finished booting.
870 */
871 boolean mBooted = false;
872
873 int mProcessLimit = 0;
874
875 WindowManagerService mWindowManager;
876
877 static ActivityManagerService mSelf;
878 static ActivityThread mSystemThread;
879
880 private final class AppDeathRecipient implements IBinder.DeathRecipient {
881 final ProcessRecord mApp;
882 final int mPid;
883 final IApplicationThread mAppThread;
884
885 AppDeathRecipient(ProcessRecord app, int pid,
886 IApplicationThread thread) {
887 if (localLOGV) Log.v(
888 TAG, "New death recipient " + this
889 + " for thread " + thread.asBinder());
890 mApp = app;
891 mPid = pid;
892 mAppThread = thread;
893 }
894
895 public void binderDied() {
896 if (localLOGV) Log.v(
897 TAG, "Death received in " + this
898 + " for thread " + mAppThread.asBinder());
899 removeRequestedPss(mApp);
900 synchronized(ActivityManagerService.this) {
901 appDiedLocked(mApp, mPid, mAppThread);
902 }
903 }
904 }
905
906 static final int SHOW_ERROR_MSG = 1;
907 static final int SHOW_NOT_RESPONDING_MSG = 2;
908 static final int SHOW_FACTORY_ERROR_MSG = 3;
909 static final int UPDATE_CONFIGURATION_MSG = 4;
910 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
911 static final int WAIT_FOR_DEBUGGER_MSG = 6;
912 static final int BROADCAST_INTENT_MSG = 7;
913 static final int BROADCAST_TIMEOUT_MSG = 8;
914 static final int PAUSE_TIMEOUT_MSG = 9;
915 static final int IDLE_TIMEOUT_MSG = 10;
916 static final int IDLE_NOW_MSG = 11;
917 static final int SERVICE_TIMEOUT_MSG = 12;
918 static final int UPDATE_TIME_ZONE = 13;
919 static final int SHOW_UID_ERROR_MSG = 14;
920 static final int IM_FEELING_LUCKY_MSG = 15;
921 static final int LAUNCH_TIMEOUT_MSG = 16;
922 static final int DESTROY_TIMEOUT_MSG = 17;
923 static final int SERVICE_ERROR_MSG = 18;
924 static final int RESUME_TOP_ACTIVITY_MSG = 19;
925 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700926 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927
928 AlertDialog mUidAlert;
929
930 final Handler mHandler = new Handler() {
931 //public Handler() {
932 // if (localLOGV) Log.v(TAG, "Handler started!");
933 //}
934
935 public void handleMessage(Message msg) {
936 switch (msg.what) {
937 case SHOW_ERROR_MSG: {
938 HashMap data = (HashMap) msg.obj;
939 byte[] crashData = (byte[])data.get("crashData");
940 if (crashData != null) {
941 // This needs to be *un*synchronized to avoid deadlock.
942 ContentResolver resolver = mContext.getContentResolver();
943 Checkin.reportCrash(resolver, crashData);
944 }
945 synchronized (ActivityManagerService.this) {
946 ProcessRecord proc = (ProcessRecord)data.get("app");
947 if (proc != null && proc.crashDialog != null) {
948 Log.e(TAG, "App already has crash dialog: " + proc);
949 return;
950 }
951 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700952 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 Dialog d = new AppErrorDialog(
954 mContext, res, proc,
955 (Integer)data.get("flags"),
956 (String)data.get("shortMsg"),
957 (String)data.get("longMsg"));
958 d.show();
959 proc.crashDialog = d;
960 } else {
961 // The device is asleep, so just pretend that the user
962 // saw a crash dialog and hit "force quit".
963 res.set(0);
964 }
965 }
966 } break;
967 case SHOW_NOT_RESPONDING_MSG: {
968 synchronized (ActivityManagerService.this) {
969 HashMap data = (HashMap) msg.obj;
970 ProcessRecord proc = (ProcessRecord)data.get("app");
971 if (proc != null && proc.anrDialog != null) {
972 Log.e(TAG, "App already has anr dialog: " + proc);
973 return;
974 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800975
976 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
977 null, null, 0, null, null, null,
978 false, false, MY_PID, Process.SYSTEM_UID);
979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
981 mContext, proc, (HistoryRecord)data.get("activity"));
982 d.show();
983 proc.anrDialog = d;
984 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700985
986 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 } break;
988 case SHOW_FACTORY_ERROR_MSG: {
989 Dialog d = new FactoryErrorDialog(
990 mContext, msg.getData().getCharSequence("msg"));
991 d.show();
992 enableScreenAfterBoot();
993 } break;
994 case UPDATE_CONFIGURATION_MSG: {
995 final ContentResolver resolver = mContext.getContentResolver();
996 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
997 } break;
998 case GC_BACKGROUND_PROCESSES_MSG: {
999 synchronized (ActivityManagerService.this) {
1000 performAppGcsIfAppropriateLocked();
1001 }
1002 } break;
1003 case WAIT_FOR_DEBUGGER_MSG: {
1004 synchronized (ActivityManagerService.this) {
1005 ProcessRecord app = (ProcessRecord)msg.obj;
1006 if (msg.arg1 != 0) {
1007 if (!app.waitedForDebugger) {
1008 Dialog d = new AppWaitingForDebuggerDialog(
1009 ActivityManagerService.this,
1010 mContext, app);
1011 app.waitDialog = d;
1012 app.waitedForDebugger = true;
1013 d.show();
1014 }
1015 } else {
1016 if (app.waitDialog != null) {
1017 app.waitDialog.dismiss();
1018 app.waitDialog = null;
1019 }
1020 }
1021 }
1022 } break;
1023 case BROADCAST_INTENT_MSG: {
1024 if (DEBUG_BROADCAST) Log.v(
1025 TAG, "Received BROADCAST_INTENT_MSG");
1026 processNextBroadcast(true);
1027 } break;
1028 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001029 if (mDidDexOpt) {
1030 mDidDexOpt = false;
1031 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1032 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1033 return;
1034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 broadcastTimeout();
1036 } break;
1037 case PAUSE_TIMEOUT_MSG: {
1038 IBinder token = (IBinder)msg.obj;
1039 // We don't at this point know if the activity is fullscreen,
1040 // so we need to be conservative and assume it isn't.
1041 Log.w(TAG, "Activity pause timeout for " + token);
1042 activityPaused(token, null, true);
1043 } break;
1044 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001045 if (mDidDexOpt) {
1046 mDidDexOpt = false;
1047 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1048 nmsg.obj = msg.obj;
1049 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1050 return;
1051 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 // We don't at this point know if the activity is fullscreen,
1053 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001054 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 Log.w(TAG, "Activity idle timeout for " + token);
1056 activityIdleInternal(token, true);
1057 } break;
1058 case DESTROY_TIMEOUT_MSG: {
1059 IBinder token = (IBinder)msg.obj;
1060 // We don't at this point know if the activity is fullscreen,
1061 // so we need to be conservative and assume it isn't.
1062 Log.w(TAG, "Activity destroy timeout for " + token);
1063 activityDestroyed(token);
1064 } break;
1065 case IDLE_NOW_MSG: {
1066 IBinder token = (IBinder)msg.obj;
1067 activityIdle(token);
1068 } break;
1069 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001070 if (mDidDexOpt) {
1071 mDidDexOpt = false;
1072 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1073 nmsg.obj = msg.obj;
1074 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1075 return;
1076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 serviceTimeout((ProcessRecord)msg.obj);
1078 } break;
1079 case UPDATE_TIME_ZONE: {
1080 synchronized (ActivityManagerService.this) {
1081 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1082 ProcessRecord r = mLRUProcesses.get(i);
1083 if (r.thread != null) {
1084 try {
1085 r.thread.updateTimeZone();
1086 } catch (RemoteException ex) {
1087 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1088 }
1089 }
1090 }
1091 }
1092 break;
1093 }
1094 case SHOW_UID_ERROR_MSG: {
1095 // XXX This is a temporary dialog, no need to localize.
1096 AlertDialog d = new BaseErrorDialog(mContext);
1097 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1098 d.setCancelable(false);
1099 d.setTitle("System UIDs Inconsistent");
1100 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1101 d.setButton("I'm Feeling Lucky",
1102 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1103 mUidAlert = d;
1104 d.show();
1105 } break;
1106 case IM_FEELING_LUCKY_MSG: {
1107 if (mUidAlert != null) {
1108 mUidAlert.dismiss();
1109 mUidAlert = null;
1110 }
1111 } break;
1112 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001113 if (mDidDexOpt) {
1114 mDidDexOpt = false;
1115 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1116 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1117 return;
1118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 synchronized (ActivityManagerService.this) {
1120 if (mLaunchingActivity.isHeld()) {
1121 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1122 mLaunchingActivity.release();
1123 }
1124 }
1125 } break;
1126 case SERVICE_ERROR_MSG: {
1127 ServiceRecord srv = (ServiceRecord)msg.obj;
1128 // This needs to be *un*synchronized to avoid deadlock.
1129 Checkin.logEvent(mContext.getContentResolver(),
1130 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1131 srv.name.toShortString());
1132 } break;
1133 case RESUME_TOP_ACTIVITY_MSG: {
1134 synchronized (ActivityManagerService.this) {
1135 resumeTopActivityLocked(null);
1136 }
1137 }
1138 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001139 if (mDidDexOpt) {
1140 mDidDexOpt = false;
1141 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1142 nmsg.obj = msg.obj;
1143 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1144 return;
1145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 ProcessRecord app = (ProcessRecord)msg.obj;
1147 synchronized (ActivityManagerService.this) {
1148 processStartTimedOutLocked(app);
1149 }
1150 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001151 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1152 synchronized (ActivityManagerService.this) {
1153 doPendingActivityLaunchesLocked(true);
1154 }
1155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 }
1157 }
1158 };
1159
1160 public static void setSystemProcess() {
1161 try {
1162 ActivityManagerService m = mSelf;
1163
1164 ServiceManager.addService("activity", m);
1165 ServiceManager.addService("meminfo", new MemBinder(m));
1166 if (MONITOR_CPU_USAGE) {
1167 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1168 }
1169 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1170 ServiceManager.addService("activity.services", new ServicesBinder(m));
1171 ServiceManager.addService("activity.senders", new SendersBinder(m));
1172 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1173 ServiceManager.addService("permission", new PermissionController(m));
1174
1175 ApplicationInfo info =
1176 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001177 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 synchronized (mSelf) {
1179 ProcessRecord app = mSelf.newProcessRecordLocked(
1180 mSystemThread.getApplicationThread(), info,
1181 info.processName);
1182 app.persistent = true;
1183 app.pid = Process.myPid();
1184 app.maxAdj = SYSTEM_ADJ;
1185 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1186 synchronized (mSelf.mPidsSelfLocked) {
1187 mSelf.mPidsSelfLocked.put(app.pid, app);
1188 }
1189 mSelf.updateLRUListLocked(app, true);
1190 }
1191 } catch (PackageManager.NameNotFoundException e) {
1192 throw new RuntimeException(
1193 "Unable to find android system package", e);
1194 }
1195 }
1196
1197 public void setWindowManager(WindowManagerService wm) {
1198 mWindowManager = wm;
1199 }
1200
1201 public static final Context main(int factoryTest) {
1202 AThread thr = new AThread();
1203 thr.start();
1204
1205 synchronized (thr) {
1206 while (thr.mService == null) {
1207 try {
1208 thr.wait();
1209 } catch (InterruptedException e) {
1210 }
1211 }
1212 }
1213
1214 ActivityManagerService m = thr.mService;
1215 mSelf = m;
1216 ActivityThread at = ActivityThread.systemMain();
1217 mSystemThread = at;
1218 Context context = at.getSystemContext();
1219 m.mContext = context;
1220 m.mFactoryTest = factoryTest;
1221 PowerManager pm =
1222 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1223 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1224 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1225 m.mLaunchingActivity.setReferenceCounted(false);
1226
1227 m.mBatteryStatsService.publish(context);
1228 m.mUsageStatsService.publish(context);
1229
1230 synchronized (thr) {
1231 thr.mReady = true;
1232 thr.notifyAll();
1233 }
1234
1235 m.startRunning(null, null, null, null);
1236
1237 return context;
1238 }
1239
1240 public static ActivityManagerService self() {
1241 return mSelf;
1242 }
1243
1244 static class AThread extends Thread {
1245 ActivityManagerService mService;
1246 boolean mReady = false;
1247
1248 public AThread() {
1249 super("ActivityManager");
1250 }
1251
1252 public void run() {
1253 Looper.prepare();
1254
1255 android.os.Process.setThreadPriority(
1256 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1257
1258 ActivityManagerService m = new ActivityManagerService();
1259
1260 synchronized (this) {
1261 mService = m;
1262 notifyAll();
1263 }
1264
1265 synchronized (this) {
1266 while (!mReady) {
1267 try {
1268 wait();
1269 } catch (InterruptedException e) {
1270 }
1271 }
1272 }
1273
1274 Looper.loop();
1275 }
1276 }
1277
1278 static class BroadcastsBinder extends Binder {
1279 ActivityManagerService mActivityManagerService;
1280 BroadcastsBinder(ActivityManagerService activityManagerService) {
1281 mActivityManagerService = activityManagerService;
1282 }
1283
1284 @Override
1285 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1286 mActivityManagerService.dumpBroadcasts(pw);
1287 }
1288 }
1289
1290 static class ServicesBinder extends Binder {
1291 ActivityManagerService mActivityManagerService;
1292 ServicesBinder(ActivityManagerService activityManagerService) {
1293 mActivityManagerService = activityManagerService;
1294 }
1295
1296 @Override
1297 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1298 mActivityManagerService.dumpServices(pw);
1299 }
1300 }
1301
1302 static class SendersBinder extends Binder {
1303 ActivityManagerService mActivityManagerService;
1304 SendersBinder(ActivityManagerService activityManagerService) {
1305 mActivityManagerService = activityManagerService;
1306 }
1307
1308 @Override
1309 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1310 mActivityManagerService.dumpSenders(pw);
1311 }
1312 }
1313
1314 static class ProvidersBinder extends Binder {
1315 ActivityManagerService mActivityManagerService;
1316 ProvidersBinder(ActivityManagerService activityManagerService) {
1317 mActivityManagerService = activityManagerService;
1318 }
1319
1320 @Override
1321 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1322 mActivityManagerService.dumpProviders(pw);
1323 }
1324 }
1325
1326 static class MemBinder extends Binder {
1327 ActivityManagerService mActivityManagerService;
1328 MemBinder(ActivityManagerService activityManagerService) {
1329 mActivityManagerService = activityManagerService;
1330 }
1331
1332 @Override
1333 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1334 ActivityManagerService service = mActivityManagerService;
1335 ArrayList<ProcessRecord> procs;
1336 synchronized (mActivityManagerService) {
1337 if (args != null && args.length > 0
1338 && args[0].charAt(0) != '-') {
1339 procs = new ArrayList<ProcessRecord>();
1340 int pid = -1;
1341 try {
1342 pid = Integer.parseInt(args[0]);
1343 } catch (NumberFormatException e) {
1344
1345 }
1346 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1347 ProcessRecord proc = service.mLRUProcesses.get(i);
1348 if (proc.pid == pid) {
1349 procs.add(proc);
1350 } else if (proc.processName.equals(args[0])) {
1351 procs.add(proc);
1352 }
1353 }
1354 if (procs.size() <= 0) {
1355 pw.println("No process found for: " + args[0]);
1356 return;
1357 }
1358 } else {
1359 procs = service.mLRUProcesses;
1360 }
1361 }
1362 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1363 }
1364 }
1365
1366 static class CpuBinder extends Binder {
1367 ActivityManagerService mActivityManagerService;
1368 CpuBinder(ActivityManagerService activityManagerService) {
1369 mActivityManagerService = activityManagerService;
1370 }
1371
1372 @Override
1373 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1374 synchronized (mActivityManagerService.mProcessStatsThread) {
1375 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1376 }
1377 }
1378 }
1379
1380 private ActivityManagerService() {
1381 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1382 if (v != null && Integer.getInteger(v) != 0) {
1383 mSimpleProcessManagement = true;
1384 }
1385 v = System.getenv("ANDROID_DEBUG_APP");
1386 if (v != null) {
1387 mSimpleProcessManagement = true;
1388 }
1389
1390 MY_PID = Process.myPid();
1391
1392 File dataDir = Environment.getDataDirectory();
1393 File systemDir = new File(dataDir, "system");
1394 systemDir.mkdirs();
1395 mBatteryStatsService = new BatteryStatsService(new File(
1396 systemDir, "batterystats.bin").toString());
1397 mBatteryStatsService.getActiveStatistics().readLocked();
1398 mBatteryStatsService.getActiveStatistics().writeLocked();
1399
1400 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001401 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402
Jack Palevichb90d28c2009-07-22 15:35:24 -07001403 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1404 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 mConfiguration.makeDefault();
1407 mProcessStats.init();
1408
1409 // Add ourself to the Watchdog monitors.
1410 Watchdog.getInstance().addMonitor(this);
1411
1412 // These values are set in system/rootdir/init.rc on startup.
1413 FOREGROUND_APP_ADJ =
1414 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1415 VISIBLE_APP_ADJ =
1416 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1417 SECONDARY_SERVER_ADJ =
1418 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001419 BACKUP_APP_ADJ =
1420 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001421 HOME_APP_ADJ =
1422 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 HIDDEN_APP_MIN_ADJ =
1424 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1425 CONTENT_PROVIDER_ADJ =
1426 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1427 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1428 EMPTY_APP_ADJ =
1429 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1430 FOREGROUND_APP_MEM =
1431 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1432 VISIBLE_APP_MEM =
1433 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1434 SECONDARY_SERVER_MEM =
1435 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001436 BACKUP_APP_MEM =
1437 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001438 HOME_APP_MEM =
1439 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 HIDDEN_APP_MEM =
1441 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1442 EMPTY_APP_MEM =
1443 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1444
1445 mProcessStatsThread = new Thread("ProcessStats") {
1446 public void run() {
1447 while (true) {
1448 try {
1449 try {
1450 synchronized(this) {
1451 final long now = SystemClock.uptimeMillis();
1452 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1453 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1454 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1455 // + ", write delay=" + nextWriteDelay);
1456 if (nextWriteDelay < nextCpuDelay) {
1457 nextCpuDelay = nextWriteDelay;
1458 }
1459 if (nextCpuDelay > 0) {
1460 this.wait(nextCpuDelay);
1461 }
1462 }
1463 } catch (InterruptedException e) {
1464 }
1465
1466 updateCpuStatsNow();
1467 } catch (Exception e) {
1468 Log.e(TAG, "Unexpected exception collecting process stats", e);
1469 }
1470 }
1471 }
1472 };
1473 mProcessStatsThread.start();
1474 }
1475
1476 @Override
1477 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1478 throws RemoteException {
1479 try {
1480 return super.onTransact(code, data, reply, flags);
1481 } catch (RuntimeException e) {
1482 // The activity manager only throws security exceptions, so let's
1483 // log all others.
1484 if (!(e instanceof SecurityException)) {
1485 Log.e(TAG, "Activity Manager Crash", e);
1486 }
1487 throw e;
1488 }
1489 }
1490
1491 void updateCpuStats() {
1492 synchronized (mProcessStatsThread) {
1493 final long now = SystemClock.uptimeMillis();
1494 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1495 mProcessStatsThread.notify();
1496 }
1497 }
1498 }
1499
1500 void updateCpuStatsNow() {
1501 synchronized (mProcessStatsThread) {
1502 final long now = SystemClock.uptimeMillis();
1503 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 if (MONITOR_CPU_USAGE &&
1506 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1507 mLastCpuTime = now;
1508 haveNewCpuStats = true;
1509 mProcessStats.update();
1510 //Log.i(TAG, mProcessStats.printCurrentState());
1511 //Log.i(TAG, "Total CPU usage: "
1512 // + mProcessStats.getTotalCpuPercent() + "%");
1513
1514 // Log the cpu usage if the property is set.
1515 if ("true".equals(SystemProperties.get("events.cpu"))) {
1516 int user = mProcessStats.getLastUserTime();
1517 int system = mProcessStats.getLastSystemTime();
1518 int iowait = mProcessStats.getLastIoWaitTime();
1519 int irq = mProcessStats.getLastIrqTime();
1520 int softIrq = mProcessStats.getLastSoftIrqTime();
1521 int idle = mProcessStats.getLastIdleTime();
1522
1523 int total = user + system + iowait + irq + softIrq + idle;
1524 if (total == 0) total = 1;
1525
1526 EventLog.writeEvent(LOG_CPU,
1527 ((user+system+iowait+irq+softIrq) * 100) / total,
1528 (user * 100) / total,
1529 (system * 100) / total,
1530 (iowait * 100) / total,
1531 (irq * 100) / total,
1532 (softIrq * 100) / total);
1533 }
1534 }
1535
Amith Yamasani819f9282009-06-24 23:18:15 -07001536 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001537 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 synchronized(mPidsSelfLocked) {
1539 if (haveNewCpuStats) {
1540 if (mBatteryStatsService.isOnBattery()) {
1541 final int N = mProcessStats.countWorkingStats();
1542 for (int i=0; i<N; i++) {
1543 ProcessStats.Stats st
1544 = mProcessStats.getWorkingStats(i);
1545 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1546 if (pr != null) {
1547 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1548 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001549 } else {
1550 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001551 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001552 if (ps != null) {
1553 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556 }
1557 }
1558 }
1559 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1562 mLastWriteTime = now;
1563 mBatteryStatsService.getActiveStatistics().writeLocked();
1564 }
1565 }
1566 }
1567 }
1568
1569 /**
1570 * Initialize the application bind args. These are passed to each
1571 * process when the bindApplication() IPC is sent to the process. They're
1572 * lazily setup to make sure the services are running when they're asked for.
1573 */
1574 private HashMap<String, IBinder> getCommonServicesLocked() {
1575 if (mAppBindArgs == null) {
1576 mAppBindArgs = new HashMap<String, IBinder>();
1577
1578 // Setup the application init args
1579 mAppBindArgs.put("package", ServiceManager.getService("package"));
1580 mAppBindArgs.put("window", ServiceManager.getService("window"));
1581 mAppBindArgs.put(Context.ALARM_SERVICE,
1582 ServiceManager.getService(Context.ALARM_SERVICE));
1583 }
1584 return mAppBindArgs;
1585 }
1586
1587 private final void setFocusedActivityLocked(HistoryRecord r) {
1588 if (mFocusedActivity != r) {
1589 mFocusedActivity = r;
1590 mWindowManager.setFocusedApp(r, true);
1591 }
1592 }
1593
1594 private final void updateLRUListLocked(ProcessRecord app,
1595 boolean oomAdj) {
1596 // put it on the LRU to keep track of when it should be exited.
1597 int lrui = mLRUProcesses.indexOf(app);
1598 if (lrui >= 0) mLRUProcesses.remove(lrui);
1599 mLRUProcesses.add(app);
1600 //Log.i(TAG, "Putting proc to front: " + app.processName);
1601 if (oomAdj) {
1602 updateOomAdjLocked();
1603 }
1604 }
1605
1606 private final boolean updateLRUListLocked(HistoryRecord r) {
1607 final boolean hadit = mLRUActivities.remove(r);
1608 mLRUActivities.add(r);
1609 return hadit;
1610 }
1611
1612 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1613 int i = mHistory.size()-1;
1614 while (i >= 0) {
1615 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1616 if (!r.finishing && r != notTop) {
1617 return r;
1618 }
1619 i--;
1620 }
1621 return null;
1622 }
1623
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001624 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1625 int i = mHistory.size()-1;
1626 while (i >= 0) {
1627 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1628 if (!r.finishing && !r.delayedResume && r != notTop) {
1629 return r;
1630 }
1631 i--;
1632 }
1633 return null;
1634 }
1635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 /**
1637 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001638 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 *
1640 * @param token If non-null, any history records matching this token will be skipped.
1641 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1642 *
1643 * @return Returns the HistoryRecord of the next activity on the stack.
1644 */
1645 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1646 int i = mHistory.size()-1;
1647 while (i >= 0) {
1648 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1649 // Note: the taskId check depends on real taskId fields being non-zero
1650 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1651 return r;
1652 }
1653 i--;
1654 }
1655 return null;
1656 }
1657
1658 private final ProcessRecord getProcessRecordLocked(
1659 String processName, int uid) {
1660 if (uid == Process.SYSTEM_UID) {
1661 // The system gets to run in any process. If there are multiple
1662 // processes with the same uid, just pick the first (this
1663 // should never happen).
1664 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1665 processName);
1666 return procs != null ? procs.valueAt(0) : null;
1667 }
1668 ProcessRecord proc = mProcessNames.get(processName, uid);
1669 return proc;
1670 }
1671
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001672 private void ensurePackageDexOpt(String packageName) {
1673 IPackageManager pm = ActivityThread.getPackageManager();
1674 try {
1675 if (pm.performDexOpt(packageName)) {
1676 mDidDexOpt = true;
1677 }
1678 } catch (RemoteException e) {
1679 }
1680 }
1681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 private boolean isNextTransitionForward() {
1683 int transit = mWindowManager.getPendingAppTransition();
1684 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1685 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1686 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1687 }
1688
1689 private final boolean realStartActivityLocked(HistoryRecord r,
1690 ProcessRecord app, boolean andResume, boolean checkConfig)
1691 throws RemoteException {
1692
1693 r.startFreezingScreenLocked(app, 0);
1694 mWindowManager.setAppVisibility(r, true);
1695
1696 // Have the window manager re-evaluate the orientation of
1697 // the screen based on the new activity order. Note that
1698 // as a result of this, it can call back into the activity
1699 // manager with a new orientation. We don't care about that,
1700 // because the activity is not currently running so we are
1701 // just restarting it anyway.
1702 if (checkConfig) {
1703 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001704 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 r.mayFreezeScreenLocked(app) ? r : null);
1706 updateConfigurationLocked(config, r);
1707 }
1708
1709 r.app = app;
1710
1711 if (localLOGV) Log.v(TAG, "Launching: " + r);
1712
1713 int idx = app.activities.indexOf(r);
1714 if (idx < 0) {
1715 app.activities.add(r);
1716 }
1717 updateLRUListLocked(app, true);
1718
1719 try {
1720 if (app.thread == null) {
1721 throw new RemoteException();
1722 }
1723 List<ResultInfo> results = null;
1724 List<Intent> newIntents = null;
1725 if (andResume) {
1726 results = r.results;
1727 newIntents = r.newIntents;
1728 }
1729 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1730 + " icicle=" + r.icicle
1731 + " with results=" + results + " newIntents=" + newIntents
1732 + " andResume=" + andResume);
1733 if (andResume) {
1734 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1735 System.identityHashCode(r),
1736 r.task.taskId, r.shortComponentName);
1737 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001738 if (r.isHomeActivity) {
1739 mHomeProcess = app;
1740 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001741 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001743 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 r.info, r.icicle, results, newIntents, !andResume,
1745 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 } catch (RemoteException e) {
1747 if (r.launchFailed) {
1748 // This is the second time we failed -- finish activity
1749 // and give up.
1750 Log.e(TAG, "Second failure launching "
1751 + r.intent.getComponent().flattenToShortString()
1752 + ", giving up", e);
1753 appDiedLocked(app, app.pid, app.thread);
1754 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1755 "2nd-crash");
1756 return false;
1757 }
1758
1759 // This is the first time we failed -- restart process and
1760 // retry.
1761 app.activities.remove(r);
1762 throw e;
1763 }
1764
1765 r.launchFailed = false;
1766 if (updateLRUListLocked(r)) {
1767 Log.w(TAG, "Activity " + r
1768 + " being launched, but already in LRU list");
1769 }
1770
1771 if (andResume) {
1772 // As part of the process of launching, ActivityThread also performs
1773 // a resume.
1774 r.state = ActivityState.RESUMED;
1775 r.icicle = null;
1776 r.haveState = false;
1777 r.stopped = false;
1778 mResumedActivity = r;
1779 r.task.touchActiveTime();
1780 completeResumeLocked(r);
1781 pauseIfSleepingLocked();
1782 } else {
1783 // This activity is not starting in the resumed state... which
1784 // should look like we asked it to pause+stop (but remain visible),
1785 // and it has done so and reported back the current icicle and
1786 // other state.
1787 r.state = ActivityState.STOPPED;
1788 r.stopped = true;
1789 }
1790
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001791 // Launch the new version setup screen if needed. We do this -after-
1792 // launching the initial activity (that is, home), so that it can have
1793 // a chance to initialize itself while in the background, making the
1794 // switch back to it faster and look better.
1795 startSetupActivityLocked();
1796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 return true;
1798 }
1799
1800 private final void startSpecificActivityLocked(HistoryRecord r,
1801 boolean andResume, boolean checkConfig) {
1802 // Is this activity's application already running?
1803 ProcessRecord app = getProcessRecordLocked(r.processName,
1804 r.info.applicationInfo.uid);
1805
1806 if (r.startTime == 0) {
1807 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001808 if (mInitialStartTime == 0) {
1809 mInitialStartTime = r.startTime;
1810 }
1811 } else if (mInitialStartTime == 0) {
1812 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 }
1814
1815 if (app != null && app.thread != null) {
1816 try {
1817 realStartActivityLocked(r, app, andResume, checkConfig);
1818 return;
1819 } catch (RemoteException e) {
1820 Log.w(TAG, "Exception when starting activity "
1821 + r.intent.getComponent().flattenToShortString(), e);
1822 }
1823
1824 // If a dead object exception was thrown -- fall through to
1825 // restart the application.
1826 }
1827
1828 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1829 "activity", r.intent.getComponent());
1830 }
1831
1832 private final ProcessRecord startProcessLocked(String processName,
1833 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1834 String hostingType, ComponentName hostingName) {
1835 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1836 // We don't have to do anything more if:
1837 // (1) There is an existing application record; and
1838 // (2) The caller doesn't think it is dead, OR there is no thread
1839 // object attached to it so we know it couldn't have crashed; and
1840 // (3) There is a pid assigned to it, so it is either starting or
1841 // already running.
1842 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1843 + " app=" + app + " knownToBeDead=" + knownToBeDead
1844 + " thread=" + (app != null ? app.thread : null)
1845 + " pid=" + (app != null ? app.pid : -1));
1846 if (app != null &&
1847 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1848 return app;
1849 }
1850
1851 String hostingNameStr = hostingName != null
1852 ? hostingName.flattenToShortString() : null;
1853
1854 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1855 // If we are in the background, then check to see if this process
1856 // is bad. If so, we will just silently fail.
1857 if (mBadProcesses.get(info.processName, info.uid) != null) {
1858 return null;
1859 }
1860 } else {
1861 // When the user is explicitly starting a process, then clear its
1862 // crash count so that we won't make it bad until they see at
1863 // least one crash dialog again, and make the process good again
1864 // if it had been bad.
1865 mProcessCrashTimes.remove(info.processName, info.uid);
1866 if (mBadProcesses.get(info.processName, info.uid) != null) {
1867 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1868 info.processName);
1869 mBadProcesses.remove(info.processName, info.uid);
1870 if (app != null) {
1871 app.bad = false;
1872 }
1873 }
1874 }
1875
1876 if (app == null) {
1877 app = newProcessRecordLocked(null, info, processName);
1878 mProcessNames.put(processName, info.uid, app);
1879 } else {
1880 // If this is a new package in the process, add the package to the list
1881 app.addPackage(info.packageName);
1882 }
1883
1884 // If the system is not ready yet, then hold off on starting this
1885 // process until it is.
1886 if (!mSystemReady
1887 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1888 if (!mProcessesOnHold.contains(app)) {
1889 mProcessesOnHold.add(app);
1890 }
1891 return app;
1892 }
1893
1894 startProcessLocked(app, hostingType, hostingNameStr);
1895 return (app.pid != 0) ? app : null;
1896 }
1897
1898 private final void startProcessLocked(ProcessRecord app,
1899 String hostingType, String hostingNameStr) {
1900 if (app.pid > 0 && app.pid != MY_PID) {
1901 synchronized (mPidsSelfLocked) {
1902 mPidsSelfLocked.remove(app.pid);
1903 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1904 }
1905 app.pid = 0;
1906 }
1907
1908 mProcessesOnHold.remove(app);
1909
1910 updateCpuStats();
1911
1912 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1913 mProcDeaths[0] = 0;
1914
1915 try {
1916 int uid = app.info.uid;
1917 int[] gids = null;
1918 try {
1919 gids = mContext.getPackageManager().getPackageGids(
1920 app.info.packageName);
1921 } catch (PackageManager.NameNotFoundException e) {
1922 Log.w(TAG, "Unable to retrieve gids", e);
1923 }
1924 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1925 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1926 && mTopComponent != null
1927 && app.processName.equals(mTopComponent.getPackageName())) {
1928 uid = 0;
1929 }
1930 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1931 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1932 uid = 0;
1933 }
1934 }
1935 int debugFlags = 0;
1936 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1937 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1938 }
1939 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1940 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1941 }
1942 if ("1".equals(SystemProperties.get("debug.assert"))) {
1943 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1944 }
1945 int pid = Process.start("android.app.ActivityThread",
1946 mSimpleProcessManagement ? app.processName : null, uid, uid,
1947 gids, debugFlags, null);
1948 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1949 synchronized (bs) {
1950 if (bs.isOnBattery()) {
1951 app.batteryStats.incStartsLocked();
1952 }
1953 }
1954
1955 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1956 app.processName, hostingType,
1957 hostingNameStr != null ? hostingNameStr : "");
1958
1959 if (app.persistent) {
1960 Watchdog.getInstance().processStarted(app, app.processName, pid);
1961 }
1962
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001963 StringBuilder buf = mStringBuilder;
1964 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 buf.append("Start proc ");
1966 buf.append(app.processName);
1967 buf.append(" for ");
1968 buf.append(hostingType);
1969 if (hostingNameStr != null) {
1970 buf.append(" ");
1971 buf.append(hostingNameStr);
1972 }
1973 buf.append(": pid=");
1974 buf.append(pid);
1975 buf.append(" uid=");
1976 buf.append(uid);
1977 buf.append(" gids={");
1978 if (gids != null) {
1979 for (int gi=0; gi<gids.length; gi++) {
1980 if (gi != 0) buf.append(", ");
1981 buf.append(gids[gi]);
1982
1983 }
1984 }
1985 buf.append("}");
1986 Log.i(TAG, buf.toString());
1987 if (pid == 0 || pid == MY_PID) {
1988 // Processes are being emulated with threads.
1989 app.pid = MY_PID;
1990 app.removed = false;
1991 mStartingProcesses.add(app);
1992 } else if (pid > 0) {
1993 app.pid = pid;
1994 app.removed = false;
1995 synchronized (mPidsSelfLocked) {
1996 this.mPidsSelfLocked.put(pid, app);
1997 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1998 msg.obj = app;
1999 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2000 }
2001 } else {
2002 app.pid = 0;
2003 RuntimeException e = new RuntimeException(
2004 "Failure starting process " + app.processName
2005 + ": returned pid=" + pid);
2006 Log.e(TAG, e.getMessage(), e);
2007 }
2008 } catch (RuntimeException e) {
2009 // XXX do better error recovery.
2010 app.pid = 0;
2011 Log.e(TAG, "Failure starting process " + app.processName, e);
2012 }
2013 }
2014
2015 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2016 if (mPausingActivity != null) {
2017 RuntimeException e = new RuntimeException();
2018 Log.e(TAG, "Trying to pause when pause is already pending for "
2019 + mPausingActivity, e);
2020 }
2021 HistoryRecord prev = mResumedActivity;
2022 if (prev == null) {
2023 RuntimeException e = new RuntimeException();
2024 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2025 resumeTopActivityLocked(null);
2026 return;
2027 }
2028 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2029 mResumedActivity = null;
2030 mPausingActivity = prev;
2031 mLastPausedActivity = prev;
2032 prev.state = ActivityState.PAUSING;
2033 prev.task.touchActiveTime();
2034
2035 updateCpuStats();
2036
2037 if (prev.app != null && prev.app.thread != null) {
2038 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2039 try {
2040 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2041 System.identityHashCode(prev),
2042 prev.shortComponentName);
2043 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2044 prev.configChangeFlags);
2045 updateUsageStats(prev, false);
2046 } catch (Exception e) {
2047 // Ignore exception, if process died other code will cleanup.
2048 Log.w(TAG, "Exception thrown during pause", e);
2049 mPausingActivity = null;
2050 mLastPausedActivity = null;
2051 }
2052 } else {
2053 mPausingActivity = null;
2054 mLastPausedActivity = null;
2055 }
2056
2057 // If we are not going to sleep, we want to ensure the device is
2058 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002059 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 mLaunchingActivity.acquire();
2061 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2062 // To be safe, don't allow the wake lock to be held for too long.
2063 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2064 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2065 }
2066 }
2067
2068
2069 if (mPausingActivity != null) {
2070 // Have the window manager pause its key dispatching until the new
2071 // activity has started. If we're pausing the activity just because
2072 // the screen is being turned off and the UI is sleeping, don't interrupt
2073 // key dispatch; the same activity will pick it up again on wakeup.
2074 if (!uiSleeping) {
2075 prev.pauseKeyDispatchingLocked();
2076 } else {
2077 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2078 }
2079
2080 // Schedule a pause timeout in case the app doesn't respond.
2081 // We don't give it much time because this directly impacts the
2082 // responsiveness seen by the user.
2083 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2084 msg.obj = prev;
2085 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2086 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2087 } else {
2088 // This activity failed to schedule the
2089 // pause, so just treat it as being paused now.
2090 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2091 resumeTopActivityLocked(null);
2092 }
2093 }
2094
2095 private final void completePauseLocked() {
2096 HistoryRecord prev = mPausingActivity;
2097 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2098
2099 if (prev != null) {
2100 if (prev.finishing) {
2101 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2102 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2103 } else if (prev.app != null) {
2104 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2105 if (prev.waitingVisible) {
2106 prev.waitingVisible = false;
2107 mWaitingVisibleActivities.remove(prev);
2108 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2109 TAG, "Complete pause, no longer waiting: " + prev);
2110 }
2111 if (prev.configDestroy) {
2112 // The previous is being paused because the configuration
2113 // is changing, which means it is actually stopping...
2114 // To juggle the fact that we are also starting a new
2115 // instance right now, we need to first completely stop
2116 // the current instance before starting the new one.
2117 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2118 destroyActivityLocked(prev, true);
2119 } else {
2120 mStoppingActivities.add(prev);
2121 if (mStoppingActivities.size() > 3) {
2122 // If we already have a few activities waiting to stop,
2123 // then give up on things going idle and start clearing
2124 // them out.
2125 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2126 Message msg = Message.obtain();
2127 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2128 mHandler.sendMessage(msg);
2129 }
2130 }
2131 } else {
2132 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2133 prev = null;
2134 }
2135 mPausingActivity = null;
2136 }
2137
Dianne Hackborn55280a92009-05-07 15:53:46 -07002138 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 resumeTopActivityLocked(prev);
2140 } else {
2141 if (mGoingToSleep.isHeld()) {
2142 mGoingToSleep.release();
2143 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002144 if (mShuttingDown) {
2145 notifyAll();
2146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 }
2148
2149 if (prev != null) {
2150 prev.resumeKeyDispatchingLocked();
2151 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002152
2153 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2154 long diff = 0;
2155 synchronized (mProcessStatsThread) {
2156 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2157 }
2158 if (diff > 0) {
2159 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2160 synchronized (bsi) {
2161 BatteryStatsImpl.Uid.Proc ps =
2162 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2163 prev.info.packageName);
2164 if (ps != null) {
2165 ps.addForegroundTimeLocked(diff);
2166 }
2167 }
2168 }
2169 }
2170 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 }
2172
2173 /**
2174 * Once we know that we have asked an application to put an activity in
2175 * the resumed state (either by launching it or explicitly telling it),
2176 * this function updates the rest of our state to match that fact.
2177 */
2178 private final void completeResumeLocked(HistoryRecord next) {
2179 next.idle = false;
2180 next.results = null;
2181 next.newIntents = null;
2182
2183 // schedule an idle timeout in case the app doesn't do it for us.
2184 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2185 msg.obj = next;
2186 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2187
2188 if (false) {
2189 // The activity was never told to pause, so just keep
2190 // things going as-is. To maintain our own state,
2191 // we need to emulate it coming back and saying it is
2192 // idle.
2193 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2194 msg.obj = next;
2195 mHandler.sendMessage(msg);
2196 }
2197
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002198 reportResumedActivity(next);
2199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 next.thumbnail = null;
2201 setFocusedActivityLocked(next);
2202 next.resumeKeyDispatchingLocked();
2203 ensureActivitiesVisibleLocked(null, 0);
2204 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002205
2206 // Mark the point when the activity is resuming
2207 // TODO: To be more accurate, the mark should be before the onCreate,
2208 // not after the onResume. But for subsequent starts, onResume is fine.
2209 if (next.app != null) {
2210 synchronized (mProcessStatsThread) {
2211 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2212 }
2213 } else {
2214 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
2217
2218 /**
2219 * Make sure that all activities that need to be visible (that is, they
2220 * currently can be seen by the user) actually are.
2221 */
2222 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2223 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2224 if (DEBUG_VISBILITY) Log.v(
2225 TAG, "ensureActivitiesVisible behind " + top
2226 + " configChanges=0x" + Integer.toHexString(configChanges));
2227
2228 // If the top activity is not fullscreen, then we need to
2229 // make sure any activities under it are now visible.
2230 final int count = mHistory.size();
2231 int i = count-1;
2232 while (mHistory.get(i) != top) {
2233 i--;
2234 }
2235 HistoryRecord r;
2236 boolean behindFullscreen = false;
2237 for (; i>=0; i--) {
2238 r = (HistoryRecord)mHistory.get(i);
2239 if (DEBUG_VISBILITY) Log.v(
2240 TAG, "Make visible? " + r + " finishing=" + r.finishing
2241 + " state=" + r.state);
2242 if (r.finishing) {
2243 continue;
2244 }
2245
2246 final boolean doThisProcess = onlyThisProcess == null
2247 || onlyThisProcess.equals(r.processName);
2248
2249 // First: if this is not the current activity being started, make
2250 // sure it matches the current configuration.
2251 if (r != starting && doThisProcess) {
2252 ensureActivityConfigurationLocked(r, 0);
2253 }
2254
2255 if (r.app == null || r.app.thread == null) {
2256 if (onlyThisProcess == null
2257 || onlyThisProcess.equals(r.processName)) {
2258 // This activity needs to be visible, but isn't even
2259 // running... get it started, but don't resume it
2260 // at this point.
2261 if (DEBUG_VISBILITY) Log.v(
2262 TAG, "Start and freeze screen for " + r);
2263 if (r != starting) {
2264 r.startFreezingScreenLocked(r.app, configChanges);
2265 }
2266 if (!r.visible) {
2267 if (DEBUG_VISBILITY) Log.v(
2268 TAG, "Starting and making visible: " + r);
2269 mWindowManager.setAppVisibility(r, true);
2270 }
2271 if (r != starting) {
2272 startSpecificActivityLocked(r, false, false);
2273 }
2274 }
2275
2276 } else if (r.visible) {
2277 // If this activity is already visible, then there is nothing
2278 // else to do here.
2279 if (DEBUG_VISBILITY) Log.v(
2280 TAG, "Skipping: already visible at " + r);
2281 r.stopFreezingScreenLocked(false);
2282
2283 } else if (onlyThisProcess == null) {
2284 // This activity is not currently visible, but is running.
2285 // Tell it to become visible.
2286 r.visible = true;
2287 if (r.state != ActivityState.RESUMED && r != starting) {
2288 // If this activity is paused, tell it
2289 // to now show its window.
2290 if (DEBUG_VISBILITY) Log.v(
2291 TAG, "Making visible and scheduling visibility: " + r);
2292 try {
2293 mWindowManager.setAppVisibility(r, true);
2294 r.app.thread.scheduleWindowVisibility(r, true);
2295 r.stopFreezingScreenLocked(false);
2296 } catch (Exception e) {
2297 // Just skip on any failure; we'll make it
2298 // visible when it next restarts.
2299 Log.w(TAG, "Exception thrown making visibile: "
2300 + r.intent.getComponent(), e);
2301 }
2302 }
2303 }
2304
2305 // Aggregate current change flags.
2306 configChanges |= r.configChangeFlags;
2307
2308 if (r.fullscreen) {
2309 // At this point, nothing else needs to be shown
2310 if (DEBUG_VISBILITY) Log.v(
2311 TAG, "Stopping: fullscreen at " + r);
2312 behindFullscreen = true;
2313 i--;
2314 break;
2315 }
2316 }
2317
2318 // Now for any activities that aren't visible to the user, make
2319 // sure they no longer are keeping the screen frozen.
2320 while (i >= 0) {
2321 r = (HistoryRecord)mHistory.get(i);
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2324 + " state=" + r.state
2325 + " behindFullscreen=" + behindFullscreen);
2326 if (!r.finishing) {
2327 if (behindFullscreen) {
2328 if (r.visible) {
2329 if (DEBUG_VISBILITY) Log.v(
2330 TAG, "Making invisible: " + r);
2331 r.visible = false;
2332 try {
2333 mWindowManager.setAppVisibility(r, false);
2334 if ((r.state == ActivityState.STOPPING
2335 || r.state == ActivityState.STOPPED)
2336 && r.app != null && r.app.thread != null) {
2337 if (DEBUG_VISBILITY) Log.v(
2338 TAG, "Scheduling invisibility: " + r);
2339 r.app.thread.scheduleWindowVisibility(r, false);
2340 }
2341 } catch (Exception e) {
2342 // Just skip on any failure; we'll make it
2343 // visible when it next restarts.
2344 Log.w(TAG, "Exception thrown making hidden: "
2345 + r.intent.getComponent(), e);
2346 }
2347 } else {
2348 if (DEBUG_VISBILITY) Log.v(
2349 TAG, "Already invisible: " + r);
2350 }
2351 } else if (r.fullscreen) {
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Now behindFullscreen: " + r);
2354 behindFullscreen = true;
2355 }
2356 }
2357 i--;
2358 }
2359 }
2360
2361 /**
2362 * Version of ensureActivitiesVisible that can easily be called anywhere.
2363 */
2364 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2365 int configChanges) {
2366 HistoryRecord r = topRunningActivityLocked(null);
2367 if (r != null) {
2368 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2369 }
2370 }
2371
2372 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2373 if (resumed) {
2374 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2375 } else {
2376 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2377 }
2378 }
2379
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002380 private boolean startHomeActivityLocked() {
2381 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2382 && mTopAction == null) {
2383 // We are running in factory test mode, but unable to find
2384 // the factory test app, so just sit around displaying the
2385 // error message and don't try to start anything.
2386 return false;
2387 }
2388 Intent intent = new Intent(
2389 mTopAction,
2390 mTopData != null ? Uri.parse(mTopData) : null);
2391 intent.setComponent(mTopComponent);
2392 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2393 intent.addCategory(Intent.CATEGORY_HOME);
2394 }
2395 ActivityInfo aInfo =
2396 intent.resolveActivityInfo(mContext.getPackageManager(),
2397 STOCK_PM_FLAGS);
2398 if (aInfo != null) {
2399 intent.setComponent(new ComponentName(
2400 aInfo.applicationInfo.packageName, aInfo.name));
2401 // Don't do this if the home app is currently being
2402 // instrumented.
2403 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2404 aInfo.applicationInfo.uid);
2405 if (app == null || app.instrumentationClass == null) {
2406 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2407 startActivityLocked(null, intent, null, null, 0, aInfo,
2408 null, null, 0, 0, 0, false, false);
2409 }
2410 }
2411
2412
2413 return true;
2414 }
2415
2416 /**
2417 * Starts the "new version setup screen" if appropriate.
2418 */
2419 private void startSetupActivityLocked() {
2420 // Only do this once per boot.
2421 if (mCheckedForSetup) {
2422 return;
2423 }
2424
2425 // We will show this screen if the current one is a different
2426 // version than the last one shown, and we are not running in
2427 // low-level factory test mode.
2428 final ContentResolver resolver = mContext.getContentResolver();
2429 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2430 Settings.Secure.getInt(resolver,
2431 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2432 mCheckedForSetup = true;
2433
2434 // See if we should be showing the platform update setup UI.
2435 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2436 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2437 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2438
2439 // We don't allow third party apps to replace this.
2440 ResolveInfo ri = null;
2441 for (int i=0; ris != null && i<ris.size(); i++) {
2442 if ((ris.get(i).activityInfo.applicationInfo.flags
2443 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2444 ri = ris.get(i);
2445 break;
2446 }
2447 }
2448
2449 if (ri != null) {
2450 String vers = ri.activityInfo.metaData != null
2451 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2452 : null;
2453 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2454 vers = ri.activityInfo.applicationInfo.metaData.getString(
2455 Intent.METADATA_SETUP_VERSION);
2456 }
2457 String lastVers = Settings.Secure.getString(
2458 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2459 if (vers != null && !vers.equals(lastVers)) {
2460 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2461 intent.setComponent(new ComponentName(
2462 ri.activityInfo.packageName, ri.activityInfo.name));
2463 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2464 null, null, 0, 0, 0, false, false);
2465 }
2466 }
2467 }
2468 }
2469
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002470 private void reportResumedActivity(HistoryRecord r) {
2471 //Log.i(TAG, "**** REPORT RESUME: " + r);
2472
2473 final int identHash = System.identityHashCode(r);
2474 updateUsageStats(r, true);
2475
2476 int i = mWatchers.beginBroadcast();
2477 while (i > 0) {
2478 i--;
2479 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2480 if (w != null) {
2481 try {
2482 w.activityResuming(identHash);
2483 } catch (RemoteException e) {
2484 }
2485 }
2486 }
2487 mWatchers.finishBroadcast();
2488 }
2489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 /**
2491 * Ensure that the top activity in the stack is resumed.
2492 *
2493 * @param prev The previously resumed activity, for when in the process
2494 * of pausing; can be null to call from elsewhere.
2495 *
2496 * @return Returns true if something is being resumed, or false if
2497 * nothing happened.
2498 */
2499 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2500 // Find the first activity that is not finishing.
2501 HistoryRecord next = topRunningActivityLocked(null);
2502
2503 // Remember how we'll process this pause/resume situation, and ensure
2504 // that the state is reset however we wind up proceeding.
2505 final boolean userLeaving = mUserLeaving;
2506 mUserLeaving = false;
2507
2508 if (next == null) {
2509 // There are no more activities! Let's just start up the
2510 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002511 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 }
2513
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002514 next.delayedResume = false;
2515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 // If the top activity is the resumed one, nothing to do.
2517 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2518 // Make sure we have executed any pending transitions, since there
2519 // should be nothing left to do at this point.
2520 mWindowManager.executeAppTransition();
2521 return false;
2522 }
2523
2524 // If we are sleeping, and there is no resumed activity, and the top
2525 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002526 if ((mSleeping || mShuttingDown)
2527 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 // Make sure we have executed any pending transitions, since there
2529 // should be nothing left to do at this point.
2530 mWindowManager.executeAppTransition();
2531 return false;
2532 }
2533
2534 // The activity may be waiting for stop, but that is no longer
2535 // appropriate for it.
2536 mStoppingActivities.remove(next);
2537 mWaitingVisibleActivities.remove(next);
2538
2539 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2540
2541 // If we are currently pausing an activity, then don't do anything
2542 // until that is done.
2543 if (mPausingActivity != null) {
2544 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2545 return false;
2546 }
2547
2548 // We need to start pausing the current activity so the top one
2549 // can be resumed...
2550 if (mResumedActivity != null) {
2551 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2552 startPausingLocked(userLeaving, false);
2553 return true;
2554 }
2555
2556 if (prev != null && prev != next) {
2557 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2558 prev.waitingVisible = true;
2559 mWaitingVisibleActivities.add(prev);
2560 if (DEBUG_SWITCH) Log.v(
2561 TAG, "Resuming top, waiting visible to hide: " + prev);
2562 } else {
2563 // The next activity is already visible, so hide the previous
2564 // activity's windows right now so we can show the new one ASAP.
2565 // We only do this if the previous is finishing, which should mean
2566 // it is on top of the one being resumed so hiding it quickly
2567 // is good. Otherwise, we want to do the normal route of allowing
2568 // the resumed activity to be shown so we can decide if the
2569 // previous should actually be hidden depending on whether the
2570 // new one is found to be full-screen or not.
2571 if (prev.finishing) {
2572 mWindowManager.setAppVisibility(prev, false);
2573 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2574 + prev + ", waitingVisible="
2575 + (prev != null ? prev.waitingVisible : null)
2576 + ", nowVisible=" + next.nowVisible);
2577 } else {
2578 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2579 + prev + ", waitingVisible="
2580 + (prev != null ? prev.waitingVisible : null)
2581 + ", nowVisible=" + next.nowVisible);
2582 }
2583 }
2584 }
2585
2586 // We are starting up the next activity, so tell the window manager
2587 // that the previous one will be hidden soon. This way it can know
2588 // to ignore it when computing the desired screen orientation.
2589 if (prev != null) {
2590 if (prev.finishing) {
2591 if (DEBUG_TRANSITION) Log.v(TAG,
2592 "Prepare close transition: prev=" + prev);
2593 mWindowManager.prepareAppTransition(prev.task == next.task
2594 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2595 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2596 mWindowManager.setAppWillBeHidden(prev);
2597 mWindowManager.setAppVisibility(prev, false);
2598 } else {
2599 if (DEBUG_TRANSITION) Log.v(TAG,
2600 "Prepare open transition: prev=" + prev);
2601 mWindowManager.prepareAppTransition(prev.task == next.task
2602 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2603 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2604 }
2605 if (false) {
2606 mWindowManager.setAppWillBeHidden(prev);
2607 mWindowManager.setAppVisibility(prev, false);
2608 }
2609 } else if (mHistory.size() > 1) {
2610 if (DEBUG_TRANSITION) Log.v(TAG,
2611 "Prepare open transition: no previous");
2612 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2613 }
2614
2615 if (next.app != null && next.app.thread != null) {
2616 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2617
2618 // This activity is now becoming visible.
2619 mWindowManager.setAppVisibility(next, true);
2620
2621 HistoryRecord lastResumedActivity = mResumedActivity;
2622 ActivityState lastState = next.state;
2623
2624 updateCpuStats();
2625
2626 next.state = ActivityState.RESUMED;
2627 mResumedActivity = next;
2628 next.task.touchActiveTime();
2629 updateLRUListLocked(next.app, true);
2630 updateLRUListLocked(next);
2631
2632 // Have the window manager re-evaluate the orientation of
2633 // the screen based on the new activity order.
2634 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002635 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002636 next.mayFreezeScreenLocked(next.app) ? next : null);
2637 if (config != null) {
2638 next.frozenBeforeDestroy = true;
2639 }
2640 if (!updateConfigurationLocked(config, next)) {
2641 // The configuration update wasn't able to keep the existing
2642 // instance of the activity, and instead started a new one.
2643 // We should be all done, but let's just make sure our activity
2644 // is still at the top and schedule another run if something
2645 // weird happened.
2646 HistoryRecord nextNext = topRunningActivityLocked(null);
2647 if (DEBUG_SWITCH) Log.i(TAG,
2648 "Activity config changed during resume: " + next
2649 + ", new next: " + nextNext);
2650 if (nextNext != next) {
2651 // Do over!
2652 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2653 }
2654 mWindowManager.executeAppTransition();
2655 return true;
2656 }
2657
2658 try {
2659 // Deliver all pending results.
2660 ArrayList a = next.results;
2661 if (a != null) {
2662 final int N = a.size();
2663 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002664 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002665 TAG, "Delivering results to " + next
2666 + ": " + a);
2667 next.app.thread.scheduleSendResult(next, a);
2668 }
2669 }
2670
2671 if (next.newIntents != null) {
2672 next.app.thread.scheduleNewIntent(next.newIntents, next);
2673 }
2674
2675 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2676 System.identityHashCode(next),
2677 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678
2679 next.app.thread.scheduleResumeActivity(next,
2680 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 pauseIfSleepingLocked();
2683
2684 } catch (Exception e) {
2685 // Whoops, need to restart this activity!
2686 next.state = lastState;
2687 mResumedActivity = lastResumedActivity;
2688 if (Config.LOGD) Log.d(TAG,
2689 "Restarting because process died: " + next);
2690 if (!next.hasBeenLaunched) {
2691 next.hasBeenLaunched = true;
2692 } else {
2693 if (SHOW_APP_STARTING_ICON) {
2694 mWindowManager.setAppStartingWindow(
2695 next, next.packageName, next.theme,
2696 next.nonLocalizedLabel,
2697 next.labelRes, next.icon, null, true);
2698 }
2699 }
2700 startSpecificActivityLocked(next, true, false);
2701 return true;
2702 }
2703
2704 // From this point on, if something goes wrong there is no way
2705 // to recover the activity.
2706 try {
2707 next.visible = true;
2708 completeResumeLocked(next);
2709 } catch (Exception e) {
2710 // If any exception gets thrown, toss away this
2711 // activity and try the next one.
2712 Log.w(TAG, "Exception thrown during resume of " + next, e);
2713 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2714 "resume-exception");
2715 return true;
2716 }
2717
2718 // Didn't need to use the icicle, and it is now out of date.
2719 next.icicle = null;
2720 next.haveState = false;
2721 next.stopped = false;
2722
2723 } else {
2724 // Whoops, need to restart this activity!
2725 if (!next.hasBeenLaunched) {
2726 next.hasBeenLaunched = true;
2727 } else {
2728 if (SHOW_APP_STARTING_ICON) {
2729 mWindowManager.setAppStartingWindow(
2730 next, next.packageName, next.theme,
2731 next.nonLocalizedLabel,
2732 next.labelRes, next.icon, null, true);
2733 }
2734 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2735 }
2736 startSpecificActivityLocked(next, true, true);
2737 }
2738
2739 return true;
2740 }
2741
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002742 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2743 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 final int NH = mHistory.size();
2745
2746 int addPos = -1;
2747
2748 if (!newTask) {
2749 // If starting in an existing task, find where that is...
2750 HistoryRecord next = null;
2751 boolean startIt = true;
2752 for (int i = NH-1; i >= 0; i--) {
2753 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2754 if (p.finishing) {
2755 continue;
2756 }
2757 if (p.task == r.task) {
2758 // Here it is! Now, if this is not yet visible to the
2759 // user, then just add it without starting; it will
2760 // get started when the user navigates back to it.
2761 addPos = i+1;
2762 if (!startIt) {
2763 mHistory.add(addPos, r);
2764 r.inHistory = true;
2765 r.task.numActivities++;
2766 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2767 r.info.screenOrientation, r.fullscreen);
2768 if (VALIDATE_TOKENS) {
2769 mWindowManager.validateAppTokens(mHistory);
2770 }
2771 return;
2772 }
2773 break;
2774 }
2775 if (p.fullscreen) {
2776 startIt = false;
2777 }
2778 next = p;
2779 }
2780 }
2781
2782 // Place a new activity at top of stack, so it is next to interact
2783 // with the user.
2784 if (addPos < 0) {
2785 addPos = mHistory.size();
2786 }
2787
2788 // If we are not placing the new activity frontmost, we do not want
2789 // to deliver the onUserLeaving callback to the actual frontmost
2790 // activity
2791 if (addPos < NH) {
2792 mUserLeaving = false;
2793 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2794 }
2795
2796 // Slot the activity into the history stack and proceed
2797 mHistory.add(addPos, r);
2798 r.inHistory = true;
2799 r.frontOfTask = newTask;
2800 r.task.numActivities++;
2801 if (NH > 0) {
2802 // We want to show the starting preview window if we are
2803 // switching to a new task, or the next activity's process is
2804 // not currently running.
2805 boolean showStartingIcon = newTask;
2806 ProcessRecord proc = r.app;
2807 if (proc == null) {
2808 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2809 }
2810 if (proc == null || proc.thread == null) {
2811 showStartingIcon = true;
2812 }
2813 if (DEBUG_TRANSITION) Log.v(TAG,
2814 "Prepare open transition: starting " + r);
2815 mWindowManager.prepareAppTransition(newTask
2816 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2817 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2818 mWindowManager.addAppToken(
2819 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2820 boolean doShow = true;
2821 if (newTask) {
2822 // Even though this activity is starting fresh, we still need
2823 // to reset it to make sure we apply affinities to move any
2824 // existing activities from other tasks in to it.
2825 // If the caller has requested that the target task be
2826 // reset, then do so.
2827 if ((r.intent.getFlags()
2828 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2829 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002830 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 }
2832 }
2833 if (SHOW_APP_STARTING_ICON && doShow) {
2834 // Figure out if we are transitioning from another activity that is
2835 // "has the same starting icon" as the next one. This allows the
2836 // window manager to keep the previous window it had previously
2837 // created, if it still had one.
2838 HistoryRecord prev = mResumedActivity;
2839 if (prev != null) {
2840 // We don't want to reuse the previous starting preview if:
2841 // (1) The current activity is in a different task.
2842 if (prev.task != r.task) prev = null;
2843 // (2) The current activity is already displayed.
2844 else if (prev.nowVisible) prev = null;
2845 }
2846 mWindowManager.setAppStartingWindow(
2847 r, r.packageName, r.theme, r.nonLocalizedLabel,
2848 r.labelRes, r.icon, prev, showStartingIcon);
2849 }
2850 } else {
2851 // If this is the first activity, don't do any fancy animations,
2852 // because there is nothing for it to animate on top of.
2853 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2854 r.info.screenOrientation, r.fullscreen);
2855 }
2856 if (VALIDATE_TOKENS) {
2857 mWindowManager.validateAppTokens(mHistory);
2858 }
2859
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002860 if (doResume) {
2861 resumeTopActivityLocked(null);
2862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 }
2864
2865 /**
2866 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002867 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2868 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 * an instance of that activity in the stack and, if found, finish all
2870 * activities on top of it and return the instance.
2871 *
2872 * @param newR Description of the new activity being started.
2873 * @return Returns the old activity that should be continue to be used,
2874 * or null if none was found.
2875 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002876 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 HistoryRecord newR, boolean doClear) {
2878 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002879
2880 // First find the requested task.
2881 while (i > 0) {
2882 i--;
2883 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2884 if (r.task.taskId == taskId) {
2885 i++;
2886 break;
2887 }
2888 }
2889
2890 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 while (i > 0) {
2892 i--;
2893 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2894 if (r.finishing) {
2895 continue;
2896 }
2897 if (r.task.taskId != taskId) {
2898 return null;
2899 }
2900 if (r.realActivity.equals(newR.realActivity)) {
2901 // Here it is! Now finish everything in front...
2902 HistoryRecord ret = r;
2903 if (doClear) {
2904 while (i < (mHistory.size()-1)) {
2905 i++;
2906 r = (HistoryRecord)mHistory.get(i);
2907 if (r.finishing) {
2908 continue;
2909 }
2910 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2911 null, "clear")) {
2912 i--;
2913 }
2914 }
2915 }
2916
2917 // Finally, if this is a normal launch mode (that is, not
2918 // expecting onNewIntent()), then we will finish the current
2919 // instance of the activity so a new fresh one can be started.
2920 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2921 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002922 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 if (index >= 0) {
2924 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2925 null, "clear");
2926 }
2927 return null;
2928 }
2929 }
2930
2931 return ret;
2932 }
2933 }
2934
2935 return null;
2936 }
2937
2938 /**
2939 * Find the activity in the history stack within the given task. Returns
2940 * the index within the history at which it's found, or < 0 if not found.
2941 */
2942 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2943 int i = mHistory.size();
2944 while (i > 0) {
2945 i--;
2946 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2947 if (candidate.task.taskId != task) {
2948 break;
2949 }
2950 if (candidate.realActivity.equals(r.realActivity)) {
2951 return i;
2952 }
2953 }
2954
2955 return -1;
2956 }
2957
2958 /**
2959 * Reorder the history stack so that the activity at the given index is
2960 * brought to the front.
2961 */
2962 private final HistoryRecord moveActivityToFrontLocked(int where) {
2963 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2964 int top = mHistory.size();
2965 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2966 mHistory.add(top, newTop);
2967 oldTop.frontOfTask = false;
2968 newTop.frontOfTask = true;
2969 return newTop;
2970 }
2971
2972 /**
2973 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2974 * method will be called at the proper time.
2975 */
2976 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2977 boolean sent = false;
2978 if (r.state == ActivityState.RESUMED
2979 && r.app != null && r.app.thread != null) {
2980 try {
2981 ArrayList<Intent> ar = new ArrayList<Intent>();
2982 ar.add(new Intent(intent));
2983 r.app.thread.scheduleNewIntent(ar, r);
2984 sent = true;
2985 } catch (Exception e) {
2986 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2987 }
2988 }
2989 if (!sent) {
2990 r.addNewIntentLocked(new Intent(intent));
2991 }
2992 }
2993
2994 private final void logStartActivity(int tag, HistoryRecord r,
2995 TaskRecord task) {
2996 EventLog.writeEvent(tag,
2997 System.identityHashCode(r), task.taskId,
2998 r.shortComponentName, r.intent.getAction(),
2999 r.intent.getType(), r.intent.getDataString(),
3000 r.intent.getFlags());
3001 }
3002
3003 private final int startActivityLocked(IApplicationThread caller,
3004 Intent intent, String resolvedType,
3005 Uri[] grantedUriPermissions,
3006 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3007 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003008 int callingPid, int callingUid, boolean onlyIfNeeded,
3009 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 Log.i(TAG, "Starting activity: " + intent);
3011
3012 HistoryRecord sourceRecord = null;
3013 HistoryRecord resultRecord = null;
3014 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003015 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003016 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003017 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3018 if (index >= 0) {
3019 sourceRecord = (HistoryRecord)mHistory.get(index);
3020 if (requestCode >= 0 && !sourceRecord.finishing) {
3021 resultRecord = sourceRecord;
3022 }
3023 }
3024 }
3025
3026 int launchFlags = intent.getFlags();
3027
3028 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3029 && sourceRecord != null) {
3030 // Transfer the result target from the source activity to the new
3031 // one being started, including any failures.
3032 if (requestCode >= 0) {
3033 return START_FORWARD_AND_REQUEST_CONFLICT;
3034 }
3035 resultRecord = sourceRecord.resultTo;
3036 resultWho = sourceRecord.resultWho;
3037 requestCode = sourceRecord.requestCode;
3038 sourceRecord.resultTo = null;
3039 if (resultRecord != null) {
3040 resultRecord.removeResultsLocked(
3041 sourceRecord, resultWho, requestCode);
3042 }
3043 }
3044
3045 int err = START_SUCCESS;
3046
3047 if (intent.getComponent() == null) {
3048 // We couldn't find a class that can handle the given Intent.
3049 // That's the end of that!
3050 err = START_INTENT_NOT_RESOLVED;
3051 }
3052
3053 if (err == START_SUCCESS && aInfo == null) {
3054 // We couldn't find the specific class specified in the Intent.
3055 // Also the end of the line.
3056 err = START_CLASS_NOT_FOUND;
3057 }
3058
3059 ProcessRecord callerApp = null;
3060 if (err == START_SUCCESS && caller != null) {
3061 callerApp = getRecordForAppLocked(caller);
3062 if (callerApp != null) {
3063 callingPid = callerApp.pid;
3064 callingUid = callerApp.info.uid;
3065 } else {
3066 Log.w(TAG, "Unable to find app for caller " + caller
3067 + " (pid=" + callingPid + ") when starting: "
3068 + intent.toString());
3069 err = START_PERMISSION_DENIED;
3070 }
3071 }
3072
3073 if (err != START_SUCCESS) {
3074 if (resultRecord != null) {
3075 sendActivityResultLocked(-1,
3076 resultRecord, resultWho, requestCode,
3077 Activity.RESULT_CANCELED, null);
3078 }
3079 return err;
3080 }
3081
3082 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3083 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3084 if (perm != PackageManager.PERMISSION_GRANTED) {
3085 if (resultRecord != null) {
3086 sendActivityResultLocked(-1,
3087 resultRecord, resultWho, requestCode,
3088 Activity.RESULT_CANCELED, null);
3089 }
3090 String msg = "Permission Denial: starting " + intent.toString()
3091 + " from " + callerApp + " (pid=" + callingPid
3092 + ", uid=" + callingUid + ")"
3093 + " requires " + aInfo.permission;
3094 Log.w(TAG, msg);
3095 throw new SecurityException(msg);
3096 }
3097
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003098 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 boolean abort = false;
3100 try {
3101 // The Intent we give to the watcher has the extra data
3102 // stripped off, since it can contain private information.
3103 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003104 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 aInfo.applicationInfo.packageName);
3106 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003107 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003108 }
3109
3110 if (abort) {
3111 if (resultRecord != null) {
3112 sendActivityResultLocked(-1,
3113 resultRecord, resultWho, requestCode,
3114 Activity.RESULT_CANCELED, null);
3115 }
3116 // We pretend to the caller that it was really started, but
3117 // they will just get a cancel result.
3118 return START_SUCCESS;
3119 }
3120 }
3121
3122 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3123 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003124 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003125
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003126 if (mResumedActivity == null
3127 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3128 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3129 PendingActivityLaunch pal = new PendingActivityLaunch();
3130 pal.r = r;
3131 pal.sourceRecord = sourceRecord;
3132 pal.grantedUriPermissions = grantedUriPermissions;
3133 pal.grantedMode = grantedMode;
3134 pal.onlyIfNeeded = onlyIfNeeded;
3135 mPendingActivityLaunches.add(pal);
3136 return START_SWITCHES_CANCELED;
3137 }
3138 }
3139
3140 if (mDidAppSwitch) {
3141 // This is the second allowed switch since we stopped switches,
3142 // so now just generally allow switches. Use case: user presses
3143 // home (switches disabled, switch to home, mDidAppSwitch now true);
3144 // user taps a home icon (coming from home so allowed, we hit here
3145 // and now allow anyone to switch again).
3146 mAppSwitchesAllowedTime = 0;
3147 } else {
3148 mDidAppSwitch = true;
3149 }
3150
3151 doPendingActivityLaunchesLocked(false);
3152
3153 return startActivityUncheckedLocked(r, sourceRecord,
3154 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3155 }
3156
3157 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3158 final int N = mPendingActivityLaunches.size();
3159 if (N <= 0) {
3160 return;
3161 }
3162 for (int i=0; i<N; i++) {
3163 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3164 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3165 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3166 doResume && i == (N-1));
3167 }
3168 mPendingActivityLaunches.clear();
3169 }
3170
3171 private final int startActivityUncheckedLocked(HistoryRecord r,
3172 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3173 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3174 final Intent intent = r.intent;
3175 final int callingUid = r.launchedFromUid;
3176
3177 int launchFlags = intent.getFlags();
3178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 // We'll invoke onUserLeaving before onPause only if the launching
3180 // activity did not explicitly state that this is an automated launch.
3181 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3182 if (DEBUG_USER_LEAVING) Log.v(TAG,
3183 "startActivity() => mUserLeaving=" + mUserLeaving);
3184
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003185 // If the caller has asked not to resume at this point, we make note
3186 // of this in the record so that we can skip it when trying to find
3187 // the top running activity.
3188 if (!doResume) {
3189 r.delayedResume = true;
3190 }
3191
3192 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3193 != 0 ? r : null;
3194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 // If the onlyIfNeeded flag is set, then we can do this if the activity
3196 // being launched is the same as the one making the call... or, as
3197 // a special case, if we do not know the caller then we count the
3198 // current top activity as the caller.
3199 if (onlyIfNeeded) {
3200 HistoryRecord checkedCaller = sourceRecord;
3201 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003202 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 }
3204 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3205 // Caller is not the same as launcher, so always needed.
3206 onlyIfNeeded = false;
3207 }
3208 }
3209
3210 if (grantedUriPermissions != null && callingUid > 0) {
3211 for (int i=0; i<grantedUriPermissions.length; i++) {
3212 grantUriPermissionLocked(callingUid, r.packageName,
3213 grantedUriPermissions[i], grantedMode, r);
3214 }
3215 }
3216
3217 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3218 intent, r);
3219
3220 if (sourceRecord == null) {
3221 // This activity is not being started from another... in this
3222 // case we -always- start a new task.
3223 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3224 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3225 + intent);
3226 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3227 }
3228 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3229 // The original activity who is starting us is running as a single
3230 // instance... this new activity it is starting must go on its
3231 // own task.
3232 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3233 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3234 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3235 // The activity being started is a single instance... it always
3236 // gets launched into its own task.
3237 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3238 }
3239
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003240 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 // For whatever reason this activity is being launched into a new
3242 // task... yet the caller has requested a result back. Well, that
3243 // is pretty messed up, so instead immediately send back a cancel
3244 // and let the new task continue launched as normal without a
3245 // dependency on its originator.
3246 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3247 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003248 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003249 Activity.RESULT_CANCELED, null);
3250 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 }
3252
3253 boolean addingToTask = false;
3254 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3255 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3256 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3257 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3258 // If bring to front is requested, and no result is requested, and
3259 // we can find a task that was started with this same
3260 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003261 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 // See if there is a task to bring to the front. If this is
3263 // a SINGLE_INSTANCE activity, there can be one and only one
3264 // instance of it in the history, and it is always in its own
3265 // unique task, so we do a special search.
3266 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3267 ? findTaskLocked(intent, r.info)
3268 : findActivityLocked(intent, r.info);
3269 if (taskTop != null) {
3270 if (taskTop.task.intent == null) {
3271 // This task was started because of movement of
3272 // the activity based on affinity... now that we
3273 // are actually launching it, we can assign the
3274 // base intent.
3275 taskTop.task.setIntent(intent, r.info);
3276 }
3277 // If the target task is not in the front, then we need
3278 // to bring it to the front... except... well, with
3279 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3280 // to have the same behavior as if a new instance was
3281 // being started, which means not bringing it to the front
3282 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003283 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 if (curTop.task != taskTop.task) {
3285 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3286 boolean callerAtFront = sourceRecord == null
3287 || curTop.task == sourceRecord.task;
3288 if (callerAtFront) {
3289 // We really do want to push this one into the
3290 // user's face, right now.
3291 moveTaskToFrontLocked(taskTop.task);
3292 }
3293 }
3294 // If the caller has requested that the target task be
3295 // reset, then do so.
3296 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3297 taskTop = resetTaskIfNeededLocked(taskTop, r);
3298 }
3299 if (onlyIfNeeded) {
3300 // We don't need to start a new activity, and
3301 // the client said not to do anything if that
3302 // is the case, so this is it! And for paranoia, make
3303 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003304 if (doResume) {
3305 resumeTopActivityLocked(null);
3306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 return START_RETURN_INTENT_TO_CALLER;
3308 }
3309 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3310 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3311 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3312 // In this situation we want to remove all activities
3313 // from the task up to the one being started. In most
3314 // cases this means we are resetting the task to its
3315 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003316 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003317 taskTop.task.taskId, r, true);
3318 if (top != null) {
3319 if (top.frontOfTask) {
3320 // Activity aliases may mean we use different
3321 // intents for the top activity, so make sure
3322 // the task now has the identity of the new
3323 // intent.
3324 top.task.setIntent(r.intent, r.info);
3325 }
3326 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3327 deliverNewIntentLocked(top, r.intent);
3328 } else {
3329 // A special case: we need to
3330 // start the activity because it is not currently
3331 // running, and the caller has asked to clear the
3332 // current task to have this activity at the top.
3333 addingToTask = true;
3334 // Now pretend like this activity is being started
3335 // by the top of its task, so it is put in the
3336 // right place.
3337 sourceRecord = taskTop;
3338 }
3339 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3340 // In this case the top activity on the task is the
3341 // same as the one being launched, so we take that
3342 // as a request to bring the task to the foreground.
3343 // If the top activity in the task is the root
3344 // activity, deliver this new intent to it if it
3345 // desires.
3346 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3347 && taskTop.realActivity.equals(r.realActivity)) {
3348 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3349 if (taskTop.frontOfTask) {
3350 taskTop.task.setIntent(r.intent, r.info);
3351 }
3352 deliverNewIntentLocked(taskTop, r.intent);
3353 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3354 // In this case we are launching the root activity
3355 // of the task, but with a different intent. We
3356 // should start a new instance on top.
3357 addingToTask = true;
3358 sourceRecord = taskTop;
3359 }
3360 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3361 // In this case an activity is being launched in to an
3362 // existing task, without resetting that task. This
3363 // is typically the situation of launching an activity
3364 // from a notification or shortcut. We want to place
3365 // the new activity on top of the current task.
3366 addingToTask = true;
3367 sourceRecord = taskTop;
3368 } else if (!taskTop.task.rootWasReset) {
3369 // In this case we are launching in to an existing task
3370 // that has not yet been started from its front door.
3371 // The current task has been brought to the front.
3372 // Ideally, we'd probably like to place this new task
3373 // at the bottom of its stack, but that's a little hard
3374 // to do with the current organization of the code so
3375 // for now we'll just drop it.
3376 taskTop.task.setIntent(r.intent, r.info);
3377 }
3378 if (!addingToTask) {
3379 // We didn't do anything... but it was needed (a.k.a., client
3380 // don't use that intent!) And for paranoia, make
3381 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003382 if (doResume) {
3383 resumeTopActivityLocked(null);
3384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 return START_TASK_TO_FRONT;
3386 }
3387 }
3388 }
3389 }
3390
3391 //String uri = r.intent.toURI();
3392 //Intent intent2 = new Intent(uri);
3393 //Log.i(TAG, "Given intent: " + r.intent);
3394 //Log.i(TAG, "URI is: " + uri);
3395 //Log.i(TAG, "To intent: " + intent2);
3396
3397 if (r.packageName != null) {
3398 // If the activity being launched is the same as the one currently
3399 // at the top, then we need to check if it should only be launched
3400 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3402 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 if (top.realActivity.equals(r.realActivity)) {
3404 if (top.app != null && top.app.thread != null) {
3405 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3406 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3407 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3408 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3409 // For paranoia, make sure we have correctly
3410 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003411 if (doResume) {
3412 resumeTopActivityLocked(null);
3413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 if (onlyIfNeeded) {
3415 // We don't need to start a new activity, and
3416 // the client said not to do anything if that
3417 // is the case, so this is it!
3418 return START_RETURN_INTENT_TO_CALLER;
3419 }
3420 deliverNewIntentLocked(top, r.intent);
3421 return START_DELIVERED_TO_TOP;
3422 }
3423 }
3424 }
3425 }
3426
3427 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003428 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003430 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 Activity.RESULT_CANCELED, null);
3432 }
3433 return START_CLASS_NOT_FOUND;
3434 }
3435
3436 boolean newTask = false;
3437
3438 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003439 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3441 // todo: should do better management of integers.
3442 mCurTask++;
3443 if (mCurTask <= 0) {
3444 mCurTask = 1;
3445 }
3446 r.task = new TaskRecord(mCurTask, r.info, intent,
3447 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3448 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3449 + " in new task " + r.task);
3450 newTask = true;
3451 addRecentTask(r.task);
3452
3453 } else if (sourceRecord != null) {
3454 if (!addingToTask &&
3455 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3456 // In this case, we are adding the activity to an existing
3457 // task, but the caller has asked to clear that task if the
3458 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 sourceRecord.task.taskId, r, true);
3461 if (top != null) {
3462 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3463 deliverNewIntentLocked(top, r.intent);
3464 // For paranoia, make sure we have correctly
3465 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003466 if (doResume) {
3467 resumeTopActivityLocked(null);
3468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 return START_DELIVERED_TO_TOP;
3470 }
3471 } else if (!addingToTask &&
3472 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3473 // In this case, we are launching an activity in our own task
3474 // that may already be running somewhere in the history, and
3475 // we want to shuffle it to the front of the stack if so.
3476 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3477 if (where >= 0) {
3478 HistoryRecord top = moveActivityToFrontLocked(where);
3479 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3480 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003481 if (doResume) {
3482 resumeTopActivityLocked(null);
3483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 return START_DELIVERED_TO_TOP;
3485 }
3486 }
3487 // An existing activity is starting this new activity, so we want
3488 // to keep the new one in the same task as the one that is starting
3489 // it.
3490 r.task = sourceRecord.task;
3491 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3492 + " in existing task " + r.task);
3493
3494 } else {
3495 // This not being started from an existing activity, and not part
3496 // of a new task... just put it in the top task, though these days
3497 // this case should never happen.
3498 final int N = mHistory.size();
3499 HistoryRecord prev =
3500 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3501 r.task = prev != null
3502 ? prev.task
3503 : new TaskRecord(mCurTask, r.info, intent,
3504 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3505 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3506 + " in new guessed " + r.task);
3507 }
3508 if (newTask) {
3509 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3510 }
3511 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003512 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 return START_SUCCESS;
3514 }
3515
3516 public final int startActivity(IApplicationThread caller,
3517 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3518 int grantedMode, IBinder resultTo,
3519 String resultWho, int requestCode, boolean onlyIfNeeded,
3520 boolean debug) {
3521 // Refuse possible leaked file descriptors
3522 if (intent != null && intent.hasFileDescriptors()) {
3523 throw new IllegalArgumentException("File descriptors passed in Intent");
3524 }
3525
The Android Open Source Project4df24232009-03-05 14:34:35 -08003526 final boolean componentSpecified = intent.getComponent() != null;
3527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 // Don't modify the client's object!
3529 intent = new Intent(intent);
3530
3531 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 ActivityInfo aInfo;
3533 try {
3534 ResolveInfo rInfo =
3535 ActivityThread.getPackageManager().resolveIntent(
3536 intent, resolvedType,
3537 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003538 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 aInfo = rInfo != null ? rInfo.activityInfo : null;
3540 } catch (RemoteException e) {
3541 aInfo = null;
3542 }
3543
3544 if (aInfo != null) {
3545 // Store the found target back into the intent, because now that
3546 // we have it we never want to do this again. For example, if the
3547 // user navigates back to this point in the history, we should
3548 // always restart the exact same activity.
3549 intent.setComponent(new ComponentName(
3550 aInfo.applicationInfo.packageName, aInfo.name));
3551
3552 // Don't debug things in the system process
3553 if (debug) {
3554 if (!aInfo.processName.equals("system")) {
3555 setDebugApp(aInfo.processName, true, false);
3556 }
3557 }
3558 }
3559
3560 synchronized(this) {
3561 final long origId = Binder.clearCallingIdentity();
3562 int res = startActivityLocked(caller, intent, resolvedType,
3563 grantedUriPermissions, grantedMode, aInfo,
3564 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003565 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 Binder.restoreCallingIdentity(origId);
3567 return res;
3568 }
3569 }
3570
3571 public boolean startNextMatchingActivity(IBinder callingActivity,
3572 Intent intent) {
3573 // Refuse possible leaked file descriptors
3574 if (intent != null && intent.hasFileDescriptors() == true) {
3575 throw new IllegalArgumentException("File descriptors passed in Intent");
3576 }
3577
3578 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003579 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 if (index < 0) {
3581 return false;
3582 }
3583 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3584 if (r.app == null || r.app.thread == null) {
3585 // The caller is not running... d'oh!
3586 return false;
3587 }
3588 intent = new Intent(intent);
3589 // The caller is not allowed to change the data.
3590 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3591 // And we are resetting to find the next component...
3592 intent.setComponent(null);
3593
3594 ActivityInfo aInfo = null;
3595 try {
3596 List<ResolveInfo> resolves =
3597 ActivityThread.getPackageManager().queryIntentActivities(
3598 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003599 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600
3601 // Look for the original activity in the list...
3602 final int N = resolves != null ? resolves.size() : 0;
3603 for (int i=0; i<N; i++) {
3604 ResolveInfo rInfo = resolves.get(i);
3605 if (rInfo.activityInfo.packageName.equals(r.packageName)
3606 && rInfo.activityInfo.name.equals(r.info.name)) {
3607 // We found the current one... the next matching is
3608 // after it.
3609 i++;
3610 if (i<N) {
3611 aInfo = resolves.get(i).activityInfo;
3612 }
3613 break;
3614 }
3615 }
3616 } catch (RemoteException e) {
3617 }
3618
3619 if (aInfo == null) {
3620 // Nobody who is next!
3621 return false;
3622 }
3623
3624 intent.setComponent(new ComponentName(
3625 aInfo.applicationInfo.packageName, aInfo.name));
3626 intent.setFlags(intent.getFlags()&~(
3627 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3628 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3629 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3630 Intent.FLAG_ACTIVITY_NEW_TASK));
3631
3632 // Okay now we need to start the new activity, replacing the
3633 // currently running activity. This is a little tricky because
3634 // we want to start the new one as if the current one is finished,
3635 // but not finish the current one first so that there is no flicker.
3636 // And thus...
3637 final boolean wasFinishing = r.finishing;
3638 r.finishing = true;
3639
3640 // Propagate reply information over to the new activity.
3641 final HistoryRecord resultTo = r.resultTo;
3642 final String resultWho = r.resultWho;
3643 final int requestCode = r.requestCode;
3644 r.resultTo = null;
3645 if (resultTo != null) {
3646 resultTo.removeResultsLocked(r, resultWho, requestCode);
3647 }
3648
3649 final long origId = Binder.clearCallingIdentity();
3650 // XXX we are not dealing with propagating grantedUriPermissions...
3651 // those are not yet exposed to user code, so there is no need.
3652 int res = startActivityLocked(r.app.thread, intent,
3653 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003654 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003655 Binder.restoreCallingIdentity(origId);
3656
3657 r.finishing = wasFinishing;
3658 if (res != START_SUCCESS) {
3659 return false;
3660 }
3661 return true;
3662 }
3663 }
3664
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003665 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003666 Intent intent, String resolvedType, IBinder resultTo,
3667 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003668
3669 // This is so super not safe, that only the system (or okay root)
3670 // can do it.
3671 final int callingUid = Binder.getCallingUid();
3672 if (callingUid != 0 && callingUid != Process.myUid()) {
3673 throw new SecurityException(
3674 "startActivityInPackage only available to the system");
3675 }
3676
The Android Open Source Project4df24232009-03-05 14:34:35 -08003677 final boolean componentSpecified = intent.getComponent() != null;
3678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003679 // Don't modify the client's object!
3680 intent = new Intent(intent);
3681
3682 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 ActivityInfo aInfo;
3684 try {
3685 ResolveInfo rInfo =
3686 ActivityThread.getPackageManager().resolveIntent(
3687 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003688 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 aInfo = rInfo != null ? rInfo.activityInfo : null;
3690 } catch (RemoteException e) {
3691 aInfo = null;
3692 }
3693
3694 if (aInfo != null) {
3695 // Store the found target back into the intent, because now that
3696 // we have it we never want to do this again. For example, if the
3697 // user navigates back to this point in the history, we should
3698 // always restart the exact same activity.
3699 intent.setComponent(new ComponentName(
3700 aInfo.applicationInfo.packageName, aInfo.name));
3701 }
3702
3703 synchronized(this) {
3704 return startActivityLocked(null, intent, resolvedType,
3705 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003706 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 }
3708 }
3709
3710 private final void addRecentTask(TaskRecord task) {
3711 // Remove any existing entries that are the same kind of task.
3712 int N = mRecentTasks.size();
3713 for (int i=0; i<N; i++) {
3714 TaskRecord tr = mRecentTasks.get(i);
3715 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3716 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3717 mRecentTasks.remove(i);
3718 i--;
3719 N--;
3720 if (task.intent == null) {
3721 // If the new recent task we are adding is not fully
3722 // specified, then replace it with the existing recent task.
3723 task = tr;
3724 }
3725 }
3726 }
3727 if (N >= MAX_RECENT_TASKS) {
3728 mRecentTasks.remove(N-1);
3729 }
3730 mRecentTasks.add(0, task);
3731 }
3732
3733 public void setRequestedOrientation(IBinder token,
3734 int requestedOrientation) {
3735 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003736 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 if (index < 0) {
3738 return;
3739 }
3740 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3741 final long origId = Binder.clearCallingIdentity();
3742 mWindowManager.setAppOrientation(r, requestedOrientation);
3743 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003744 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003745 r.mayFreezeScreenLocked(r.app) ? r : null);
3746 if (config != null) {
3747 r.frozenBeforeDestroy = true;
3748 if (!updateConfigurationLocked(config, r)) {
3749 resumeTopActivityLocked(null);
3750 }
3751 }
3752 Binder.restoreCallingIdentity(origId);
3753 }
3754 }
3755
3756 public int getRequestedOrientation(IBinder token) {
3757 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003758 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003759 if (index < 0) {
3760 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3761 }
3762 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3763 return mWindowManager.getAppOrientation(r);
3764 }
3765 }
3766
3767 private final void stopActivityLocked(HistoryRecord r) {
3768 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3769 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3770 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3771 if (!r.finishing) {
3772 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3773 "no-history");
3774 }
3775 } else if (r.app != null && r.app.thread != null) {
3776 if (mFocusedActivity == r) {
3777 setFocusedActivityLocked(topRunningActivityLocked(null));
3778 }
3779 r.resumeKeyDispatchingLocked();
3780 try {
3781 r.stopped = false;
3782 r.state = ActivityState.STOPPING;
3783 if (DEBUG_VISBILITY) Log.v(
3784 TAG, "Stopping visible=" + r.visible + " for " + r);
3785 if (!r.visible) {
3786 mWindowManager.setAppVisibility(r, false);
3787 }
3788 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3789 } catch (Exception e) {
3790 // Maybe just ignore exceptions here... if the process
3791 // has crashed, our death notification will clean things
3792 // up.
3793 Log.w(TAG, "Exception thrown during pause", e);
3794 // Just in case, assume it to be stopped.
3795 r.stopped = true;
3796 r.state = ActivityState.STOPPED;
3797 if (r.configDestroy) {
3798 destroyActivityLocked(r, true);
3799 }
3800 }
3801 }
3802 }
3803
3804 /**
3805 * @return Returns true if the activity is being finished, false if for
3806 * some reason it is being left as-is.
3807 */
3808 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3809 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003810 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003811 TAG, "Finishing activity: token=" + token
3812 + ", result=" + resultCode + ", data=" + resultData);
3813
Dianne Hackborn75b03852009-06-12 15:43:26 -07003814 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003815 if (index < 0) {
3816 return false;
3817 }
3818 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3819
3820 // Is this the last activity left?
3821 boolean lastActivity = true;
3822 for (int i=mHistory.size()-1; i>=0; i--) {
3823 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3824 if (!p.finishing && p != r) {
3825 lastActivity = false;
3826 break;
3827 }
3828 }
3829
3830 // If this is the last activity, but it is the home activity, then
3831 // just don't finish it.
3832 if (lastActivity) {
3833 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3834 return false;
3835 }
3836 }
3837
3838 finishActivityLocked(r, index, resultCode, resultData, reason);
3839 return true;
3840 }
3841
3842 /**
3843 * @return Returns true if this activity has been removed from the history
3844 * list, or false if it is still in the list and will be removed later.
3845 */
3846 private final boolean finishActivityLocked(HistoryRecord r, int index,
3847 int resultCode, Intent resultData, String reason) {
3848 if (r.finishing) {
3849 Log.w(TAG, "Duplicate finish request for " + r);
3850 return false;
3851 }
3852
3853 r.finishing = true;
3854 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3855 System.identityHashCode(r),
3856 r.task.taskId, r.shortComponentName, reason);
3857 r.task.numActivities--;
3858 if (r.frontOfTask && index < (mHistory.size()-1)) {
3859 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3860 if (next.task == r.task) {
3861 next.frontOfTask = true;
3862 }
3863 }
3864
3865 r.pauseKeyDispatchingLocked();
3866 if (mFocusedActivity == r) {
3867 setFocusedActivityLocked(topRunningActivityLocked(null));
3868 }
3869
3870 // send the result
3871 HistoryRecord resultTo = r.resultTo;
3872 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003873 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3874 + " who=" + r.resultWho + " req=" + r.requestCode
3875 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 if (r.info.applicationInfo.uid > 0) {
3877 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3878 r.packageName, resultData, r);
3879 }
3880 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3881 resultData);
3882 r.resultTo = null;
3883 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003884 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885
3886 // Make sure this HistoryRecord is not holding on to other resources,
3887 // because clients have remote IPC references to this object so we
3888 // can't assume that will go away and want to avoid circular IPC refs.
3889 r.results = null;
3890 r.pendingResults = null;
3891 r.newIntents = null;
3892 r.icicle = null;
3893
3894 if (mPendingThumbnails.size() > 0) {
3895 // There are clients waiting to receive thumbnails so, in case
3896 // this is an activity that someone is waiting for, add it
3897 // to the pending list so we can correctly update the clients.
3898 mCancelledThumbnails.add(r);
3899 }
3900
3901 if (mResumedActivity == r) {
3902 boolean endTask = index <= 0
3903 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3904 if (DEBUG_TRANSITION) Log.v(TAG,
3905 "Prepare close transition: finishing " + r);
3906 mWindowManager.prepareAppTransition(endTask
3907 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3908 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3909
3910 // Tell window manager to prepare for this one to be removed.
3911 mWindowManager.setAppVisibility(r, false);
3912
3913 if (mPausingActivity == null) {
3914 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3915 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3916 startPausingLocked(false, false);
3917 }
3918
3919 } else if (r.state != ActivityState.PAUSING) {
3920 // If the activity is PAUSING, we will complete the finish once
3921 // it is done pausing; else we can just directly finish it here.
3922 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3923 return finishCurrentActivityLocked(r, index,
3924 FINISH_AFTER_PAUSE) == null;
3925 } else {
3926 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3927 }
3928
3929 return false;
3930 }
3931
3932 private static final int FINISH_IMMEDIATELY = 0;
3933 private static final int FINISH_AFTER_PAUSE = 1;
3934 private static final int FINISH_AFTER_VISIBLE = 2;
3935
3936 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3937 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003938 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003939 if (index < 0) {
3940 return null;
3941 }
3942
3943 return finishCurrentActivityLocked(r, index, mode);
3944 }
3945
3946 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3947 int index, int mode) {
3948 // First things first: if this activity is currently visible,
3949 // and the resumed activity is not yet visible, then hold off on
3950 // finishing until the resumed one becomes visible.
3951 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3952 if (!mStoppingActivities.contains(r)) {
3953 mStoppingActivities.add(r);
3954 if (mStoppingActivities.size() > 3) {
3955 // If we already have a few activities waiting to stop,
3956 // then give up on things going idle and start clearing
3957 // them out.
3958 Message msg = Message.obtain();
3959 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3960 mHandler.sendMessage(msg);
3961 }
3962 }
3963 r.state = ActivityState.STOPPING;
3964 updateOomAdjLocked();
3965 return r;
3966 }
3967
3968 // make sure the record is cleaned out of other places.
3969 mStoppingActivities.remove(r);
3970 mWaitingVisibleActivities.remove(r);
3971 if (mResumedActivity == r) {
3972 mResumedActivity = null;
3973 }
3974 final ActivityState prevState = r.state;
3975 r.state = ActivityState.FINISHING;
3976
3977 if (mode == FINISH_IMMEDIATELY
3978 || prevState == ActivityState.STOPPED
3979 || prevState == ActivityState.INITIALIZING) {
3980 // If this activity is already stopped, we can just finish
3981 // it right now.
3982 return destroyActivityLocked(r, true) ? null : r;
3983 } else {
3984 // Need to go through the full pause cycle to get this
3985 // activity into the stopped state and then finish it.
3986 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3987 mFinishingActivities.add(r);
3988 resumeTopActivityLocked(null);
3989 }
3990 return r;
3991 }
3992
3993 /**
3994 * This is the internal entry point for handling Activity.finish().
3995 *
3996 * @param token The Binder token referencing the Activity we want to finish.
3997 * @param resultCode Result code, if any, from this Activity.
3998 * @param resultData Result data (Intent), if any, from this Activity.
3999 *
4000 * @result Returns true if the activity successfully finished, or false if it is still running.
4001 */
4002 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4003 // Refuse possible leaked file descriptors
4004 if (resultData != null && resultData.hasFileDescriptors() == true) {
4005 throw new IllegalArgumentException("File descriptors passed in Intent");
4006 }
4007
4008 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004009 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004010 // Find the first activity that is not finishing.
4011 HistoryRecord next = topRunningActivityLocked(token, 0);
4012 if (next != null) {
4013 // ask watcher if this is allowed
4014 boolean resumeOK = true;
4015 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004016 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004018 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004019 }
4020
4021 if (!resumeOK) {
4022 return false;
4023 }
4024 }
4025 }
4026 final long origId = Binder.clearCallingIdentity();
4027 boolean res = requestFinishActivityLocked(token, resultCode,
4028 resultData, "app-request");
4029 Binder.restoreCallingIdentity(origId);
4030 return res;
4031 }
4032 }
4033
4034 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4035 String resultWho, int requestCode, int resultCode, Intent data) {
4036
4037 if (callingUid > 0) {
4038 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4039 data, r);
4040 }
4041
The Android Open Source Project10592532009-03-18 17:39:46 -07004042 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4043 + " : who=" + resultWho + " req=" + requestCode
4044 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004045 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4046 try {
4047 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4048 list.add(new ResultInfo(resultWho, requestCode,
4049 resultCode, data));
4050 r.app.thread.scheduleSendResult(r, list);
4051 return;
4052 } catch (Exception e) {
4053 Log.w(TAG, "Exception thrown sending result to " + r, e);
4054 }
4055 }
4056
4057 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4058 }
4059
4060 public final void finishSubActivity(IBinder token, String resultWho,
4061 int requestCode) {
4062 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004063 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004064 if (index < 0) {
4065 return;
4066 }
4067 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4068
4069 final long origId = Binder.clearCallingIdentity();
4070
4071 int i;
4072 for (i=mHistory.size()-1; i>=0; i--) {
4073 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4074 if (r.resultTo == self && r.requestCode == requestCode) {
4075 if ((r.resultWho == null && resultWho == null) ||
4076 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4077 finishActivityLocked(r, i,
4078 Activity.RESULT_CANCELED, null, "request-sub");
4079 }
4080 }
4081 }
4082
4083 Binder.restoreCallingIdentity(origId);
4084 }
4085 }
4086
4087 /**
4088 * Perform clean-up of service connections in an activity record.
4089 */
4090 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4091 // Throw away any services that have been bound by this activity.
4092 if (r.connections != null) {
4093 Iterator<ConnectionRecord> it = r.connections.iterator();
4094 while (it.hasNext()) {
4095 ConnectionRecord c = it.next();
4096 removeConnectionLocked(c, null, r);
4097 }
4098 r.connections = null;
4099 }
4100 }
4101
4102 /**
4103 * Perform the common clean-up of an activity record. This is called both
4104 * as part of destroyActivityLocked() (when destroying the client-side
4105 * representation) and cleaning things up as a result of its hosting
4106 * processing going away, in which case there is no remaining client-side
4107 * state to destroy so only the cleanup here is needed.
4108 */
4109 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4110 if (mResumedActivity == r) {
4111 mResumedActivity = null;
4112 }
4113 if (mFocusedActivity == r) {
4114 mFocusedActivity = null;
4115 }
4116
4117 r.configDestroy = false;
4118 r.frozenBeforeDestroy = false;
4119
4120 // Make sure this record is no longer in the pending finishes list.
4121 // This could happen, for example, if we are trimming activities
4122 // down to the max limit while they are still waiting to finish.
4123 mFinishingActivities.remove(r);
4124 mWaitingVisibleActivities.remove(r);
4125
4126 // Remove any pending results.
4127 if (r.finishing && r.pendingResults != null) {
4128 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4129 PendingIntentRecord rec = apr.get();
4130 if (rec != null) {
4131 cancelIntentSenderLocked(rec, false);
4132 }
4133 }
4134 r.pendingResults = null;
4135 }
4136
4137 if (cleanServices) {
4138 cleanUpActivityServicesLocked(r);
4139 }
4140
4141 if (mPendingThumbnails.size() > 0) {
4142 // There are clients waiting to receive thumbnails so, in case
4143 // this is an activity that someone is waiting for, add it
4144 // to the pending list so we can correctly update the clients.
4145 mCancelledThumbnails.add(r);
4146 }
4147
4148 // Get rid of any pending idle timeouts.
4149 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4150 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4151 }
4152
4153 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4154 if (r.state != ActivityState.DESTROYED) {
4155 mHistory.remove(r);
4156 r.inHistory = false;
4157 r.state = ActivityState.DESTROYED;
4158 mWindowManager.removeAppToken(r);
4159 if (VALIDATE_TOKENS) {
4160 mWindowManager.validateAppTokens(mHistory);
4161 }
4162 cleanUpActivityServicesLocked(r);
4163 removeActivityUriPermissionsLocked(r);
4164 }
4165 }
4166
4167 /**
4168 * Destroy the current CLIENT SIDE instance of an activity. This may be
4169 * called both when actually finishing an activity, or when performing
4170 * a configuration switch where we destroy the current client-side object
4171 * but then create a new client-side object for this same HistoryRecord.
4172 */
4173 private final boolean destroyActivityLocked(HistoryRecord r,
4174 boolean removeFromApp) {
4175 if (DEBUG_SWITCH) Log.v(
4176 TAG, "Removing activity: token=" + r
4177 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4178 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4179 System.identityHashCode(r),
4180 r.task.taskId, r.shortComponentName);
4181
4182 boolean removedFromHistory = false;
4183
4184 cleanUpActivityLocked(r, false);
4185
4186 if (r.app != null) {
4187 if (removeFromApp) {
4188 int idx = r.app.activities.indexOf(r);
4189 if (idx >= 0) {
4190 r.app.activities.remove(idx);
4191 }
4192 if (r.persistent) {
4193 decPersistentCountLocked(r.app);
4194 }
4195 }
4196
4197 boolean skipDestroy = false;
4198
4199 try {
4200 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4201 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4202 r.configChangeFlags);
4203 } catch (Exception e) {
4204 // We can just ignore exceptions here... if the process
4205 // has crashed, our death notification will clean things
4206 // up.
4207 //Log.w(TAG, "Exception thrown during finish", e);
4208 if (r.finishing) {
4209 removeActivityFromHistoryLocked(r);
4210 removedFromHistory = true;
4211 skipDestroy = true;
4212 }
4213 }
4214
4215 r.app = null;
4216 r.nowVisible = false;
4217
4218 if (r.finishing && !skipDestroy) {
4219 r.state = ActivityState.DESTROYING;
4220 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4221 msg.obj = r;
4222 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4223 } else {
4224 r.state = ActivityState.DESTROYED;
4225 }
4226 } else {
4227 // remove this record from the history.
4228 if (r.finishing) {
4229 removeActivityFromHistoryLocked(r);
4230 removedFromHistory = true;
4231 } else {
4232 r.state = ActivityState.DESTROYED;
4233 }
4234 }
4235
4236 r.configChangeFlags = 0;
4237
4238 if (!mLRUActivities.remove(r)) {
4239 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4240 }
4241
4242 return removedFromHistory;
4243 }
4244
4245 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4246 ProcessRecord app)
4247 {
4248 int i = list.size();
4249 if (localLOGV) Log.v(
4250 TAG, "Removing app " + app + " from list " + list
4251 + " with " + i + " entries");
4252 while (i > 0) {
4253 i--;
4254 HistoryRecord r = (HistoryRecord)list.get(i);
4255 if (localLOGV) Log.v(
4256 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4257 if (r.app == app) {
4258 if (localLOGV) Log.v(TAG, "Removing this entry!");
4259 list.remove(i);
4260 }
4261 }
4262 }
4263
4264 /**
4265 * Main function for removing an existing process from the activity manager
4266 * as a result of that process going away. Clears out all connections
4267 * to the process.
4268 */
4269 private final void handleAppDiedLocked(ProcessRecord app,
4270 boolean restarting) {
4271 cleanUpApplicationRecordLocked(app, restarting, -1);
4272 if (!restarting) {
4273 mLRUProcesses.remove(app);
4274 }
4275
4276 // Just in case...
4277 if (mPausingActivity != null && mPausingActivity.app == app) {
4278 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4279 mPausingActivity = null;
4280 }
4281 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4282 mLastPausedActivity = null;
4283 }
4284
4285 // Remove this application's activities from active lists.
4286 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4287 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4288 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4289 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4290
4291 boolean atTop = true;
4292 boolean hasVisibleActivities = false;
4293
4294 // Clean out the history list.
4295 int i = mHistory.size();
4296 if (localLOGV) Log.v(
4297 TAG, "Removing app " + app + " from history with " + i + " entries");
4298 while (i > 0) {
4299 i--;
4300 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4301 if (localLOGV) Log.v(
4302 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4303 if (r.app == app) {
4304 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4305 if (localLOGV) Log.v(
4306 TAG, "Removing this entry! frozen=" + r.haveState
4307 + " finishing=" + r.finishing);
4308 mHistory.remove(i);
4309
4310 r.inHistory = false;
4311 mWindowManager.removeAppToken(r);
4312 if (VALIDATE_TOKENS) {
4313 mWindowManager.validateAppTokens(mHistory);
4314 }
4315 removeActivityUriPermissionsLocked(r);
4316
4317 } else {
4318 // We have the current state for this activity, so
4319 // it can be restarted later when needed.
4320 if (localLOGV) Log.v(
4321 TAG, "Keeping entry, setting app to null");
4322 if (r.visible) {
4323 hasVisibleActivities = true;
4324 }
4325 r.app = null;
4326 r.nowVisible = false;
4327 if (!r.haveState) {
4328 r.icicle = null;
4329 }
4330 }
4331
4332 cleanUpActivityLocked(r, true);
4333 r.state = ActivityState.STOPPED;
4334 }
4335 atTop = false;
4336 }
4337
4338 app.activities.clear();
4339
4340 if (app.instrumentationClass != null) {
4341 Log.w(TAG, "Crash of app " + app.processName
4342 + " running instrumentation " + app.instrumentationClass);
4343 Bundle info = new Bundle();
4344 info.putString("shortMsg", "Process crashed.");
4345 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4346 }
4347
4348 if (!restarting) {
4349 if (!resumeTopActivityLocked(null)) {
4350 // If there was nothing to resume, and we are not already
4351 // restarting this process, but there is a visible activity that
4352 // is hosted by the process... then make sure all visible
4353 // activities are running, taking care of restarting this
4354 // process.
4355 if (hasVisibleActivities) {
4356 ensureActivitiesVisibleLocked(null, 0);
4357 }
4358 }
4359 }
4360 }
4361
4362 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4363 IBinder threadBinder = thread.asBinder();
4364
4365 // Find the application record.
4366 int count = mLRUProcesses.size();
4367 int i;
4368 for (i=0; i<count; i++) {
4369 ProcessRecord rec = mLRUProcesses.get(i);
4370 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4371 return i;
4372 }
4373 }
4374 return -1;
4375 }
4376
4377 private final ProcessRecord getRecordForAppLocked(
4378 IApplicationThread thread) {
4379 if (thread == null) {
4380 return null;
4381 }
4382
4383 int appIndex = getLRURecordIndexForAppLocked(thread);
4384 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4385 }
4386
4387 private final void appDiedLocked(ProcessRecord app, int pid,
4388 IApplicationThread thread) {
4389
4390 mProcDeaths[0]++;
4391
4392 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4393 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4394 + ") has died.");
4395 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4396 if (localLOGV) Log.v(
4397 TAG, "Dying app: " + app + ", pid: " + pid
4398 + ", thread: " + thread.asBinder());
4399 boolean doLowMem = app.instrumentationClass == null;
4400 handleAppDiedLocked(app, false);
4401
4402 if (doLowMem) {
4403 // If there are no longer any background processes running,
4404 // and the app that died was not running instrumentation,
4405 // then tell everyone we are now low on memory.
4406 boolean haveBg = false;
4407 int count = mLRUProcesses.size();
4408 int i;
4409 for (i=0; i<count; i++) {
4410 ProcessRecord rec = mLRUProcesses.get(i);
4411 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4412 haveBg = true;
4413 break;
4414 }
4415 }
4416
4417 if (!haveBg) {
4418 Log.i(TAG, "Low Memory: No more background processes.");
4419 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4420 for (i=0; i<count; i++) {
4421 ProcessRecord rec = mLRUProcesses.get(i);
4422 if (rec.thread != null) {
4423 rec.lastRequestedGc = SystemClock.uptimeMillis();
4424 try {
4425 rec.thread.scheduleLowMemory();
4426 } catch (RemoteException e) {
4427 // Don't care if the process is gone.
4428 }
4429 }
4430 }
4431 }
4432 }
4433 } else if (Config.LOGD) {
4434 Log.d(TAG, "Received spurious death notification for thread "
4435 + thread.asBinder());
4436 }
4437 }
4438
4439 final String readFile(String filename) {
4440 try {
4441 FileInputStream fs = new FileInputStream(filename);
4442 byte[] inp = new byte[8192];
4443 int size = fs.read(inp);
4444 fs.close();
4445 return new String(inp, 0, 0, size);
4446 } catch (java.io.IOException e) {
4447 }
4448 return "";
4449 }
4450
4451 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4452 final String annotation) {
4453 if (app.notResponding || app.crashing) {
4454 return;
4455 }
4456
4457 // Log the ANR to the event log.
4458 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4459
4460 // If we are on a secure build and the application is not interesting to the user (it is
4461 // not visible or in the background), just kill it instead of displaying a dialog.
4462 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4463 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4464 Process.killProcess(app.pid);
4465 return;
4466 }
4467
4468 // DeviceMonitor.start();
4469
4470 String processInfo = null;
4471 if (MONITOR_CPU_USAGE) {
4472 updateCpuStatsNow();
4473 synchronized (mProcessStatsThread) {
4474 processInfo = mProcessStats.printCurrentState();
4475 }
4476 }
4477
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004478 StringBuilder info = mStringBuilder;
4479 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 info.append("ANR (application not responding) in process: ");
4481 info.append(app.processName);
4482 if (annotation != null) {
4483 info.append("\nAnnotation: ");
4484 info.append(annotation);
4485 }
4486 if (MONITOR_CPU_USAGE) {
4487 info.append("\nCPU usage:\n");
4488 info.append(processInfo);
4489 }
4490 Log.i(TAG, info.toString());
4491
4492 // The application is not responding. Dump as many thread traces as we can.
4493 boolean fileDump = prepareTraceFile(true);
4494 if (!fileDump) {
4495 // Dumping traces to the log, just dump the process that isn't responding so
4496 // we don't overflow the log
4497 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4498 } else {
4499 // Dumping traces to a file so dump all active processes we know about
4500 synchronized (this) {
4501 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4502 ProcessRecord r = mLRUProcesses.get(i);
4503 if (r.thread != null) {
4504 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4505 }
4506 }
4507 }
4508 }
4509
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004510 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004511 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004512 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004513 app.pid, info.toString());
4514 if (res != 0) {
4515 if (res < 0) {
4516 // wait until the SIGQUIT has had a chance to process before killing the
4517 // process.
4518 try {
4519 wait(2000);
4520 } catch (InterruptedException e) {
4521 }
4522
4523 Process.killProcess(app.pid);
4524 return;
4525 }
4526 }
4527 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004528 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004529 }
4530 }
4531
4532 makeAppNotRespondingLocked(app,
4533 activity != null ? activity.shortComponentName : null,
4534 annotation != null ? "ANR " + annotation : "ANR",
4535 info.toString(), null);
4536 Message msg = Message.obtain();
4537 HashMap map = new HashMap();
4538 msg.what = SHOW_NOT_RESPONDING_MSG;
4539 msg.obj = map;
4540 map.put("app", app);
4541 if (activity != null) {
4542 map.put("activity", activity);
4543 }
4544
4545 mHandler.sendMessage(msg);
4546 return;
4547 }
4548
4549 /**
4550 * If a stack trace file has been configured, prepare the filesystem
4551 * by creating the directory if it doesn't exist and optionally
4552 * removing the old trace file.
4553 *
4554 * @param removeExisting If set, the existing trace file will be removed.
4555 * @return Returns true if the trace file preparations succeeded
4556 */
4557 public static boolean prepareTraceFile(boolean removeExisting) {
4558 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4559 boolean fileReady = false;
4560 if (!TextUtils.isEmpty(tracesPath)) {
4561 File f = new File(tracesPath);
4562 if (!f.exists()) {
4563 // Ensure the enclosing directory exists
4564 File dir = f.getParentFile();
4565 if (!dir.exists()) {
4566 fileReady = dir.mkdirs();
4567 FileUtils.setPermissions(dir.getAbsolutePath(),
4568 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4569 } else if (dir.isDirectory()) {
4570 fileReady = true;
4571 }
4572 } else if (removeExisting) {
4573 // Remove the previous traces file, so we don't fill the disk.
4574 // The VM will recreate it
4575 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4576 fileReady = f.delete();
4577 }
4578 }
4579
4580 return fileReady;
4581 }
4582
4583
4584 private final void decPersistentCountLocked(ProcessRecord app)
4585 {
4586 app.persistentActivities--;
4587 if (app.persistentActivities > 0) {
4588 // Still more of 'em...
4589 return;
4590 }
4591 if (app.persistent) {
4592 // Ah, but the application itself is persistent. Whatever!
4593 return;
4594 }
4595
4596 // App is no longer persistent... make sure it and the ones
4597 // following it in the LRU list have the correc oom_adj.
4598 updateOomAdjLocked();
4599 }
4600
4601 public void setPersistent(IBinder token, boolean isPersistent) {
4602 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4603 != PackageManager.PERMISSION_GRANTED) {
4604 String msg = "Permission Denial: setPersistent() from pid="
4605 + Binder.getCallingPid()
4606 + ", uid=" + Binder.getCallingUid()
4607 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4608 Log.w(TAG, msg);
4609 throw new SecurityException(msg);
4610 }
4611
4612 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004613 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614 if (index < 0) {
4615 return;
4616 }
4617 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4618 ProcessRecord app = r.app;
4619
4620 if (localLOGV) Log.v(
4621 TAG, "Setting persistence " + isPersistent + ": " + r);
4622
4623 if (isPersistent) {
4624 if (r.persistent) {
4625 // Okay okay, I heard you already!
4626 if (localLOGV) Log.v(TAG, "Already persistent!");
4627 return;
4628 }
4629 r.persistent = true;
4630 app.persistentActivities++;
4631 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4632 if (app.persistentActivities > 1) {
4633 // We aren't the first...
4634 if (localLOGV) Log.v(TAG, "Not the first!");
4635 return;
4636 }
4637 if (app.persistent) {
4638 // This would be redundant.
4639 if (localLOGV) Log.v(TAG, "App is persistent!");
4640 return;
4641 }
4642
4643 // App is now persistent... make sure it and the ones
4644 // following it now have the correct oom_adj.
4645 final long origId = Binder.clearCallingIdentity();
4646 updateOomAdjLocked();
4647 Binder.restoreCallingIdentity(origId);
4648
4649 } else {
4650 if (!r.persistent) {
4651 // Okay okay, I heard you already!
4652 return;
4653 }
4654 r.persistent = false;
4655 final long origId = Binder.clearCallingIdentity();
4656 decPersistentCountLocked(app);
4657 Binder.restoreCallingIdentity(origId);
4658
4659 }
4660 }
4661 }
4662
4663 public boolean clearApplicationUserData(final String packageName,
4664 final IPackageDataObserver observer) {
4665 int uid = Binder.getCallingUid();
4666 int pid = Binder.getCallingPid();
4667 long callingId = Binder.clearCallingIdentity();
4668 try {
4669 IPackageManager pm = ActivityThread.getPackageManager();
4670 int pkgUid = -1;
4671 synchronized(this) {
4672 try {
4673 pkgUid = pm.getPackageUid(packageName);
4674 } catch (RemoteException e) {
4675 }
4676 if (pkgUid == -1) {
4677 Log.w(TAG, "Invalid packageName:" + packageName);
4678 return false;
4679 }
4680 if (uid == pkgUid || checkComponentPermission(
4681 android.Manifest.permission.CLEAR_APP_USER_DATA,
4682 pid, uid, -1)
4683 == PackageManager.PERMISSION_GRANTED) {
4684 restartPackageLocked(packageName, pkgUid);
4685 } else {
4686 throw new SecurityException(pid+" does not have permission:"+
4687 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4688 "for process:"+packageName);
4689 }
4690 }
4691
4692 try {
4693 //clear application user data
4694 pm.clearApplicationUserData(packageName, observer);
4695 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4696 Uri.fromParts("package", packageName, null));
4697 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4698 broadcastIntentLocked(null, null, intent,
4699 null, null, 0, null, null, null,
4700 false, false, MY_PID, Process.SYSTEM_UID);
4701 } catch (RemoteException e) {
4702 }
4703 } finally {
4704 Binder.restoreCallingIdentity(callingId);
4705 }
4706 return true;
4707 }
4708
4709 public void restartPackage(final String packageName) {
4710 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4711 != PackageManager.PERMISSION_GRANTED) {
4712 String msg = "Permission Denial: restartPackage() from pid="
4713 + Binder.getCallingPid()
4714 + ", uid=" + Binder.getCallingUid()
4715 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4716 Log.w(TAG, msg);
4717 throw new SecurityException(msg);
4718 }
4719
4720 long callingId = Binder.clearCallingIdentity();
4721 try {
4722 IPackageManager pm = ActivityThread.getPackageManager();
4723 int pkgUid = -1;
4724 synchronized(this) {
4725 try {
4726 pkgUid = pm.getPackageUid(packageName);
4727 } catch (RemoteException e) {
4728 }
4729 if (pkgUid == -1) {
4730 Log.w(TAG, "Invalid packageName: " + packageName);
4731 return;
4732 }
4733 restartPackageLocked(packageName, pkgUid);
4734 }
4735 } finally {
4736 Binder.restoreCallingIdentity(callingId);
4737 }
4738 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004739
4740 /*
4741 * The pkg name and uid have to be specified.
4742 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4743 */
4744 public void killApplicationWithUid(String pkg, int uid) {
4745 if (pkg == null) {
4746 return;
4747 }
4748 // Make sure the uid is valid.
4749 if (uid < 0) {
4750 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4751 return;
4752 }
4753 int callerUid = Binder.getCallingUid();
4754 // Only the system server can kill an application
4755 if (callerUid == Process.SYSTEM_UID) {
4756 uninstallPackageLocked(pkg, uid, false);
4757 } else {
4758 throw new SecurityException(callerUid + " cannot kill pkg: " +
4759 pkg);
4760 }
4761 }
4762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004763 private void restartPackageLocked(final String packageName, int uid) {
4764 uninstallPackageLocked(packageName, uid, false);
4765 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4766 Uri.fromParts("package", packageName, null));
4767 intent.putExtra(Intent.EXTRA_UID, uid);
4768 broadcastIntentLocked(null, null, intent,
4769 null, null, 0, null, null, null,
4770 false, false, MY_PID, Process.SYSTEM_UID);
4771 }
4772
4773 private final void uninstallPackageLocked(String name, int uid,
4774 boolean callerWillRestart) {
4775 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4776
4777 int i, N;
4778
4779 final String procNamePrefix = name + ":";
4780 if (uid < 0) {
4781 try {
4782 uid = ActivityThread.getPackageManager().getPackageUid(name);
4783 } catch (RemoteException e) {
4784 }
4785 }
4786
4787 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4788 while (badApps.hasNext()) {
4789 SparseArray<Long> ba = badApps.next();
4790 if (ba.get(uid) != null) {
4791 badApps.remove();
4792 }
4793 }
4794
4795 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4796
4797 // Remove all processes this package may have touched: all with the
4798 // same UID (except for the system or root user), and all whose name
4799 // matches the package name.
4800 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4801 final int NA = apps.size();
4802 for (int ia=0; ia<NA; ia++) {
4803 ProcessRecord app = apps.valueAt(ia);
4804 if (app.removed) {
4805 procs.add(app);
4806 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4807 || app.processName.equals(name)
4808 || app.processName.startsWith(procNamePrefix)) {
4809 app.removed = true;
4810 procs.add(app);
4811 }
4812 }
4813 }
4814
4815 N = procs.size();
4816 for (i=0; i<N; i++) {
4817 removeProcessLocked(procs.get(i), callerWillRestart);
4818 }
4819
4820 for (i=mHistory.size()-1; i>=0; i--) {
4821 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4822 if (r.packageName.equals(name)) {
4823 if (Config.LOGD) Log.d(
4824 TAG, " Force finishing activity "
4825 + r.intent.getComponent().flattenToShortString());
4826 if (r.app != null) {
4827 r.app.removed = true;
4828 }
4829 r.app = null;
4830 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4831 }
4832 }
4833
4834 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4835 for (ServiceRecord service : mServices.values()) {
4836 if (service.packageName.equals(name)) {
4837 if (service.app != null) {
4838 service.app.removed = true;
4839 }
4840 service.app = null;
4841 services.add(service);
4842 }
4843 }
4844
4845 N = services.size();
4846 for (i=0; i<N; i++) {
4847 bringDownServiceLocked(services.get(i), true);
4848 }
4849
4850 resumeTopActivityLocked(null);
4851 }
4852
4853 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4854 final String name = app.processName;
4855 final int uid = app.info.uid;
4856 if (Config.LOGD) Log.d(
4857 TAG, "Force removing process " + app + " (" + name
4858 + "/" + uid + ")");
4859
4860 mProcessNames.remove(name, uid);
4861 boolean needRestart = false;
4862 if (app.pid > 0 && app.pid != MY_PID) {
4863 int pid = app.pid;
4864 synchronized (mPidsSelfLocked) {
4865 mPidsSelfLocked.remove(pid);
4866 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4867 }
4868 handleAppDiedLocked(app, true);
4869 mLRUProcesses.remove(app);
4870 Process.killProcess(pid);
4871
4872 if (app.persistent) {
4873 if (!callerWillRestart) {
4874 addAppLocked(app.info);
4875 } else {
4876 needRestart = true;
4877 }
4878 }
4879 } else {
4880 mRemovedProcesses.add(app);
4881 }
4882
4883 return needRestart;
4884 }
4885
4886 private final void processStartTimedOutLocked(ProcessRecord app) {
4887 final int pid = app.pid;
4888 boolean gone = false;
4889 synchronized (mPidsSelfLocked) {
4890 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4891 if (knownApp != null && knownApp.thread == null) {
4892 mPidsSelfLocked.remove(pid);
4893 gone = true;
4894 }
4895 }
4896
4897 if (gone) {
4898 Log.w(TAG, "Process " + app + " failed to attach");
4899 mProcessNames.remove(app.processName, app.info.uid);
4900 Process.killProcess(pid);
4901 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4902 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4903 mPendingBroadcast = null;
4904 scheduleBroadcastsLocked();
4905 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004906 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4907 Log.w(TAG, "Unattached app died before backup, skipping");
4908 try {
4909 IBackupManager bm = IBackupManager.Stub.asInterface(
4910 ServiceManager.getService(Context.BACKUP_SERVICE));
4911 bm.agentDisconnected(app.info.packageName);
4912 } catch (RemoteException e) {
4913 // Can't happen; the backup manager is local
4914 }
4915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004916 } else {
4917 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4918 }
4919 }
4920
4921 private final boolean attachApplicationLocked(IApplicationThread thread,
4922 int pid) {
4923
4924 // Find the application record that is being attached... either via
4925 // the pid if we are running in multiple processes, or just pull the
4926 // next app record if we are emulating process with anonymous threads.
4927 ProcessRecord app;
4928 if (pid != MY_PID && pid >= 0) {
4929 synchronized (mPidsSelfLocked) {
4930 app = mPidsSelfLocked.get(pid);
4931 }
4932 } else if (mStartingProcesses.size() > 0) {
4933 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004934 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004935 } else {
4936 app = null;
4937 }
4938
4939 if (app == null) {
4940 Log.w(TAG, "No pending application record for pid " + pid
4941 + " (IApplicationThread " + thread + "); dropping process");
4942 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4943 if (pid > 0 && pid != MY_PID) {
4944 Process.killProcess(pid);
4945 } else {
4946 try {
4947 thread.scheduleExit();
4948 } catch (Exception e) {
4949 // Ignore exceptions.
4950 }
4951 }
4952 return false;
4953 }
4954
4955 // If this application record is still attached to a previous
4956 // process, clean it up now.
4957 if (app.thread != null) {
4958 handleAppDiedLocked(app, true);
4959 }
4960
4961 // Tell the process all about itself.
4962
4963 if (localLOGV) Log.v(
4964 TAG, "Binding process pid " + pid + " to record " + app);
4965
4966 String processName = app.processName;
4967 try {
4968 thread.asBinder().linkToDeath(new AppDeathRecipient(
4969 app, pid, thread), 0);
4970 } catch (RemoteException e) {
4971 app.resetPackageList();
4972 startProcessLocked(app, "link fail", processName);
4973 return false;
4974 }
4975
4976 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4977
4978 app.thread = thread;
4979 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004980 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004981 app.forcingToForeground = null;
4982 app.foregroundServices = false;
4983 app.debugging = false;
4984
4985 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4986
4987 List providers = generateApplicationProvidersLocked(app);
4988
4989 if (localLOGV) Log.v(
4990 TAG, "New app record " + app
4991 + " thread=" + thread.asBinder() + " pid=" + pid);
4992 try {
4993 int testMode = IApplicationThread.DEBUG_OFF;
4994 if (mDebugApp != null && mDebugApp.equals(processName)) {
4995 testMode = mWaitForDebugger
4996 ? IApplicationThread.DEBUG_WAIT
4997 : IApplicationThread.DEBUG_ON;
4998 app.debugging = true;
4999 if (mDebugTransient) {
5000 mDebugApp = mOrigDebugApp;
5001 mWaitForDebugger = mOrigWaitForDebugger;
5002 }
5003 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005004 // If the app is being launched for restore or full backup, set it up specially
5005 boolean isRestrictedBackupMode = false;
5006 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5007 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5008 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5009 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005010 ensurePackageDexOpt(app.instrumentationInfo != null
5011 ? app.instrumentationInfo.packageName
5012 : app.info.packageName);
5013 if (app.instrumentationClass != null) {
5014 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005015 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005016 thread.bindApplication(processName, app.instrumentationInfo != null
5017 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005018 app.instrumentationClass, app.instrumentationProfileFile,
5019 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005020 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005021 updateLRUListLocked(app, false);
5022 app.lastRequestedGc = SystemClock.uptimeMillis();
5023 } catch (Exception e) {
5024 // todo: Yikes! What should we do? For now we will try to
5025 // start another process, but that could easily get us in
5026 // an infinite loop of restarting processes...
5027 Log.w(TAG, "Exception thrown during bind!", e);
5028
5029 app.resetPackageList();
5030 startProcessLocked(app, "bind fail", processName);
5031 return false;
5032 }
5033
5034 // Remove this record from the list of starting applications.
5035 mPersistentStartingProcesses.remove(app);
5036 mProcessesOnHold.remove(app);
5037
5038 boolean badApp = false;
5039 boolean didSomething = false;
5040
5041 // See if the top visible activity is waiting to run in this process...
5042 HistoryRecord hr = topRunningActivityLocked(null);
5043 if (hr != null) {
5044 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5045 && processName.equals(hr.processName)) {
5046 try {
5047 if (realStartActivityLocked(hr, app, true, true)) {
5048 didSomething = true;
5049 }
5050 } catch (Exception e) {
5051 Log.w(TAG, "Exception in new application when starting activity "
5052 + hr.intent.getComponent().flattenToShortString(), e);
5053 badApp = true;
5054 }
5055 } else {
5056 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5057 }
5058 }
5059
5060 // Find any services that should be running in this process...
5061 if (!badApp && mPendingServices.size() > 0) {
5062 ServiceRecord sr = null;
5063 try {
5064 for (int i=0; i<mPendingServices.size(); i++) {
5065 sr = mPendingServices.get(i);
5066 if (app.info.uid != sr.appInfo.uid
5067 || !processName.equals(sr.processName)) {
5068 continue;
5069 }
5070
5071 mPendingServices.remove(i);
5072 i--;
5073 realStartServiceLocked(sr, app);
5074 didSomething = true;
5075 }
5076 } catch (Exception e) {
5077 Log.w(TAG, "Exception in new application when starting service "
5078 + sr.shortName, e);
5079 badApp = true;
5080 }
5081 }
5082
5083 // Check if the next broadcast receiver is in this process...
5084 BroadcastRecord br = mPendingBroadcast;
5085 if (!badApp && br != null && br.curApp == app) {
5086 try {
5087 mPendingBroadcast = null;
5088 processCurBroadcastLocked(br, app);
5089 didSomething = true;
5090 } catch (Exception e) {
5091 Log.w(TAG, "Exception in new application when starting receiver "
5092 + br.curComponent.flattenToShortString(), e);
5093 badApp = true;
5094 logBroadcastReceiverDiscard(br);
5095 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5096 br.resultExtras, br.resultAbort, true);
5097 scheduleBroadcastsLocked();
5098 }
5099 }
5100
Christopher Tate181fafa2009-05-14 11:12:14 -07005101 // Check whether the next backup agent is in this process...
5102 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5103 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005104 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005105 try {
5106 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5107 } catch (Exception e) {
5108 Log.w(TAG, "Exception scheduling backup agent creation: ");
5109 e.printStackTrace();
5110 }
5111 }
5112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005113 if (badApp) {
5114 // todo: Also need to kill application to deal with all
5115 // kinds of exceptions.
5116 handleAppDiedLocked(app, false);
5117 return false;
5118 }
5119
5120 if (!didSomething) {
5121 updateOomAdjLocked();
5122 }
5123
5124 return true;
5125 }
5126
5127 public final void attachApplication(IApplicationThread thread) {
5128 synchronized (this) {
5129 int callingPid = Binder.getCallingPid();
5130 final long origId = Binder.clearCallingIdentity();
5131 attachApplicationLocked(thread, callingPid);
5132 Binder.restoreCallingIdentity(origId);
5133 }
5134 }
5135
5136 public final void activityIdle(IBinder token) {
5137 final long origId = Binder.clearCallingIdentity();
5138 activityIdleInternal(token, false);
5139 Binder.restoreCallingIdentity(origId);
5140 }
5141
5142 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5143 boolean remove) {
5144 int N = mStoppingActivities.size();
5145 if (N <= 0) return null;
5146
5147 ArrayList<HistoryRecord> stops = null;
5148
5149 final boolean nowVisible = mResumedActivity != null
5150 && mResumedActivity.nowVisible
5151 && !mResumedActivity.waitingVisible;
5152 for (int i=0; i<N; i++) {
5153 HistoryRecord s = mStoppingActivities.get(i);
5154 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5155 + nowVisible + " waitingVisible=" + s.waitingVisible
5156 + " finishing=" + s.finishing);
5157 if (s.waitingVisible && nowVisible) {
5158 mWaitingVisibleActivities.remove(s);
5159 s.waitingVisible = false;
5160 if (s.finishing) {
5161 // If this activity is finishing, it is sitting on top of
5162 // everyone else but we now know it is no longer needed...
5163 // so get rid of it. Otherwise, we need to go through the
5164 // normal flow and hide it once we determine that it is
5165 // hidden by the activities in front of it.
5166 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5167 mWindowManager.setAppVisibility(s, false);
5168 }
5169 }
5170 if (!s.waitingVisible && remove) {
5171 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5172 if (stops == null) {
5173 stops = new ArrayList<HistoryRecord>();
5174 }
5175 stops.add(s);
5176 mStoppingActivities.remove(i);
5177 N--;
5178 i--;
5179 }
5180 }
5181
5182 return stops;
5183 }
5184
5185 void enableScreenAfterBoot() {
5186 mWindowManager.enableScreenAfterBoot();
5187 }
5188
5189 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5190 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5191
5192 ArrayList<HistoryRecord> stops = null;
5193 ArrayList<HistoryRecord> finishes = null;
5194 ArrayList<HistoryRecord> thumbnails = null;
5195 int NS = 0;
5196 int NF = 0;
5197 int NT = 0;
5198 IApplicationThread sendThumbnail = null;
5199 boolean booting = false;
5200 boolean enableScreen = false;
5201
5202 synchronized (this) {
5203 if (token != null) {
5204 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5205 }
5206
5207 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005208 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 if (index >= 0) {
5210 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5211
5212 // No longer need to keep the device awake.
5213 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5214 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5215 mLaunchingActivity.release();
5216 }
5217
5218 // We are now idle. If someone is waiting for a thumbnail from
5219 // us, we can now deliver.
5220 r.idle = true;
5221 scheduleAppGcsLocked();
5222 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5223 sendThumbnail = r.app.thread;
5224 r.thumbnailNeeded = false;
5225 }
5226
5227 // If this activity is fullscreen, set up to hide those under it.
5228
5229 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5230 ensureActivitiesVisibleLocked(null, 0);
5231
5232 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5233 if (!mBooted && !fromTimeout) {
5234 mBooted = true;
5235 enableScreen = true;
5236 }
5237 }
5238
5239 // Atomically retrieve all of the other things to do.
5240 stops = processStoppingActivitiesLocked(true);
5241 NS = stops != null ? stops.size() : 0;
5242 if ((NF=mFinishingActivities.size()) > 0) {
5243 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5244 mFinishingActivities.clear();
5245 }
5246 if ((NT=mCancelledThumbnails.size()) > 0) {
5247 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5248 mCancelledThumbnails.clear();
5249 }
5250
5251 booting = mBooting;
5252 mBooting = false;
5253 }
5254
5255 int i;
5256
5257 // Send thumbnail if requested.
5258 if (sendThumbnail != null) {
5259 try {
5260 sendThumbnail.requestThumbnail(token);
5261 } catch (Exception e) {
5262 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5263 sendPendingThumbnail(null, token, null, null, true);
5264 }
5265 }
5266
5267 // Stop any activities that are scheduled to do so but have been
5268 // waiting for the next one to start.
5269 for (i=0; i<NS; i++) {
5270 HistoryRecord r = (HistoryRecord)stops.get(i);
5271 synchronized (this) {
5272 if (r.finishing) {
5273 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5274 } else {
5275 stopActivityLocked(r);
5276 }
5277 }
5278 }
5279
5280 // Finish any activities that are scheduled to do so but have been
5281 // waiting for the next one to start.
5282 for (i=0; i<NF; i++) {
5283 HistoryRecord r = (HistoryRecord)finishes.get(i);
5284 synchronized (this) {
5285 destroyActivityLocked(r, true);
5286 }
5287 }
5288
5289 // Report back to any thumbnail receivers.
5290 for (i=0; i<NT; i++) {
5291 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5292 sendPendingThumbnail(r, null, null, null, true);
5293 }
5294
5295 if (booting) {
5296 // Ensure that any processes we had put on hold are now started
5297 // up.
5298 final int NP = mProcessesOnHold.size();
5299 if (NP > 0) {
5300 ArrayList<ProcessRecord> procs =
5301 new ArrayList<ProcessRecord>(mProcessesOnHold);
5302 for (int ip=0; ip<NP; ip++) {
5303 this.startProcessLocked(procs.get(ip), "on-hold", null);
5304 }
5305 }
5306 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5307 // Tell anyone interested that we are done booting!
5308 synchronized (this) {
5309 broadcastIntentLocked(null, null,
5310 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5311 null, null, 0, null, null,
5312 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5313 false, false, MY_PID, Process.SYSTEM_UID);
5314 }
5315 }
5316 }
5317
5318 trimApplications();
5319 //dump();
5320 //mWindowManager.dump();
5321
5322 if (enableScreen) {
5323 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5324 SystemClock.uptimeMillis());
5325 enableScreenAfterBoot();
5326 }
5327 }
5328
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005329 final void ensureScreenEnabled() {
5330 boolean enableScreen;
5331 synchronized (this) {
5332 enableScreen = !mBooted;
5333 mBooted = true;
5334 }
5335
5336 if (enableScreen) {
5337 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5338 SystemClock.uptimeMillis());
5339 enableScreenAfterBoot();
5340 }
5341 }
5342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005343 public final void activityPaused(IBinder token, Bundle icicle) {
5344 // Refuse possible leaked file descriptors
5345 if (icicle != null && icicle.hasFileDescriptors()) {
5346 throw new IllegalArgumentException("File descriptors passed in Bundle");
5347 }
5348
5349 final long origId = Binder.clearCallingIdentity();
5350 activityPaused(token, icicle, false);
5351 Binder.restoreCallingIdentity(origId);
5352 }
5353
5354 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5355 if (DEBUG_PAUSE) Log.v(
5356 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5357 + ", timeout=" + timeout);
5358
5359 HistoryRecord r = null;
5360
5361 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005362 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005363 if (index >= 0) {
5364 r = (HistoryRecord)mHistory.get(index);
5365 if (!timeout) {
5366 r.icicle = icicle;
5367 r.haveState = true;
5368 }
5369 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5370 if (mPausingActivity == r) {
5371 r.state = ActivityState.PAUSED;
5372 completePauseLocked();
5373 } else {
5374 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5375 System.identityHashCode(r), r.shortComponentName,
5376 mPausingActivity != null
5377 ? mPausingActivity.shortComponentName : "(none)");
5378 }
5379 }
5380 }
5381 }
5382
5383 public final void activityStopped(IBinder token, Bitmap thumbnail,
5384 CharSequence description) {
5385 if (localLOGV) Log.v(
5386 TAG, "Activity stopped: token=" + token);
5387
5388 HistoryRecord r = null;
5389
5390 final long origId = Binder.clearCallingIdentity();
5391
5392 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005393 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 if (index >= 0) {
5395 r = (HistoryRecord)mHistory.get(index);
5396 r.thumbnail = thumbnail;
5397 r.description = description;
5398 r.stopped = true;
5399 r.state = ActivityState.STOPPED;
5400 if (!r.finishing) {
5401 if (r.configDestroy) {
5402 destroyActivityLocked(r, true);
5403 resumeTopActivityLocked(null);
5404 }
5405 }
5406 }
5407 }
5408
5409 if (r != null) {
5410 sendPendingThumbnail(r, null, null, null, false);
5411 }
5412
5413 trimApplications();
5414
5415 Binder.restoreCallingIdentity(origId);
5416 }
5417
5418 public final void activityDestroyed(IBinder token) {
5419 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5420 synchronized (this) {
5421 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5422
Dianne Hackborn75b03852009-06-12 15:43:26 -07005423 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005424 if (index >= 0) {
5425 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5426 if (r.state == ActivityState.DESTROYING) {
5427 final long origId = Binder.clearCallingIdentity();
5428 removeActivityFromHistoryLocked(r);
5429 Binder.restoreCallingIdentity(origId);
5430 }
5431 }
5432 }
5433 }
5434
5435 public String getCallingPackage(IBinder token) {
5436 synchronized (this) {
5437 HistoryRecord r = getCallingRecordLocked(token);
5438 return r != null && r.app != null ? r.app.processName : null;
5439 }
5440 }
5441
5442 public ComponentName getCallingActivity(IBinder token) {
5443 synchronized (this) {
5444 HistoryRecord r = getCallingRecordLocked(token);
5445 return r != null ? r.intent.getComponent() : null;
5446 }
5447 }
5448
5449 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005450 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005451 if (index >= 0) {
5452 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5453 if (r != null) {
5454 return r.resultTo;
5455 }
5456 }
5457 return null;
5458 }
5459
5460 public ComponentName getActivityClassForToken(IBinder token) {
5461 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005462 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005463 if (index >= 0) {
5464 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5465 return r.intent.getComponent();
5466 }
5467 return null;
5468 }
5469 }
5470
5471 public String getPackageForToken(IBinder token) {
5472 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005473 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474 if (index >= 0) {
5475 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5476 return r.packageName;
5477 }
5478 return null;
5479 }
5480 }
5481
5482 public IIntentSender getIntentSender(int type,
5483 String packageName, IBinder token, String resultWho,
5484 int requestCode, Intent intent, String resolvedType, int flags) {
5485 // Refuse possible leaked file descriptors
5486 if (intent != null && intent.hasFileDescriptors() == true) {
5487 throw new IllegalArgumentException("File descriptors passed in Intent");
5488 }
5489
5490 synchronized(this) {
5491 int callingUid = Binder.getCallingUid();
5492 try {
5493 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5494 Process.supportsProcesses()) {
5495 int uid = ActivityThread.getPackageManager()
5496 .getPackageUid(packageName);
5497 if (uid != Binder.getCallingUid()) {
5498 String msg = "Permission Denial: getIntentSender() from pid="
5499 + Binder.getCallingPid()
5500 + ", uid=" + Binder.getCallingUid()
5501 + ", (need uid=" + uid + ")"
5502 + " is not allowed to send as package " + packageName;
5503 Log.w(TAG, msg);
5504 throw new SecurityException(msg);
5505 }
5506 }
5507 } catch (RemoteException e) {
5508 throw new SecurityException(e);
5509 }
5510 HistoryRecord activity = null;
5511 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005512 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005513 if (index < 0) {
5514 return null;
5515 }
5516 activity = (HistoryRecord)mHistory.get(index);
5517 if (activity.finishing) {
5518 return null;
5519 }
5520 }
5521
5522 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5523 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5524 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5525 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5526 |PendingIntent.FLAG_UPDATE_CURRENT);
5527
5528 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5529 type, packageName, activity, resultWho,
5530 requestCode, intent, resolvedType, flags);
5531 WeakReference<PendingIntentRecord> ref;
5532 ref = mIntentSenderRecords.get(key);
5533 PendingIntentRecord rec = ref != null ? ref.get() : null;
5534 if (rec != null) {
5535 if (!cancelCurrent) {
5536 if (updateCurrent) {
5537 rec.key.requestIntent.replaceExtras(intent);
5538 }
5539 return rec;
5540 }
5541 rec.canceled = true;
5542 mIntentSenderRecords.remove(key);
5543 }
5544 if (noCreate) {
5545 return rec;
5546 }
5547 rec = new PendingIntentRecord(this, key, callingUid);
5548 mIntentSenderRecords.put(key, rec.ref);
5549 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5550 if (activity.pendingResults == null) {
5551 activity.pendingResults
5552 = new HashSet<WeakReference<PendingIntentRecord>>();
5553 }
5554 activity.pendingResults.add(rec.ref);
5555 }
5556 return rec;
5557 }
5558 }
5559
5560 public void cancelIntentSender(IIntentSender sender) {
5561 if (!(sender instanceof PendingIntentRecord)) {
5562 return;
5563 }
5564 synchronized(this) {
5565 PendingIntentRecord rec = (PendingIntentRecord)sender;
5566 try {
5567 int uid = ActivityThread.getPackageManager()
5568 .getPackageUid(rec.key.packageName);
5569 if (uid != Binder.getCallingUid()) {
5570 String msg = "Permission Denial: cancelIntentSender() from pid="
5571 + Binder.getCallingPid()
5572 + ", uid=" + Binder.getCallingUid()
5573 + " is not allowed to cancel packges "
5574 + rec.key.packageName;
5575 Log.w(TAG, msg);
5576 throw new SecurityException(msg);
5577 }
5578 } catch (RemoteException e) {
5579 throw new SecurityException(e);
5580 }
5581 cancelIntentSenderLocked(rec, true);
5582 }
5583 }
5584
5585 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5586 rec.canceled = true;
5587 mIntentSenderRecords.remove(rec.key);
5588 if (cleanActivity && rec.key.activity != null) {
5589 rec.key.activity.pendingResults.remove(rec.ref);
5590 }
5591 }
5592
5593 public String getPackageForIntentSender(IIntentSender pendingResult) {
5594 if (!(pendingResult instanceof PendingIntentRecord)) {
5595 return null;
5596 }
5597 synchronized(this) {
5598 try {
5599 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5600 return res.key.packageName;
5601 } catch (ClassCastException e) {
5602 }
5603 }
5604 return null;
5605 }
5606
5607 public void setProcessLimit(int max) {
5608 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5609 "setProcessLimit()");
5610 mProcessLimit = max;
5611 }
5612
5613 public int getProcessLimit() {
5614 return mProcessLimit;
5615 }
5616
5617 void foregroundTokenDied(ForegroundToken token) {
5618 synchronized (ActivityManagerService.this) {
5619 synchronized (mPidsSelfLocked) {
5620 ForegroundToken cur
5621 = mForegroundProcesses.get(token.pid);
5622 if (cur != token) {
5623 return;
5624 }
5625 mForegroundProcesses.remove(token.pid);
5626 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5627 if (pr == null) {
5628 return;
5629 }
5630 pr.forcingToForeground = null;
5631 pr.foregroundServices = false;
5632 }
5633 updateOomAdjLocked();
5634 }
5635 }
5636
5637 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5638 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5639 "setProcessForeground()");
5640 synchronized(this) {
5641 boolean changed = false;
5642
5643 synchronized (mPidsSelfLocked) {
5644 ProcessRecord pr = mPidsSelfLocked.get(pid);
5645 if (pr == null) {
5646 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5647 return;
5648 }
5649 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5650 if (oldToken != null) {
5651 oldToken.token.unlinkToDeath(oldToken, 0);
5652 mForegroundProcesses.remove(pid);
5653 pr.forcingToForeground = null;
5654 changed = true;
5655 }
5656 if (isForeground && token != null) {
5657 ForegroundToken newToken = new ForegroundToken() {
5658 public void binderDied() {
5659 foregroundTokenDied(this);
5660 }
5661 };
5662 newToken.pid = pid;
5663 newToken.token = token;
5664 try {
5665 token.linkToDeath(newToken, 0);
5666 mForegroundProcesses.put(pid, newToken);
5667 pr.forcingToForeground = token;
5668 changed = true;
5669 } catch (RemoteException e) {
5670 // If the process died while doing this, we will later
5671 // do the cleanup with the process death link.
5672 }
5673 }
5674 }
5675
5676 if (changed) {
5677 updateOomAdjLocked();
5678 }
5679 }
5680 }
5681
5682 // =========================================================
5683 // PERMISSIONS
5684 // =========================================================
5685
5686 static class PermissionController extends IPermissionController.Stub {
5687 ActivityManagerService mActivityManagerService;
5688 PermissionController(ActivityManagerService activityManagerService) {
5689 mActivityManagerService = activityManagerService;
5690 }
5691
5692 public boolean checkPermission(String permission, int pid, int uid) {
5693 return mActivityManagerService.checkPermission(permission, pid,
5694 uid) == PackageManager.PERMISSION_GRANTED;
5695 }
5696 }
5697
5698 /**
5699 * This can be called with or without the global lock held.
5700 */
5701 int checkComponentPermission(String permission, int pid, int uid,
5702 int reqUid) {
5703 // We might be performing an operation on behalf of an indirect binder
5704 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5705 // client identity accordingly before proceeding.
5706 Identity tlsIdentity = sCallerIdentity.get();
5707 if (tlsIdentity != null) {
5708 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5709 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5710 uid = tlsIdentity.uid;
5711 pid = tlsIdentity.pid;
5712 }
5713
5714 // Root, system server and our own process get to do everything.
5715 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5716 !Process.supportsProcesses()) {
5717 return PackageManager.PERMISSION_GRANTED;
5718 }
5719 // If the target requires a specific UID, always fail for others.
5720 if (reqUid >= 0 && uid != reqUid) {
5721 return PackageManager.PERMISSION_DENIED;
5722 }
5723 if (permission == null) {
5724 return PackageManager.PERMISSION_GRANTED;
5725 }
5726 try {
5727 return ActivityThread.getPackageManager()
5728 .checkUidPermission(permission, uid);
5729 } catch (RemoteException e) {
5730 // Should never happen, but if it does... deny!
5731 Log.e(TAG, "PackageManager is dead?!?", e);
5732 }
5733 return PackageManager.PERMISSION_DENIED;
5734 }
5735
5736 /**
5737 * As the only public entry point for permissions checking, this method
5738 * can enforce the semantic that requesting a check on a null global
5739 * permission is automatically denied. (Internally a null permission
5740 * string is used when calling {@link #checkComponentPermission} in cases
5741 * when only uid-based security is needed.)
5742 *
5743 * This can be called with or without the global lock held.
5744 */
5745 public int checkPermission(String permission, int pid, int uid) {
5746 if (permission == null) {
5747 return PackageManager.PERMISSION_DENIED;
5748 }
5749 return checkComponentPermission(permission, pid, uid, -1);
5750 }
5751
5752 /**
5753 * Binder IPC calls go through the public entry point.
5754 * This can be called with or without the global lock held.
5755 */
5756 int checkCallingPermission(String permission) {
5757 return checkPermission(permission,
5758 Binder.getCallingPid(),
5759 Binder.getCallingUid());
5760 }
5761
5762 /**
5763 * This can be called with or without the global lock held.
5764 */
5765 void enforceCallingPermission(String permission, String func) {
5766 if (checkCallingPermission(permission)
5767 == PackageManager.PERMISSION_GRANTED) {
5768 return;
5769 }
5770
5771 String msg = "Permission Denial: " + func + " from pid="
5772 + Binder.getCallingPid()
5773 + ", uid=" + Binder.getCallingUid()
5774 + " requires " + permission;
5775 Log.w(TAG, msg);
5776 throw new SecurityException(msg);
5777 }
5778
5779 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5780 ProviderInfo pi, int uid, int modeFlags) {
5781 try {
5782 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5783 if ((pi.readPermission != null) &&
5784 (pm.checkUidPermission(pi.readPermission, uid)
5785 != PackageManager.PERMISSION_GRANTED)) {
5786 return false;
5787 }
5788 }
5789 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5790 if ((pi.writePermission != null) &&
5791 (pm.checkUidPermission(pi.writePermission, uid)
5792 != PackageManager.PERMISSION_GRANTED)) {
5793 return false;
5794 }
5795 }
5796 return true;
5797 } catch (RemoteException e) {
5798 return false;
5799 }
5800 }
5801
5802 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5803 int modeFlags) {
5804 // Root gets to do everything.
5805 if (uid == 0 || !Process.supportsProcesses()) {
5806 return true;
5807 }
5808 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5809 if (perms == null) return false;
5810 UriPermission perm = perms.get(uri);
5811 if (perm == null) return false;
5812 return (modeFlags&perm.modeFlags) == modeFlags;
5813 }
5814
5815 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5816 // Another redirected-binder-call permissions check as in
5817 // {@link checkComponentPermission}.
5818 Identity tlsIdentity = sCallerIdentity.get();
5819 if (tlsIdentity != null) {
5820 uid = tlsIdentity.uid;
5821 pid = tlsIdentity.pid;
5822 }
5823
5824 // Our own process gets to do everything.
5825 if (pid == MY_PID) {
5826 return PackageManager.PERMISSION_GRANTED;
5827 }
5828 synchronized(this) {
5829 return checkUriPermissionLocked(uri, uid, modeFlags)
5830 ? PackageManager.PERMISSION_GRANTED
5831 : PackageManager.PERMISSION_DENIED;
5832 }
5833 }
5834
5835 private void grantUriPermissionLocked(int callingUid,
5836 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5837 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5838 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5839 if (modeFlags == 0) {
5840 return;
5841 }
5842
5843 final IPackageManager pm = ActivityThread.getPackageManager();
5844
5845 // If this is not a content: uri, we can't do anything with it.
5846 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5847 return;
5848 }
5849
5850 String name = uri.getAuthority();
5851 ProviderInfo pi = null;
5852 ContentProviderRecord cpr
5853 = (ContentProviderRecord)mProvidersByName.get(name);
5854 if (cpr != null) {
5855 pi = cpr.info;
5856 } else {
5857 try {
5858 pi = pm.resolveContentProvider(name,
5859 PackageManager.GET_URI_PERMISSION_PATTERNS);
5860 } catch (RemoteException ex) {
5861 }
5862 }
5863 if (pi == null) {
5864 Log.w(TAG, "No content provider found for: " + name);
5865 return;
5866 }
5867
5868 int targetUid;
5869 try {
5870 targetUid = pm.getPackageUid(targetPkg);
5871 if (targetUid < 0) {
5872 return;
5873 }
5874 } catch (RemoteException ex) {
5875 return;
5876 }
5877
5878 // First... does the target actually need this permission?
5879 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5880 // No need to grant the target this permission.
5881 return;
5882 }
5883
5884 // Second... maybe someone else has already granted the
5885 // permission?
5886 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5887 // No need to grant the target this permission.
5888 return;
5889 }
5890
5891 // Third... is the provider allowing granting of URI permissions?
5892 if (!pi.grantUriPermissions) {
5893 throw new SecurityException("Provider " + pi.packageName
5894 + "/" + pi.name
5895 + " does not allow granting of Uri permissions (uri "
5896 + uri + ")");
5897 }
5898 if (pi.uriPermissionPatterns != null) {
5899 final int N = pi.uriPermissionPatterns.length;
5900 boolean allowed = false;
5901 for (int i=0; i<N; i++) {
5902 if (pi.uriPermissionPatterns[i] != null
5903 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5904 allowed = true;
5905 break;
5906 }
5907 }
5908 if (!allowed) {
5909 throw new SecurityException("Provider " + pi.packageName
5910 + "/" + pi.name
5911 + " does not allow granting of permission to path of Uri "
5912 + uri);
5913 }
5914 }
5915
5916 // Fourth... does the caller itself have permission to access
5917 // this uri?
5918 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5919 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5920 throw new SecurityException("Uid " + callingUid
5921 + " does not have permission to uri " + uri);
5922 }
5923 }
5924
5925 // Okay! So here we are: the caller has the assumed permission
5926 // to the uri, and the target doesn't. Let's now give this to
5927 // the target.
5928
5929 HashMap<Uri, UriPermission> targetUris
5930 = mGrantedUriPermissions.get(targetUid);
5931 if (targetUris == null) {
5932 targetUris = new HashMap<Uri, UriPermission>();
5933 mGrantedUriPermissions.put(targetUid, targetUris);
5934 }
5935
5936 UriPermission perm = targetUris.get(uri);
5937 if (perm == null) {
5938 perm = new UriPermission(targetUid, uri);
5939 targetUris.put(uri, perm);
5940
5941 }
5942 perm.modeFlags |= modeFlags;
5943 if (activity == null) {
5944 perm.globalModeFlags |= modeFlags;
5945 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5946 perm.readActivities.add(activity);
5947 if (activity.readUriPermissions == null) {
5948 activity.readUriPermissions = new HashSet<UriPermission>();
5949 }
5950 activity.readUriPermissions.add(perm);
5951 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5952 perm.writeActivities.add(activity);
5953 if (activity.writeUriPermissions == null) {
5954 activity.writeUriPermissions = new HashSet<UriPermission>();
5955 }
5956 activity.writeUriPermissions.add(perm);
5957 }
5958 }
5959
5960 private void grantUriPermissionFromIntentLocked(int callingUid,
5961 String targetPkg, Intent intent, HistoryRecord activity) {
5962 if (intent == null) {
5963 return;
5964 }
5965 Uri data = intent.getData();
5966 if (data == null) {
5967 return;
5968 }
5969 grantUriPermissionLocked(callingUid, targetPkg, data,
5970 intent.getFlags(), activity);
5971 }
5972
5973 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5974 Uri uri, int modeFlags) {
5975 synchronized(this) {
5976 final ProcessRecord r = getRecordForAppLocked(caller);
5977 if (r == null) {
5978 throw new SecurityException("Unable to find app for caller "
5979 + caller
5980 + " when granting permission to uri " + uri);
5981 }
5982 if (targetPkg == null) {
5983 Log.w(TAG, "grantUriPermission: null target");
5984 return;
5985 }
5986 if (uri == null) {
5987 Log.w(TAG, "grantUriPermission: null uri");
5988 return;
5989 }
5990
5991 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5992 null);
5993 }
5994 }
5995
5996 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5997 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5998 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5999 HashMap<Uri, UriPermission> perms
6000 = mGrantedUriPermissions.get(perm.uid);
6001 if (perms != null) {
6002 perms.remove(perm.uri);
6003 if (perms.size() == 0) {
6004 mGrantedUriPermissions.remove(perm.uid);
6005 }
6006 }
6007 }
6008 }
6009
6010 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6011 if (activity.readUriPermissions != null) {
6012 for (UriPermission perm : activity.readUriPermissions) {
6013 perm.readActivities.remove(activity);
6014 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6015 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6016 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6017 removeUriPermissionIfNeededLocked(perm);
6018 }
6019 }
6020 }
6021 if (activity.writeUriPermissions != null) {
6022 for (UriPermission perm : activity.writeUriPermissions) {
6023 perm.writeActivities.remove(activity);
6024 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6025 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6026 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6027 removeUriPermissionIfNeededLocked(perm);
6028 }
6029 }
6030 }
6031 }
6032
6033 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6034 int modeFlags) {
6035 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6036 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6037 if (modeFlags == 0) {
6038 return;
6039 }
6040
6041 final IPackageManager pm = ActivityThread.getPackageManager();
6042
6043 final String authority = uri.getAuthority();
6044 ProviderInfo pi = null;
6045 ContentProviderRecord cpr
6046 = (ContentProviderRecord)mProvidersByName.get(authority);
6047 if (cpr != null) {
6048 pi = cpr.info;
6049 } else {
6050 try {
6051 pi = pm.resolveContentProvider(authority,
6052 PackageManager.GET_URI_PERMISSION_PATTERNS);
6053 } catch (RemoteException ex) {
6054 }
6055 }
6056 if (pi == null) {
6057 Log.w(TAG, "No content provider found for: " + authority);
6058 return;
6059 }
6060
6061 // Does the caller have this permission on the URI?
6062 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6063 // Right now, if you are not the original owner of the permission,
6064 // you are not allowed to revoke it.
6065 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6066 throw new SecurityException("Uid " + callingUid
6067 + " does not have permission to uri " + uri);
6068 //}
6069 }
6070
6071 // Go through all of the permissions and remove any that match.
6072 final List<String> SEGMENTS = uri.getPathSegments();
6073 if (SEGMENTS != null) {
6074 final int NS = SEGMENTS.size();
6075 int N = mGrantedUriPermissions.size();
6076 for (int i=0; i<N; i++) {
6077 HashMap<Uri, UriPermission> perms
6078 = mGrantedUriPermissions.valueAt(i);
6079 Iterator<UriPermission> it = perms.values().iterator();
6080 toploop:
6081 while (it.hasNext()) {
6082 UriPermission perm = it.next();
6083 Uri targetUri = perm.uri;
6084 if (!authority.equals(targetUri.getAuthority())) {
6085 continue;
6086 }
6087 List<String> targetSegments = targetUri.getPathSegments();
6088 if (targetSegments == null) {
6089 continue;
6090 }
6091 if (targetSegments.size() < NS) {
6092 continue;
6093 }
6094 for (int j=0; j<NS; j++) {
6095 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6096 continue toploop;
6097 }
6098 }
6099 perm.clearModes(modeFlags);
6100 if (perm.modeFlags == 0) {
6101 it.remove();
6102 }
6103 }
6104 if (perms.size() == 0) {
6105 mGrantedUriPermissions.remove(
6106 mGrantedUriPermissions.keyAt(i));
6107 N--;
6108 i--;
6109 }
6110 }
6111 }
6112 }
6113
6114 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6115 int modeFlags) {
6116 synchronized(this) {
6117 final ProcessRecord r = getRecordForAppLocked(caller);
6118 if (r == null) {
6119 throw new SecurityException("Unable to find app for caller "
6120 + caller
6121 + " when revoking permission to uri " + uri);
6122 }
6123 if (uri == null) {
6124 Log.w(TAG, "revokeUriPermission: null uri");
6125 return;
6126 }
6127
6128 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6129 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6130 if (modeFlags == 0) {
6131 return;
6132 }
6133
6134 final IPackageManager pm = ActivityThread.getPackageManager();
6135
6136 final String authority = uri.getAuthority();
6137 ProviderInfo pi = null;
6138 ContentProviderRecord cpr
6139 = (ContentProviderRecord)mProvidersByName.get(authority);
6140 if (cpr != null) {
6141 pi = cpr.info;
6142 } else {
6143 try {
6144 pi = pm.resolveContentProvider(authority,
6145 PackageManager.GET_URI_PERMISSION_PATTERNS);
6146 } catch (RemoteException ex) {
6147 }
6148 }
6149 if (pi == null) {
6150 Log.w(TAG, "No content provider found for: " + authority);
6151 return;
6152 }
6153
6154 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6155 }
6156 }
6157
6158 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6159 synchronized (this) {
6160 ProcessRecord app =
6161 who != null ? getRecordForAppLocked(who) : null;
6162 if (app == null) return;
6163
6164 Message msg = Message.obtain();
6165 msg.what = WAIT_FOR_DEBUGGER_MSG;
6166 msg.obj = app;
6167 msg.arg1 = waiting ? 1 : 0;
6168 mHandler.sendMessage(msg);
6169 }
6170 }
6171
6172 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6173 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006174 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006175 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006176 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006177 }
6178
6179 // =========================================================
6180 // TASK MANAGEMENT
6181 // =========================================================
6182
6183 public List getTasks(int maxNum, int flags,
6184 IThumbnailReceiver receiver) {
6185 ArrayList list = new ArrayList();
6186
6187 PendingThumbnailsRecord pending = null;
6188 IApplicationThread topThumbnail = null;
6189 HistoryRecord topRecord = null;
6190
6191 synchronized(this) {
6192 if (localLOGV) Log.v(
6193 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6194 + ", receiver=" + receiver);
6195
6196 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6197 != PackageManager.PERMISSION_GRANTED) {
6198 if (receiver != null) {
6199 // If the caller wants to wait for pending thumbnails,
6200 // it ain't gonna get them.
6201 try {
6202 receiver.finished();
6203 } catch (RemoteException ex) {
6204 }
6205 }
6206 String msg = "Permission Denial: getTasks() from pid="
6207 + Binder.getCallingPid()
6208 + ", uid=" + Binder.getCallingUid()
6209 + " requires " + android.Manifest.permission.GET_TASKS;
6210 Log.w(TAG, msg);
6211 throw new SecurityException(msg);
6212 }
6213
6214 int pos = mHistory.size()-1;
6215 HistoryRecord next =
6216 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6217 HistoryRecord top = null;
6218 CharSequence topDescription = null;
6219 TaskRecord curTask = null;
6220 int numActivities = 0;
6221 int numRunning = 0;
6222 while (pos >= 0 && maxNum > 0) {
6223 final HistoryRecord r = next;
6224 pos--;
6225 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6226
6227 // Initialize state for next task if needed.
6228 if (top == null ||
6229 (top.state == ActivityState.INITIALIZING
6230 && top.task == r.task)) {
6231 top = r;
6232 topDescription = r.description;
6233 curTask = r.task;
6234 numActivities = numRunning = 0;
6235 }
6236
6237 // Add 'r' into the current task.
6238 numActivities++;
6239 if (r.app != null && r.app.thread != null) {
6240 numRunning++;
6241 }
6242 if (topDescription == null) {
6243 topDescription = r.description;
6244 }
6245
6246 if (localLOGV) Log.v(
6247 TAG, r.intent.getComponent().flattenToShortString()
6248 + ": task=" + r.task);
6249
6250 // If the next one is a different task, generate a new
6251 // TaskInfo entry for what we have.
6252 if (next == null || next.task != curTask) {
6253 ActivityManager.RunningTaskInfo ci
6254 = new ActivityManager.RunningTaskInfo();
6255 ci.id = curTask.taskId;
6256 ci.baseActivity = r.intent.getComponent();
6257 ci.topActivity = top.intent.getComponent();
6258 ci.thumbnail = top.thumbnail;
6259 ci.description = topDescription;
6260 ci.numActivities = numActivities;
6261 ci.numRunning = numRunning;
6262 //System.out.println(
6263 // "#" + maxNum + ": " + " descr=" + ci.description);
6264 if (ci.thumbnail == null && receiver != null) {
6265 if (localLOGV) Log.v(
6266 TAG, "State=" + top.state + "Idle=" + top.idle
6267 + " app=" + top.app
6268 + " thr=" + (top.app != null ? top.app.thread : null));
6269 if (top.state == ActivityState.RESUMED
6270 || top.state == ActivityState.PAUSING) {
6271 if (top.idle && top.app != null
6272 && top.app.thread != null) {
6273 topRecord = top;
6274 topThumbnail = top.app.thread;
6275 } else {
6276 top.thumbnailNeeded = true;
6277 }
6278 }
6279 if (pending == null) {
6280 pending = new PendingThumbnailsRecord(receiver);
6281 }
6282 pending.pendingRecords.add(top);
6283 }
6284 list.add(ci);
6285 maxNum--;
6286 top = null;
6287 }
6288 }
6289
6290 if (pending != null) {
6291 mPendingThumbnails.add(pending);
6292 }
6293 }
6294
6295 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6296
6297 if (topThumbnail != null) {
6298 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6299 try {
6300 topThumbnail.requestThumbnail(topRecord);
6301 } catch (Exception e) {
6302 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6303 sendPendingThumbnail(null, topRecord, null, null, true);
6304 }
6305 }
6306
6307 if (pending == null && receiver != null) {
6308 // In this case all thumbnails were available and the client
6309 // is being asked to be told when the remaining ones come in...
6310 // which is unusually, since the top-most currently running
6311 // activity should never have a canned thumbnail! Oh well.
6312 try {
6313 receiver.finished();
6314 } catch (RemoteException ex) {
6315 }
6316 }
6317
6318 return list;
6319 }
6320
6321 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6322 int flags) {
6323 synchronized (this) {
6324 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6325 "getRecentTasks()");
6326
6327 final int N = mRecentTasks.size();
6328 ArrayList<ActivityManager.RecentTaskInfo> res
6329 = new ArrayList<ActivityManager.RecentTaskInfo>(
6330 maxNum < N ? maxNum : N);
6331 for (int i=0; i<N && maxNum > 0; i++) {
6332 TaskRecord tr = mRecentTasks.get(i);
6333 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6334 || (tr.intent == null)
6335 || ((tr.intent.getFlags()
6336 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6337 ActivityManager.RecentTaskInfo rti
6338 = new ActivityManager.RecentTaskInfo();
6339 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6340 rti.baseIntent = new Intent(
6341 tr.intent != null ? tr.intent : tr.affinityIntent);
6342 rti.origActivity = tr.origActivity;
6343 res.add(rti);
6344 maxNum--;
6345 }
6346 }
6347 return res;
6348 }
6349 }
6350
6351 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6352 int j;
6353 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6354 TaskRecord jt = startTask;
6355
6356 // First look backwards
6357 for (j=startIndex-1; j>=0; j--) {
6358 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6359 if (r.task != jt) {
6360 jt = r.task;
6361 if (affinity.equals(jt.affinity)) {
6362 return j;
6363 }
6364 }
6365 }
6366
6367 // Now look forwards
6368 final int N = mHistory.size();
6369 jt = startTask;
6370 for (j=startIndex+1; j<N; j++) {
6371 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6372 if (r.task != jt) {
6373 if (affinity.equals(jt.affinity)) {
6374 return j;
6375 }
6376 jt = r.task;
6377 }
6378 }
6379
6380 // Might it be at the top?
6381 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6382 return N-1;
6383 }
6384
6385 return -1;
6386 }
6387
6388 /**
6389 * Perform a reset of the given task, if needed as part of launching it.
6390 * Returns the new HistoryRecord at the top of the task.
6391 */
6392 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6393 HistoryRecord newActivity) {
6394 boolean forceReset = (newActivity.info.flags
6395 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6396 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6397 if ((newActivity.info.flags
6398 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6399 forceReset = true;
6400 }
6401 }
6402
6403 final TaskRecord task = taskTop.task;
6404
6405 // We are going to move through the history list so that we can look
6406 // at each activity 'target' with 'below' either the interesting
6407 // activity immediately below it in the stack or null.
6408 HistoryRecord target = null;
6409 int targetI = 0;
6410 int taskTopI = -1;
6411 int replyChainEnd = -1;
6412 int lastReparentPos = -1;
6413 for (int i=mHistory.size()-1; i>=-1; i--) {
6414 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6415
6416 if (below != null && below.finishing) {
6417 continue;
6418 }
6419 if (target == null) {
6420 target = below;
6421 targetI = i;
6422 // If we were in the middle of a reply chain before this
6423 // task, it doesn't appear like the root of the chain wants
6424 // anything interesting, so drop it.
6425 replyChainEnd = -1;
6426 continue;
6427 }
6428
6429 final int flags = target.info.flags;
6430
6431 final boolean finishOnTaskLaunch =
6432 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6433 final boolean allowTaskReparenting =
6434 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6435
6436 if (target.task == task) {
6437 // We are inside of the task being reset... we'll either
6438 // finish this activity, push it out for another task,
6439 // or leave it as-is. We only do this
6440 // for activities that are not the root of the task (since
6441 // if we finish the root, we may no longer have the task!).
6442 if (taskTopI < 0) {
6443 taskTopI = targetI;
6444 }
6445 if (below != null && below.task == task) {
6446 final boolean clearWhenTaskReset =
6447 (target.intent.getFlags()
6448 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006449 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006450 // If this activity is sending a reply to a previous
6451 // activity, we can't do anything with it now until
6452 // we reach the start of the reply chain.
6453 // XXX note that we are assuming the result is always
6454 // to the previous activity, which is almost always
6455 // the case but we really shouldn't count on.
6456 if (replyChainEnd < 0) {
6457 replyChainEnd = targetI;
6458 }
Ed Heyl73798232009-03-24 21:32:21 -07006459 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006460 && target.taskAffinity != null
6461 && !target.taskAffinity.equals(task.affinity)) {
6462 // If this activity has an affinity for another
6463 // task, then we need to move it out of here. We will
6464 // move it as far out of the way as possible, to the
6465 // bottom of the activity stack. This also keeps it
6466 // correctly ordered with any activities we previously
6467 // moved.
6468 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6469 if (target.taskAffinity != null
6470 && target.taskAffinity.equals(p.task.affinity)) {
6471 // If the activity currently at the bottom has the
6472 // same task affinity as the one we are moving,
6473 // then merge it into the same task.
6474 target.task = p.task;
6475 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6476 + " out to bottom task " + p.task);
6477 } else {
6478 mCurTask++;
6479 if (mCurTask <= 0) {
6480 mCurTask = 1;
6481 }
6482 target.task = new TaskRecord(mCurTask, target.info, null,
6483 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6484 target.task.affinityIntent = target.intent;
6485 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6486 + " out to new task " + target.task);
6487 }
6488 mWindowManager.setAppGroupId(target, task.taskId);
6489 if (replyChainEnd < 0) {
6490 replyChainEnd = targetI;
6491 }
6492 int dstPos = 0;
6493 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6494 p = (HistoryRecord)mHistory.get(srcPos);
6495 if (p.finishing) {
6496 continue;
6497 }
6498 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6499 + " out to target's task " + target.task);
6500 task.numActivities--;
6501 p.task = target.task;
6502 target.task.numActivities++;
6503 mHistory.remove(srcPos);
6504 mHistory.add(dstPos, p);
6505 mWindowManager.moveAppToken(dstPos, p);
6506 mWindowManager.setAppGroupId(p, p.task.taskId);
6507 dstPos++;
6508 if (VALIDATE_TOKENS) {
6509 mWindowManager.validateAppTokens(mHistory);
6510 }
6511 i++;
6512 }
6513 if (taskTop == p) {
6514 taskTop = below;
6515 }
6516 if (taskTopI == replyChainEnd) {
6517 taskTopI = -1;
6518 }
6519 replyChainEnd = -1;
6520 addRecentTask(target.task);
6521 } else if (forceReset || finishOnTaskLaunch
6522 || clearWhenTaskReset) {
6523 // If the activity should just be removed -- either
6524 // because it asks for it, or the task should be
6525 // cleared -- then finish it and anything that is
6526 // part of its reply chain.
6527 if (clearWhenTaskReset) {
6528 // In this case, we want to finish this activity
6529 // and everything above it, so be sneaky and pretend
6530 // like these are all in the reply chain.
6531 replyChainEnd = targetI+1;
6532 while (replyChainEnd < mHistory.size() &&
6533 ((HistoryRecord)mHistory.get(
6534 replyChainEnd)).task == task) {
6535 replyChainEnd++;
6536 }
6537 replyChainEnd--;
6538 } else if (replyChainEnd < 0) {
6539 replyChainEnd = targetI;
6540 }
6541 HistoryRecord p = null;
6542 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6543 p = (HistoryRecord)mHistory.get(srcPos);
6544 if (p.finishing) {
6545 continue;
6546 }
6547 if (finishActivityLocked(p, srcPos,
6548 Activity.RESULT_CANCELED, null, "reset")) {
6549 replyChainEnd--;
6550 srcPos--;
6551 }
6552 }
6553 if (taskTop == p) {
6554 taskTop = below;
6555 }
6556 if (taskTopI == replyChainEnd) {
6557 taskTopI = -1;
6558 }
6559 replyChainEnd = -1;
6560 } else {
6561 // If we were in the middle of a chain, well the
6562 // activity that started it all doesn't want anything
6563 // special, so leave it all as-is.
6564 replyChainEnd = -1;
6565 }
6566 } else {
6567 // Reached the bottom of the task -- any reply chain
6568 // should be left as-is.
6569 replyChainEnd = -1;
6570 }
6571
6572 } else if (target.resultTo != null) {
6573 // If this activity is sending a reply to a previous
6574 // activity, we can't do anything with it now until
6575 // we reach the start of the reply chain.
6576 // XXX note that we are assuming the result is always
6577 // to the previous activity, which is almost always
6578 // the case but we really shouldn't count on.
6579 if (replyChainEnd < 0) {
6580 replyChainEnd = targetI;
6581 }
6582
6583 } else if (taskTopI >= 0 && allowTaskReparenting
6584 && task.affinity != null
6585 && task.affinity.equals(target.taskAffinity)) {
6586 // We are inside of another task... if this activity has
6587 // an affinity for our task, then either remove it if we are
6588 // clearing or move it over to our task. Note that
6589 // we currently punt on the case where we are resetting a
6590 // task that is not at the top but who has activities above
6591 // with an affinity to it... this is really not a normal
6592 // case, and we will need to later pull that task to the front
6593 // and usually at that point we will do the reset and pick
6594 // up those remaining activities. (This only happens if
6595 // someone starts an activity in a new task from an activity
6596 // in a task that is not currently on top.)
6597 if (forceReset || finishOnTaskLaunch) {
6598 if (replyChainEnd < 0) {
6599 replyChainEnd = targetI;
6600 }
6601 HistoryRecord p = null;
6602 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6603 p = (HistoryRecord)mHistory.get(srcPos);
6604 if (p.finishing) {
6605 continue;
6606 }
6607 if (finishActivityLocked(p, srcPos,
6608 Activity.RESULT_CANCELED, null, "reset")) {
6609 taskTopI--;
6610 lastReparentPos--;
6611 replyChainEnd--;
6612 srcPos--;
6613 }
6614 }
6615 replyChainEnd = -1;
6616 } else {
6617 if (replyChainEnd < 0) {
6618 replyChainEnd = targetI;
6619 }
6620 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6621 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6622 if (p.finishing) {
6623 continue;
6624 }
6625 if (lastReparentPos < 0) {
6626 lastReparentPos = taskTopI;
6627 taskTop = p;
6628 } else {
6629 lastReparentPos--;
6630 }
6631 mHistory.remove(srcPos);
6632 p.task.numActivities--;
6633 p.task = task;
6634 mHistory.add(lastReparentPos, p);
6635 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6636 + " in to resetting task " + task);
6637 task.numActivities++;
6638 mWindowManager.moveAppToken(lastReparentPos, p);
6639 mWindowManager.setAppGroupId(p, p.task.taskId);
6640 if (VALIDATE_TOKENS) {
6641 mWindowManager.validateAppTokens(mHistory);
6642 }
6643 }
6644 replyChainEnd = -1;
6645
6646 // Now we've moved it in to place... but what if this is
6647 // a singleTop activity and we have put it on top of another
6648 // instance of the same activity? Then we drop the instance
6649 // below so it remains singleTop.
6650 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6651 for (int j=lastReparentPos-1; j>=0; j--) {
6652 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6653 if (p.finishing) {
6654 continue;
6655 }
6656 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6657 if (finishActivityLocked(p, j,
6658 Activity.RESULT_CANCELED, null, "replace")) {
6659 taskTopI--;
6660 lastReparentPos--;
6661 }
6662 }
6663 }
6664 }
6665 }
6666 }
6667
6668 target = below;
6669 targetI = i;
6670 }
6671
6672 return taskTop;
6673 }
6674
6675 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006676 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006677 */
6678 public void moveTaskToFront(int task) {
6679 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6680 "moveTaskToFront()");
6681
6682 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006683 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6684 Binder.getCallingUid(), "Task to front")) {
6685 return;
6686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006687 final long origId = Binder.clearCallingIdentity();
6688 try {
6689 int N = mRecentTasks.size();
6690 for (int i=0; i<N; i++) {
6691 TaskRecord tr = mRecentTasks.get(i);
6692 if (tr.taskId == task) {
6693 moveTaskToFrontLocked(tr);
6694 return;
6695 }
6696 }
6697 for (int i=mHistory.size()-1; i>=0; i--) {
6698 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6699 if (hr.task.taskId == task) {
6700 moveTaskToFrontLocked(hr.task);
6701 return;
6702 }
6703 }
6704 } finally {
6705 Binder.restoreCallingIdentity(origId);
6706 }
6707 }
6708 }
6709
6710 private final void moveTaskToFrontLocked(TaskRecord tr) {
6711 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6712
6713 final int task = tr.taskId;
6714 int top = mHistory.size()-1;
6715
6716 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6717 // nothing to do!
6718 return;
6719 }
6720
6721 if (DEBUG_TRANSITION) Log.v(TAG,
6722 "Prepare to front transition: task=" + tr);
6723 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6724
6725 ArrayList moved = new ArrayList();
6726
6727 // Applying the affinities may have removed entries from the history,
6728 // so get the size again.
6729 top = mHistory.size()-1;
6730 int pos = top;
6731
6732 // Shift all activities with this task up to the top
6733 // of the stack, keeping them in the same internal order.
6734 while (pos >= 0) {
6735 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6736 if (localLOGV) Log.v(
6737 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6738 boolean first = true;
6739 if (r.task.taskId == task) {
6740 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6741 mHistory.remove(pos);
6742 mHistory.add(top, r);
6743 moved.add(0, r);
6744 top--;
6745 if (first) {
6746 addRecentTask(r.task);
6747 first = false;
6748 }
6749 }
6750 pos--;
6751 }
6752
6753 mWindowManager.moveAppTokensToTop(moved);
6754 if (VALIDATE_TOKENS) {
6755 mWindowManager.validateAppTokens(mHistory);
6756 }
6757
6758 finishTaskMove(task);
6759 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6760 }
6761
6762 private final void finishTaskMove(int task) {
6763 resumeTopActivityLocked(null);
6764 }
6765
6766 public void moveTaskToBack(int task) {
6767 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6768 "moveTaskToBack()");
6769
6770 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006771 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6772 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6773 Binder.getCallingUid(), "Task to back")) {
6774 return;
6775 }
6776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006777 final long origId = Binder.clearCallingIdentity();
6778 moveTaskToBackLocked(task);
6779 Binder.restoreCallingIdentity(origId);
6780 }
6781 }
6782
6783 /**
6784 * Moves an activity, and all of the other activities within the same task, to the bottom
6785 * of the history stack. The activity's order within the task is unchanged.
6786 *
6787 * @param token A reference to the activity we wish to move
6788 * @param nonRoot If false then this only works if the activity is the root
6789 * of a task; if true it will work for any activity in a task.
6790 * @return Returns true if the move completed, false if not.
6791 */
6792 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6793 synchronized(this) {
6794 final long origId = Binder.clearCallingIdentity();
6795 int taskId = getTaskForActivityLocked(token, !nonRoot);
6796 if (taskId >= 0) {
6797 return moveTaskToBackLocked(taskId);
6798 }
6799 Binder.restoreCallingIdentity(origId);
6800 }
6801 return false;
6802 }
6803
6804 /**
6805 * Worker method for rearranging history stack. Implements the function of moving all
6806 * activities for a specific task (gathering them if disjoint) into a single group at the
6807 * bottom of the stack.
6808 *
6809 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6810 * to premeptively cancel the move.
6811 *
6812 * @param task The taskId to collect and move to the bottom.
6813 * @return Returns true if the move completed, false if not.
6814 */
6815 private final boolean moveTaskToBackLocked(int task) {
6816 Log.i(TAG, "moveTaskToBack: " + task);
6817
6818 // If we have a watcher, preflight the move before committing to it. First check
6819 // for *other* available tasks, but if none are available, then try again allowing the
6820 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006821 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006822 HistoryRecord next = topRunningActivityLocked(null, task);
6823 if (next == null) {
6824 next = topRunningActivityLocked(null, 0);
6825 }
6826 if (next != null) {
6827 // ask watcher if this is allowed
6828 boolean moveOK = true;
6829 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006830 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006831 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006832 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006833 }
6834 if (!moveOK) {
6835 return false;
6836 }
6837 }
6838 }
6839
6840 ArrayList moved = new ArrayList();
6841
6842 if (DEBUG_TRANSITION) Log.v(TAG,
6843 "Prepare to back transition: task=" + task);
6844 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6845
6846 final int N = mHistory.size();
6847 int bottom = 0;
6848 int pos = 0;
6849
6850 // Shift all activities with this task down to the bottom
6851 // of the stack, keeping them in the same internal order.
6852 while (pos < N) {
6853 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6854 if (localLOGV) Log.v(
6855 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6856 if (r.task.taskId == task) {
6857 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6858 mHistory.remove(pos);
6859 mHistory.add(bottom, r);
6860 moved.add(r);
6861 bottom++;
6862 }
6863 pos++;
6864 }
6865
6866 mWindowManager.moveAppTokensToBottom(moved);
6867 if (VALIDATE_TOKENS) {
6868 mWindowManager.validateAppTokens(mHistory);
6869 }
6870
6871 finishTaskMove(task);
6872 return true;
6873 }
6874
6875 public void moveTaskBackwards(int task) {
6876 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6877 "moveTaskBackwards()");
6878
6879 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006880 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6881 Binder.getCallingUid(), "Task backwards")) {
6882 return;
6883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006884 final long origId = Binder.clearCallingIdentity();
6885 moveTaskBackwardsLocked(task);
6886 Binder.restoreCallingIdentity(origId);
6887 }
6888 }
6889
6890 private final void moveTaskBackwardsLocked(int task) {
6891 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6892 }
6893
6894 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6895 synchronized(this) {
6896 return getTaskForActivityLocked(token, onlyRoot);
6897 }
6898 }
6899
6900 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6901 final int N = mHistory.size();
6902 TaskRecord lastTask = null;
6903 for (int i=0; i<N; i++) {
6904 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6905 if (r == token) {
6906 if (!onlyRoot || lastTask != r.task) {
6907 return r.task.taskId;
6908 }
6909 return -1;
6910 }
6911 lastTask = r.task;
6912 }
6913
6914 return -1;
6915 }
6916
6917 /**
6918 * Returns the top activity in any existing task matching the given
6919 * Intent. Returns null if no such task is found.
6920 */
6921 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6922 ComponentName cls = intent.getComponent();
6923 if (info.targetActivity != null) {
6924 cls = new ComponentName(info.packageName, info.targetActivity);
6925 }
6926
6927 TaskRecord cp = null;
6928
6929 final int N = mHistory.size();
6930 for (int i=(N-1); i>=0; i--) {
6931 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6932 if (!r.finishing && r.task != cp
6933 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6934 cp = r.task;
6935 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6936 // + "/aff=" + r.task.affinity + " to new cls="
6937 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6938 if (r.task.affinity != null) {
6939 if (r.task.affinity.equals(info.taskAffinity)) {
6940 //Log.i(TAG, "Found matching affinity!");
6941 return r;
6942 }
6943 } else if (r.task.intent != null
6944 && r.task.intent.getComponent().equals(cls)) {
6945 //Log.i(TAG, "Found matching class!");
6946 //dump();
6947 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6948 return r;
6949 } else if (r.task.affinityIntent != null
6950 && r.task.affinityIntent.getComponent().equals(cls)) {
6951 //Log.i(TAG, "Found matching class!");
6952 //dump();
6953 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6954 return r;
6955 }
6956 }
6957 }
6958
6959 return null;
6960 }
6961
6962 /**
6963 * Returns the first activity (starting from the top of the stack) that
6964 * is the same as the given activity. Returns null if no such activity
6965 * is found.
6966 */
6967 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6968 ComponentName cls = intent.getComponent();
6969 if (info.targetActivity != null) {
6970 cls = new ComponentName(info.packageName, info.targetActivity);
6971 }
6972
6973 final int N = mHistory.size();
6974 for (int i=(N-1); i>=0; i--) {
6975 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6976 if (!r.finishing) {
6977 if (r.intent.getComponent().equals(cls)) {
6978 //Log.i(TAG, "Found matching class!");
6979 //dump();
6980 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6981 return r;
6982 }
6983 }
6984 }
6985
6986 return null;
6987 }
6988
6989 public void finishOtherInstances(IBinder token, ComponentName className) {
6990 synchronized(this) {
6991 final long origId = Binder.clearCallingIdentity();
6992
6993 int N = mHistory.size();
6994 TaskRecord lastTask = null;
6995 for (int i=0; i<N; i++) {
6996 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6997 if (r.realActivity.equals(className)
6998 && r != token && lastTask != r.task) {
6999 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7000 null, "others")) {
7001 i--;
7002 N--;
7003 }
7004 }
7005 lastTask = r.task;
7006 }
7007
7008 Binder.restoreCallingIdentity(origId);
7009 }
7010 }
7011
7012 // =========================================================
7013 // THUMBNAILS
7014 // =========================================================
7015
7016 public void reportThumbnail(IBinder token,
7017 Bitmap thumbnail, CharSequence description) {
7018 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7019 final long origId = Binder.clearCallingIdentity();
7020 sendPendingThumbnail(null, token, thumbnail, description, true);
7021 Binder.restoreCallingIdentity(origId);
7022 }
7023
7024 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7025 Bitmap thumbnail, CharSequence description, boolean always) {
7026 TaskRecord task = null;
7027 ArrayList receivers = null;
7028
7029 //System.out.println("Send pending thumbnail: " + r);
7030
7031 synchronized(this) {
7032 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007033 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007034 if (index < 0) {
7035 return;
7036 }
7037 r = (HistoryRecord)mHistory.get(index);
7038 }
7039 if (thumbnail == null) {
7040 thumbnail = r.thumbnail;
7041 description = r.description;
7042 }
7043 if (thumbnail == null && !always) {
7044 // If there is no thumbnail, and this entry is not actually
7045 // going away, then abort for now and pick up the next
7046 // thumbnail we get.
7047 return;
7048 }
7049 task = r.task;
7050
7051 int N = mPendingThumbnails.size();
7052 int i=0;
7053 while (i<N) {
7054 PendingThumbnailsRecord pr =
7055 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7056 //System.out.println("Looking in " + pr.pendingRecords);
7057 if (pr.pendingRecords.remove(r)) {
7058 if (receivers == null) {
7059 receivers = new ArrayList();
7060 }
7061 receivers.add(pr);
7062 if (pr.pendingRecords.size() == 0) {
7063 pr.finished = true;
7064 mPendingThumbnails.remove(i);
7065 N--;
7066 continue;
7067 }
7068 }
7069 i++;
7070 }
7071 }
7072
7073 if (receivers != null) {
7074 final int N = receivers.size();
7075 for (int i=0; i<N; i++) {
7076 try {
7077 PendingThumbnailsRecord pr =
7078 (PendingThumbnailsRecord)receivers.get(i);
7079 pr.receiver.newThumbnail(
7080 task != null ? task.taskId : -1, thumbnail, description);
7081 if (pr.finished) {
7082 pr.receiver.finished();
7083 }
7084 } catch (Exception e) {
7085 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7086 }
7087 }
7088 }
7089 }
7090
7091 // =========================================================
7092 // CONTENT PROVIDERS
7093 // =========================================================
7094
7095 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7096 List providers = null;
7097 try {
7098 providers = ActivityThread.getPackageManager().
7099 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007100 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007101 } catch (RemoteException ex) {
7102 }
7103 if (providers != null) {
7104 final int N = providers.size();
7105 for (int i=0; i<N; i++) {
7106 ProviderInfo cpi =
7107 (ProviderInfo)providers.get(i);
7108 ContentProviderRecord cpr =
7109 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7110 if (cpr == null) {
7111 cpr = new ContentProviderRecord(cpi, app.info);
7112 mProvidersByClass.put(cpi.name, cpr);
7113 }
7114 app.pubProviders.put(cpi.name, cpr);
7115 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007116 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007117 }
7118 }
7119 return providers;
7120 }
7121
7122 private final String checkContentProviderPermissionLocked(
7123 ProviderInfo cpi, ProcessRecord r, int mode) {
7124 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7125 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7126 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7127 cpi.exported ? -1 : cpi.applicationInfo.uid)
7128 == PackageManager.PERMISSION_GRANTED
7129 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7130 return null;
7131 }
7132 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7133 cpi.exported ? -1 : cpi.applicationInfo.uid)
7134 == PackageManager.PERMISSION_GRANTED) {
7135 return null;
7136 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007137
7138 PathPermission[] pps = cpi.pathPermissions;
7139 if (pps != null) {
7140 int i = pps.length;
7141 while (i > 0) {
7142 i--;
7143 PathPermission pp = pps[i];
7144 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7145 cpi.exported ? -1 : cpi.applicationInfo.uid)
7146 == PackageManager.PERMISSION_GRANTED
7147 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7148 return null;
7149 }
7150 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7151 cpi.exported ? -1 : cpi.applicationInfo.uid)
7152 == PackageManager.PERMISSION_GRANTED) {
7153 return null;
7154 }
7155 }
7156 }
7157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158 String msg = "Permission Denial: opening provider " + cpi.name
7159 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7160 + ", uid=" + callingUid + ") requires "
7161 + cpi.readPermission + " or " + cpi.writePermission;
7162 Log.w(TAG, msg);
7163 return msg;
7164 }
7165
7166 private final ContentProviderHolder getContentProviderImpl(
7167 IApplicationThread caller, String name) {
7168 ContentProviderRecord cpr;
7169 ProviderInfo cpi = null;
7170
7171 synchronized(this) {
7172 ProcessRecord r = null;
7173 if (caller != null) {
7174 r = getRecordForAppLocked(caller);
7175 if (r == null) {
7176 throw new SecurityException(
7177 "Unable to find app for caller " + caller
7178 + " (pid=" + Binder.getCallingPid()
7179 + ") when getting content provider " + name);
7180 }
7181 }
7182
7183 // First check if this content provider has been published...
7184 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7185 if (cpr != null) {
7186 cpi = cpr.info;
7187 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7188 return new ContentProviderHolder(cpi,
7189 cpi.readPermission != null
7190 ? cpi.readPermission : cpi.writePermission);
7191 }
7192
7193 if (r != null && cpr.canRunHere(r)) {
7194 // This provider has been published or is in the process
7195 // of being published... but it is also allowed to run
7196 // in the caller's process, so don't make a connection
7197 // and just let the caller instantiate its own instance.
7198 if (cpr.provider != null) {
7199 // don't give caller the provider object, it needs
7200 // to make its own.
7201 cpr = new ContentProviderRecord(cpr);
7202 }
7203 return cpr;
7204 }
7205
7206 final long origId = Binder.clearCallingIdentity();
7207
7208 // In this case the provider is a single instance, so we can
7209 // return it right away.
7210 if (r != null) {
7211 r.conProviders.add(cpr);
7212 cpr.clients.add(r);
7213 } else {
7214 cpr.externals++;
7215 }
7216
7217 if (cpr.app != null) {
7218 updateOomAdjLocked(cpr.app);
7219 }
7220
7221 Binder.restoreCallingIdentity(origId);
7222
7223 } else {
7224 try {
7225 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007226 resolveContentProvider(name,
7227 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007228 } catch (RemoteException ex) {
7229 }
7230 if (cpi == null) {
7231 return null;
7232 }
7233
7234 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7235 return new ContentProviderHolder(cpi,
7236 cpi.readPermission != null
7237 ? cpi.readPermission : cpi.writePermission);
7238 }
7239
7240 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7241 final boolean firstClass = cpr == null;
7242 if (firstClass) {
7243 try {
7244 ApplicationInfo ai =
7245 ActivityThread.getPackageManager().
7246 getApplicationInfo(
7247 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007248 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007249 if (ai == null) {
7250 Log.w(TAG, "No package info for content provider "
7251 + cpi.name);
7252 return null;
7253 }
7254 cpr = new ContentProviderRecord(cpi, ai);
7255 } catch (RemoteException ex) {
7256 // pm is in same process, this will never happen.
7257 }
7258 }
7259
7260 if (r != null && cpr.canRunHere(r)) {
7261 // If this is a multiprocess provider, then just return its
7262 // info and allow the caller to instantiate it. Only do
7263 // this if the provider is the same user as the caller's
7264 // process, or can run as root (so can be in any process).
7265 return cpr;
7266 }
7267
7268 if (false) {
7269 RuntimeException e = new RuntimeException("foo");
7270 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7271 // + " pruid " + ai.uid + "): " + cpi.className, e);
7272 }
7273
7274 // This is single process, and our app is now connecting to it.
7275 // See if we are already in the process of launching this
7276 // provider.
7277 final int N = mLaunchingProviders.size();
7278 int i;
7279 for (i=0; i<N; i++) {
7280 if (mLaunchingProviders.get(i) == cpr) {
7281 break;
7282 }
7283 if (false) {
7284 final ContentProviderRecord rec =
7285 (ContentProviderRecord)mLaunchingProviders.get(i);
7286 if (rec.info.name.equals(cpr.info.name)) {
7287 cpr = rec;
7288 break;
7289 }
7290 }
7291 }
7292
7293 // If the provider is not already being launched, then get it
7294 // started.
7295 if (i >= N) {
7296 final long origId = Binder.clearCallingIdentity();
7297 ProcessRecord proc = startProcessLocked(cpi.processName,
7298 cpr.appInfo, false, 0, "content provider",
7299 new ComponentName(cpi.applicationInfo.packageName,
7300 cpi.name));
7301 if (proc == null) {
7302 Log.w(TAG, "Unable to launch app "
7303 + cpi.applicationInfo.packageName + "/"
7304 + cpi.applicationInfo.uid + " for provider "
7305 + name + ": process is bad");
7306 return null;
7307 }
7308 cpr.launchingApp = proc;
7309 mLaunchingProviders.add(cpr);
7310 Binder.restoreCallingIdentity(origId);
7311 }
7312
7313 // Make sure the provider is published (the same provider class
7314 // may be published under multiple names).
7315 if (firstClass) {
7316 mProvidersByClass.put(cpi.name, cpr);
7317 }
7318 mProvidersByName.put(name, cpr);
7319
7320 if (r != null) {
7321 r.conProviders.add(cpr);
7322 cpr.clients.add(r);
7323 } else {
7324 cpr.externals++;
7325 }
7326 }
7327 }
7328
7329 // Wait for the provider to be published...
7330 synchronized (cpr) {
7331 while (cpr.provider == null) {
7332 if (cpr.launchingApp == null) {
7333 Log.w(TAG, "Unable to launch app "
7334 + cpi.applicationInfo.packageName + "/"
7335 + cpi.applicationInfo.uid + " for provider "
7336 + name + ": launching app became null");
7337 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7338 cpi.applicationInfo.packageName,
7339 cpi.applicationInfo.uid, name);
7340 return null;
7341 }
7342 try {
7343 cpr.wait();
7344 } catch (InterruptedException ex) {
7345 }
7346 }
7347 }
7348 return cpr;
7349 }
7350
7351 public final ContentProviderHolder getContentProvider(
7352 IApplicationThread caller, String name) {
7353 if (caller == null) {
7354 String msg = "null IApplicationThread when getting content provider "
7355 + name;
7356 Log.w(TAG, msg);
7357 throw new SecurityException(msg);
7358 }
7359
7360 return getContentProviderImpl(caller, name);
7361 }
7362
7363 private ContentProviderHolder getContentProviderExternal(String name) {
7364 return getContentProviderImpl(null, name);
7365 }
7366
7367 /**
7368 * Drop a content provider from a ProcessRecord's bookkeeping
7369 * @param cpr
7370 */
7371 public void removeContentProvider(IApplicationThread caller, String name) {
7372 synchronized (this) {
7373 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7374 if(cpr == null) {
7375 //remove from mProvidersByClass
7376 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7377 return;
7378 }
7379 final ProcessRecord r = getRecordForAppLocked(caller);
7380 if (r == null) {
7381 throw new SecurityException(
7382 "Unable to find app for caller " + caller +
7383 " when removing content provider " + name);
7384 }
7385 //update content provider record entry info
7386 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7387 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7388 r.info.processName+" from process "+localCpr.appInfo.processName);
7389 if(localCpr.appInfo.processName == r.info.processName) {
7390 //should not happen. taken care of as a local provider
7391 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7392 return;
7393 } else {
7394 localCpr.clients.remove(r);
7395 r.conProviders.remove(localCpr);
7396 }
7397 updateOomAdjLocked();
7398 }
7399 }
7400
7401 private void removeContentProviderExternal(String name) {
7402 synchronized (this) {
7403 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7404 if(cpr == null) {
7405 //remove from mProvidersByClass
7406 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7407 return;
7408 }
7409
7410 //update content provider record entry info
7411 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7412 localCpr.externals--;
7413 if (localCpr.externals < 0) {
7414 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7415 }
7416 updateOomAdjLocked();
7417 }
7418 }
7419
7420 public final void publishContentProviders(IApplicationThread caller,
7421 List<ContentProviderHolder> providers) {
7422 if (providers == null) {
7423 return;
7424 }
7425
7426 synchronized(this) {
7427 final ProcessRecord r = getRecordForAppLocked(caller);
7428 if (r == null) {
7429 throw new SecurityException(
7430 "Unable to find app for caller " + caller
7431 + " (pid=" + Binder.getCallingPid()
7432 + ") when publishing content providers");
7433 }
7434
7435 final long origId = Binder.clearCallingIdentity();
7436
7437 final int N = providers.size();
7438 for (int i=0; i<N; i++) {
7439 ContentProviderHolder src = providers.get(i);
7440 if (src == null || src.info == null || src.provider == null) {
7441 continue;
7442 }
7443 ContentProviderRecord dst =
7444 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7445 if (dst != null) {
7446 mProvidersByClass.put(dst.info.name, dst);
7447 String names[] = dst.info.authority.split(";");
7448 for (int j = 0; j < names.length; j++) {
7449 mProvidersByName.put(names[j], dst);
7450 }
7451
7452 int NL = mLaunchingProviders.size();
7453 int j;
7454 for (j=0; j<NL; j++) {
7455 if (mLaunchingProviders.get(j) == dst) {
7456 mLaunchingProviders.remove(j);
7457 j--;
7458 NL--;
7459 }
7460 }
7461 synchronized (dst) {
7462 dst.provider = src.provider;
7463 dst.app = r;
7464 dst.notifyAll();
7465 }
7466 updateOomAdjLocked(r);
7467 }
7468 }
7469
7470 Binder.restoreCallingIdentity(origId);
7471 }
7472 }
7473
7474 public static final void installSystemProviders() {
7475 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7476 List providers = mSelf.generateApplicationProvidersLocked(app);
7477 mSystemThread.installSystemProviders(providers);
7478 }
7479
7480 // =========================================================
7481 // GLOBAL MANAGEMENT
7482 // =========================================================
7483
7484 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7485 ApplicationInfo info, String customProcess) {
7486 String proc = customProcess != null ? customProcess : info.processName;
7487 BatteryStatsImpl.Uid.Proc ps = null;
7488 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7489 synchronized (stats) {
7490 ps = stats.getProcessStatsLocked(info.uid, proc);
7491 }
7492 return new ProcessRecord(ps, thread, info, proc);
7493 }
7494
7495 final ProcessRecord addAppLocked(ApplicationInfo info) {
7496 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7497
7498 if (app == null) {
7499 app = newProcessRecordLocked(null, info, null);
7500 mProcessNames.put(info.processName, info.uid, app);
7501 updateLRUListLocked(app, true);
7502 }
7503
7504 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7505 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7506 app.persistent = true;
7507 app.maxAdj = CORE_SERVER_ADJ;
7508 }
7509 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7510 mPersistentStartingProcesses.add(app);
7511 startProcessLocked(app, "added application", app.processName);
7512 }
7513
7514 return app;
7515 }
7516
7517 public void unhandledBack() {
7518 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7519 "unhandledBack()");
7520
7521 synchronized(this) {
7522 int count = mHistory.size();
7523 if (Config.LOGD) Log.d(
7524 TAG, "Performing unhandledBack(): stack size = " + count);
7525 if (count > 1) {
7526 final long origId = Binder.clearCallingIdentity();
7527 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7528 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7529 Binder.restoreCallingIdentity(origId);
7530 }
7531 }
7532 }
7533
7534 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7535 String name = uri.getAuthority();
7536 ContentProviderHolder cph = getContentProviderExternal(name);
7537 ParcelFileDescriptor pfd = null;
7538 if (cph != null) {
7539 // We record the binder invoker's uid in thread-local storage before
7540 // going to the content provider to open the file. Later, in the code
7541 // that handles all permissions checks, we look for this uid and use
7542 // that rather than the Activity Manager's own uid. The effect is that
7543 // we do the check against the caller's permissions even though it looks
7544 // to the content provider like the Activity Manager itself is making
7545 // the request.
7546 sCallerIdentity.set(new Identity(
7547 Binder.getCallingPid(), Binder.getCallingUid()));
7548 try {
7549 pfd = cph.provider.openFile(uri, "r");
7550 } catch (FileNotFoundException e) {
7551 // do nothing; pfd will be returned null
7552 } finally {
7553 // Ensure that whatever happens, we clean up the identity state
7554 sCallerIdentity.remove();
7555 }
7556
7557 // We've got the fd now, so we're done with the provider.
7558 removeContentProviderExternal(name);
7559 } else {
7560 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7561 }
7562 return pfd;
7563 }
7564
7565 public void goingToSleep() {
7566 synchronized(this) {
7567 mSleeping = true;
7568 mWindowManager.setEventDispatching(false);
7569
7570 if (mResumedActivity != null) {
7571 pauseIfSleepingLocked();
7572 } else {
7573 Log.w(TAG, "goingToSleep with no resumed activity!");
7574 }
7575 }
7576 }
7577
Dianne Hackborn55280a92009-05-07 15:53:46 -07007578 public boolean shutdown(int timeout) {
7579 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7580 != PackageManager.PERMISSION_GRANTED) {
7581 throw new SecurityException("Requires permission "
7582 + android.Manifest.permission.SHUTDOWN);
7583 }
7584
7585 boolean timedout = false;
7586
7587 synchronized(this) {
7588 mShuttingDown = true;
7589 mWindowManager.setEventDispatching(false);
7590
7591 if (mResumedActivity != null) {
7592 pauseIfSleepingLocked();
7593 final long endTime = System.currentTimeMillis() + timeout;
7594 while (mResumedActivity != null || mPausingActivity != null) {
7595 long delay = endTime - System.currentTimeMillis();
7596 if (delay <= 0) {
7597 Log.w(TAG, "Activity manager shutdown timed out");
7598 timedout = true;
7599 break;
7600 }
7601 try {
7602 this.wait();
7603 } catch (InterruptedException e) {
7604 }
7605 }
7606 }
7607 }
7608
7609 mUsageStatsService.shutdown();
7610 mBatteryStatsService.shutdown();
7611
7612 return timedout;
7613 }
7614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007615 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007616 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007617 if (!mGoingToSleep.isHeld()) {
7618 mGoingToSleep.acquire();
7619 if (mLaunchingActivity.isHeld()) {
7620 mLaunchingActivity.release();
7621 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7622 }
7623 }
7624
7625 // If we are not currently pausing an activity, get the current
7626 // one to pause. If we are pausing one, we will just let that stuff
7627 // run and release the wake lock when all done.
7628 if (mPausingActivity == null) {
7629 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7630 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7631 startPausingLocked(false, true);
7632 }
7633 }
7634 }
7635
7636 public void wakingUp() {
7637 synchronized(this) {
7638 if (mGoingToSleep.isHeld()) {
7639 mGoingToSleep.release();
7640 }
7641 mWindowManager.setEventDispatching(true);
7642 mSleeping = false;
7643 resumeTopActivityLocked(null);
7644 }
7645 }
7646
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007647 public void stopAppSwitches() {
7648 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7649 != PackageManager.PERMISSION_GRANTED) {
7650 throw new SecurityException("Requires permission "
7651 + android.Manifest.permission.STOP_APP_SWITCHES);
7652 }
7653
7654 synchronized(this) {
7655 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7656 + APP_SWITCH_DELAY_TIME;
7657 mDidAppSwitch = false;
7658 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7659 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7660 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7661 }
7662 }
7663
7664 public void resumeAppSwitches() {
7665 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7666 != PackageManager.PERMISSION_GRANTED) {
7667 throw new SecurityException("Requires permission "
7668 + android.Manifest.permission.STOP_APP_SWITCHES);
7669 }
7670
7671 synchronized(this) {
7672 // Note that we don't execute any pending app switches... we will
7673 // let those wait until either the timeout, or the next start
7674 // activity request.
7675 mAppSwitchesAllowedTime = 0;
7676 }
7677 }
7678
7679 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7680 String name) {
7681 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7682 return true;
7683 }
7684
7685 final int perm = checkComponentPermission(
7686 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7687 callingUid, -1);
7688 if (perm == PackageManager.PERMISSION_GRANTED) {
7689 return true;
7690 }
7691
7692 Log.w(TAG, name + " request from " + callingUid + " stopped");
7693 return false;
7694 }
7695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007696 public void setDebugApp(String packageName, boolean waitForDebugger,
7697 boolean persistent) {
7698 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7699 "setDebugApp()");
7700
7701 // Note that this is not really thread safe if there are multiple
7702 // callers into it at the same time, but that's not a situation we
7703 // care about.
7704 if (persistent) {
7705 final ContentResolver resolver = mContext.getContentResolver();
7706 Settings.System.putString(
7707 resolver, Settings.System.DEBUG_APP,
7708 packageName);
7709 Settings.System.putInt(
7710 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7711 waitForDebugger ? 1 : 0);
7712 }
7713
7714 synchronized (this) {
7715 if (!persistent) {
7716 mOrigDebugApp = mDebugApp;
7717 mOrigWaitForDebugger = mWaitForDebugger;
7718 }
7719 mDebugApp = packageName;
7720 mWaitForDebugger = waitForDebugger;
7721 mDebugTransient = !persistent;
7722 if (packageName != null) {
7723 final long origId = Binder.clearCallingIdentity();
7724 uninstallPackageLocked(packageName, -1, false);
7725 Binder.restoreCallingIdentity(origId);
7726 }
7727 }
7728 }
7729
7730 public void setAlwaysFinish(boolean enabled) {
7731 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7732 "setAlwaysFinish()");
7733
7734 Settings.System.putInt(
7735 mContext.getContentResolver(),
7736 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7737
7738 synchronized (this) {
7739 mAlwaysFinishActivities = enabled;
7740 }
7741 }
7742
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007743 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007744 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007745 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007746 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007747 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007748 }
7749 }
7750
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007751 public void registerActivityWatcher(IActivityWatcher watcher) {
7752 mWatchers.register(watcher);
7753 }
7754
7755 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7756 mWatchers.unregister(watcher);
7757 }
7758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007759 public final void enterSafeMode() {
7760 synchronized(this) {
7761 // It only makes sense to do this before the system is ready
7762 // and started launching other packages.
7763 if (!mSystemReady) {
7764 try {
7765 ActivityThread.getPackageManager().enterSafeMode();
7766 } catch (RemoteException e) {
7767 }
7768
7769 View v = LayoutInflater.from(mContext).inflate(
7770 com.android.internal.R.layout.safe_mode, null);
7771 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7772 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7773 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7774 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7775 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7776 lp.format = v.getBackground().getOpacity();
7777 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7778 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7779 ((WindowManager)mContext.getSystemService(
7780 Context.WINDOW_SERVICE)).addView(v, lp);
7781 }
7782 }
7783 }
7784
7785 public void noteWakeupAlarm(IIntentSender sender) {
7786 if (!(sender instanceof PendingIntentRecord)) {
7787 return;
7788 }
7789 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7790 synchronized (stats) {
7791 if (mBatteryStatsService.isOnBattery()) {
7792 mBatteryStatsService.enforceCallingPermission();
7793 PendingIntentRecord rec = (PendingIntentRecord)sender;
7794 int MY_UID = Binder.getCallingUid();
7795 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7796 BatteryStatsImpl.Uid.Pkg pkg =
7797 stats.getPackageStatsLocked(uid, rec.key.packageName);
7798 pkg.incWakeupsLocked();
7799 }
7800 }
7801 }
7802
7803 public boolean killPidsForMemory(int[] pids) {
7804 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7805 throw new SecurityException("killPidsForMemory only available to the system");
7806 }
7807
7808 // XXX Note: don't acquire main activity lock here, because the window
7809 // manager calls in with its locks held.
7810
7811 boolean killed = false;
7812 synchronized (mPidsSelfLocked) {
7813 int[] types = new int[pids.length];
7814 int worstType = 0;
7815 for (int i=0; i<pids.length; i++) {
7816 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7817 if (proc != null) {
7818 int type = proc.setAdj;
7819 types[i] = type;
7820 if (type > worstType) {
7821 worstType = type;
7822 }
7823 }
7824 }
7825
7826 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7827 // then constrain it so we will kill all hidden procs.
7828 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7829 worstType = HIDDEN_APP_MIN_ADJ;
7830 }
7831 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7832 for (int i=0; i<pids.length; i++) {
7833 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7834 if (proc == null) {
7835 continue;
7836 }
7837 int adj = proc.setAdj;
7838 if (adj >= worstType) {
7839 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7840 + adj + ")");
7841 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7842 proc.processName, adj);
7843 killed = true;
7844 Process.killProcess(pids[i]);
7845 }
7846 }
7847 }
7848 return killed;
7849 }
7850
7851 public void reportPss(IApplicationThread caller, int pss) {
7852 Watchdog.PssRequestor req;
7853 String name;
7854 ProcessRecord callerApp;
7855 synchronized (this) {
7856 if (caller == null) {
7857 return;
7858 }
7859 callerApp = getRecordForAppLocked(caller);
7860 if (callerApp == null) {
7861 return;
7862 }
7863 callerApp.lastPss = pss;
7864 req = callerApp;
7865 name = callerApp.processName;
7866 }
7867 Watchdog.getInstance().reportPss(req, name, pss);
7868 if (!callerApp.persistent) {
7869 removeRequestedPss(callerApp);
7870 }
7871 }
7872
7873 public void requestPss(Runnable completeCallback) {
7874 ArrayList<ProcessRecord> procs;
7875 synchronized (this) {
7876 mRequestPssCallback = completeCallback;
7877 mRequestPssList.clear();
7878 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7879 ProcessRecord proc = mLRUProcesses.get(i);
7880 if (!proc.persistent) {
7881 mRequestPssList.add(proc);
7882 }
7883 }
7884 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7885 }
7886
7887 int oldPri = Process.getThreadPriority(Process.myTid());
7888 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7889 for (int i=procs.size()-1; i>=0; i--) {
7890 ProcessRecord proc = procs.get(i);
7891 proc.lastPss = 0;
7892 proc.requestPss();
7893 }
7894 Process.setThreadPriority(oldPri);
7895 }
7896
7897 void removeRequestedPss(ProcessRecord proc) {
7898 Runnable callback = null;
7899 synchronized (this) {
7900 if (mRequestPssList.remove(proc)) {
7901 if (mRequestPssList.size() == 0) {
7902 callback = mRequestPssCallback;
7903 mRequestPssCallback = null;
7904 }
7905 }
7906 }
7907
7908 if (callback != null) {
7909 callback.run();
7910 }
7911 }
7912
7913 public void collectPss(Watchdog.PssStats stats) {
7914 stats.mEmptyPss = 0;
7915 stats.mEmptyCount = 0;
7916 stats.mBackgroundPss = 0;
7917 stats.mBackgroundCount = 0;
7918 stats.mServicePss = 0;
7919 stats.mServiceCount = 0;
7920 stats.mVisiblePss = 0;
7921 stats.mVisibleCount = 0;
7922 stats.mForegroundPss = 0;
7923 stats.mForegroundCount = 0;
7924 stats.mNoPssCount = 0;
7925 synchronized (this) {
7926 int i;
7927 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7928 ? mProcDeaths.length : stats.mProcDeaths.length;
7929 int aggr = 0;
7930 for (i=0; i<NPD; i++) {
7931 aggr += mProcDeaths[i];
7932 stats.mProcDeaths[i] = aggr;
7933 }
7934 while (i<stats.mProcDeaths.length) {
7935 stats.mProcDeaths[i] = 0;
7936 i++;
7937 }
7938
7939 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7940 ProcessRecord proc = mLRUProcesses.get(i);
7941 if (proc.persistent) {
7942 continue;
7943 }
7944 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7945 if (proc.lastPss == 0) {
7946 stats.mNoPssCount++;
7947 continue;
7948 }
7949 if (proc.setAdj == EMPTY_APP_ADJ) {
7950 stats.mEmptyPss += proc.lastPss;
7951 stats.mEmptyCount++;
7952 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7953 stats.mEmptyPss += proc.lastPss;
7954 stats.mEmptyCount++;
7955 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7956 stats.mBackgroundPss += proc.lastPss;
7957 stats.mBackgroundCount++;
7958 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7959 stats.mVisiblePss += proc.lastPss;
7960 stats.mVisibleCount++;
7961 } else {
7962 stats.mForegroundPss += proc.lastPss;
7963 stats.mForegroundCount++;
7964 }
7965 }
7966 }
7967 }
7968
7969 public final void startRunning(String pkg, String cls, String action,
7970 String data) {
7971 synchronized(this) {
7972 if (mStartRunning) {
7973 return;
7974 }
7975 mStartRunning = true;
7976 mTopComponent = pkg != null && cls != null
7977 ? new ComponentName(pkg, cls) : null;
7978 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7979 mTopData = data;
7980 if (!mSystemReady) {
7981 return;
7982 }
7983 }
7984
7985 systemReady();
7986 }
7987
7988 private void retrieveSettings() {
7989 final ContentResolver resolver = mContext.getContentResolver();
7990 String debugApp = Settings.System.getString(
7991 resolver, Settings.System.DEBUG_APP);
7992 boolean waitForDebugger = Settings.System.getInt(
7993 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7994 boolean alwaysFinishActivities = Settings.System.getInt(
7995 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7996
7997 Configuration configuration = new Configuration();
7998 Settings.System.getConfiguration(resolver, configuration);
7999
8000 synchronized (this) {
8001 mDebugApp = mOrigDebugApp = debugApp;
8002 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8003 mAlwaysFinishActivities = alwaysFinishActivities;
8004 // This happens before any activities are started, so we can
8005 // change mConfiguration in-place.
8006 mConfiguration.updateFrom(configuration);
8007 }
8008 }
8009
8010 public boolean testIsSystemReady() {
8011 // no need to synchronize(this) just to read & return the value
8012 return mSystemReady;
8013 }
8014
8015 public void systemReady() {
8016 // In the simulator, startRunning will never have been called, which
8017 // normally sets a few crucial variables. Do it here instead.
8018 if (!Process.supportsProcesses()) {
8019 mStartRunning = true;
8020 mTopAction = Intent.ACTION_MAIN;
8021 }
8022
8023 synchronized(this) {
8024 if (mSystemReady) {
8025 return;
8026 }
8027 mSystemReady = true;
8028 if (!mStartRunning) {
8029 return;
8030 }
8031 }
8032
8033 if (Config.LOGD) Log.d(TAG, "Start running!");
8034 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8035 SystemClock.uptimeMillis());
8036
8037 synchronized(this) {
8038 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8039 ResolveInfo ri = mContext.getPackageManager()
8040 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008041 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008042 CharSequence errorMsg = null;
8043 if (ri != null) {
8044 ActivityInfo ai = ri.activityInfo;
8045 ApplicationInfo app = ai.applicationInfo;
8046 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8047 mTopAction = Intent.ACTION_FACTORY_TEST;
8048 mTopData = null;
8049 mTopComponent = new ComponentName(app.packageName,
8050 ai.name);
8051 } else {
8052 errorMsg = mContext.getResources().getText(
8053 com.android.internal.R.string.factorytest_not_system);
8054 }
8055 } else {
8056 errorMsg = mContext.getResources().getText(
8057 com.android.internal.R.string.factorytest_no_action);
8058 }
8059 if (errorMsg != null) {
8060 mTopAction = null;
8061 mTopData = null;
8062 mTopComponent = null;
8063 Message msg = Message.obtain();
8064 msg.what = SHOW_FACTORY_ERROR_MSG;
8065 msg.getData().putCharSequence("msg", errorMsg);
8066 mHandler.sendMessage(msg);
8067 }
8068 }
8069 }
8070
8071 retrieveSettings();
8072
8073 synchronized (this) {
8074 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8075 try {
8076 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008077 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008078 if (apps != null) {
8079 int N = apps.size();
8080 int i;
8081 for (i=0; i<N; i++) {
8082 ApplicationInfo info
8083 = (ApplicationInfo)apps.get(i);
8084 if (info != null &&
8085 !info.packageName.equals("android")) {
8086 addAppLocked(info);
8087 }
8088 }
8089 }
8090 } catch (RemoteException ex) {
8091 // pm is in same process, this will never happen.
8092 }
8093 }
8094
8095 try {
8096 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8097 Message msg = Message.obtain();
8098 msg.what = SHOW_UID_ERROR_MSG;
8099 mHandler.sendMessage(msg);
8100 }
8101 } catch (RemoteException e) {
8102 }
8103
8104 // Start up initial activity.
8105 mBooting = true;
8106 resumeTopActivityLocked(null);
8107 }
8108 }
8109
8110 boolean makeAppCrashingLocked(ProcessRecord app,
8111 String tag, String shortMsg, String longMsg, byte[] crashData) {
8112 app.crashing = true;
8113 app.crashingReport = generateProcessError(app,
8114 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8115 startAppProblemLocked(app);
8116 app.stopFreezingAllLocked();
8117 return handleAppCrashLocked(app);
8118 }
8119
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008120 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8121 IPackageManager pm = ActivityThread.getPackageManager();
8122 try {
8123 // was an installer package name specified when this app was
8124 // installed?
8125 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8126 if (installerPackageName == null) {
8127 return null;
8128 }
8129
8130 // is there an Activity in this package that handles ACTION_APP_ERROR?
8131 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008132 intent.setPackage(installerPackageName);
8133 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008134 if (info == null || info.activityInfo == null) {
8135 return null;
8136 }
8137
8138 return new ComponentName(installerPackageName, info.activityInfo.name);
8139 } catch (RemoteException e) {
8140 // will return null and no error report will be delivered
8141 }
8142 return null;
8143 }
8144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008145 void makeAppNotRespondingLocked(ProcessRecord app,
8146 String tag, String shortMsg, String longMsg, byte[] crashData) {
8147 app.notResponding = true;
8148 app.notRespondingReport = generateProcessError(app,
8149 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8150 crashData);
8151 startAppProblemLocked(app);
8152 app.stopFreezingAllLocked();
8153 }
8154
8155 /**
8156 * Generate a process error record, suitable for attachment to a ProcessRecord.
8157 *
8158 * @param app The ProcessRecord in which the error occurred.
8159 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8160 * ActivityManager.AppErrorStateInfo
8161 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8162 * @param shortMsg Short message describing the crash.
8163 * @param longMsg Long message describing the crash.
8164 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8165 *
8166 * @return Returns a fully-formed AppErrorStateInfo record.
8167 */
8168 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8169 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8170 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8171
8172 report.condition = condition;
8173 report.processName = app.processName;
8174 report.pid = app.pid;
8175 report.uid = app.info.uid;
8176 report.tag = tag;
8177 report.shortMsg = shortMsg;
8178 report.longMsg = longMsg;
8179 report.crashData = crashData;
8180
8181 return report;
8182 }
8183
8184 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8185 boolean crashed) {
8186 synchronized (this) {
8187 app.crashing = false;
8188 app.crashingReport = null;
8189 app.notResponding = false;
8190 app.notRespondingReport = null;
8191 if (app.anrDialog == fromDialog) {
8192 app.anrDialog = null;
8193 }
8194 if (app.waitDialog == fromDialog) {
8195 app.waitDialog = null;
8196 }
8197 if (app.pid > 0 && app.pid != MY_PID) {
8198 if (crashed) {
8199 handleAppCrashLocked(app);
8200 }
8201 Log.i(ActivityManagerService.TAG, "Killing process "
8202 + app.processName
8203 + " (pid=" + app.pid + ") at user's request");
8204 Process.killProcess(app.pid);
8205 }
8206
8207 }
8208 }
8209
8210 boolean handleAppCrashLocked(ProcessRecord app) {
8211 long now = SystemClock.uptimeMillis();
8212
8213 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8214 app.info.uid);
8215 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8216 // This process loses!
8217 Log.w(TAG, "Process " + app.info.processName
8218 + " has crashed too many times: killing!");
8219 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8220 app.info.processName, app.info.uid);
8221 killServicesLocked(app, false);
8222 for (int i=mHistory.size()-1; i>=0; i--) {
8223 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8224 if (r.app == app) {
8225 if (Config.LOGD) Log.d(
8226 TAG, " Force finishing activity "
8227 + r.intent.getComponent().flattenToShortString());
8228 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8229 }
8230 }
8231 if (!app.persistent) {
8232 // We don't want to start this process again until the user
8233 // explicitly does so... but for persistent process, we really
8234 // need to keep it running. If a persistent process is actually
8235 // repeatedly crashing, then badness for everyone.
8236 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8237 app.info.processName);
8238 mBadProcesses.put(app.info.processName, app.info.uid, now);
8239 app.bad = true;
8240 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8241 app.removed = true;
8242 removeProcessLocked(app, false);
8243 return false;
8244 }
8245 }
8246
8247 // Bump up the crash count of any services currently running in the proc.
8248 if (app.services.size() != 0) {
8249 // Any services running in the application need to be placed
8250 // back in the pending list.
8251 Iterator it = app.services.iterator();
8252 while (it.hasNext()) {
8253 ServiceRecord sr = (ServiceRecord)it.next();
8254 sr.crashCount++;
8255 }
8256 }
8257
8258 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8259 return true;
8260 }
8261
8262 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008263 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008264 skipCurrentReceiverLocked(app);
8265 }
8266
8267 void skipCurrentReceiverLocked(ProcessRecord app) {
8268 boolean reschedule = false;
8269 BroadcastRecord r = app.curReceiver;
8270 if (r != null) {
8271 // The current broadcast is waiting for this app's receiver
8272 // to be finished. Looks like that's not going to happen, so
8273 // let the broadcast continue.
8274 logBroadcastReceiverDiscard(r);
8275 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8276 r.resultExtras, r.resultAbort, true);
8277 reschedule = true;
8278 }
8279 r = mPendingBroadcast;
8280 if (r != null && r.curApp == app) {
8281 if (DEBUG_BROADCAST) Log.v(TAG,
8282 "skip & discard pending app " + r);
8283 logBroadcastReceiverDiscard(r);
8284 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8285 r.resultExtras, r.resultAbort, true);
8286 reschedule = true;
8287 }
8288 if (reschedule) {
8289 scheduleBroadcastsLocked();
8290 }
8291 }
8292
8293 public int handleApplicationError(IBinder app, int flags,
8294 String tag, String shortMsg, String longMsg, byte[] crashData) {
8295 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008296 ProcessRecord r = null;
8297 synchronized (this) {
8298 if (app != null) {
8299 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8300 final int NA = apps.size();
8301 for (int ia=0; ia<NA; ia++) {
8302 ProcessRecord p = apps.valueAt(ia);
8303 if (p.thread != null && p.thread.asBinder() == app) {
8304 r = p;
8305 break;
8306 }
8307 }
8308 }
8309 }
8310
8311 if (r != null) {
8312 // The application has crashed. Send the SIGQUIT to the process so
8313 // that it can dump its state.
8314 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8315 //Log.i(TAG, "Current system threads:");
8316 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8317 }
8318
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008319 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008320 try {
8321 String name = r != null ? r.processName : null;
8322 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008323 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008324 shortMsg, longMsg, crashData)) {
8325 Log.w(TAG, "Force-killing crashed app " + name
8326 + " at watcher's request");
8327 Process.killProcess(pid);
8328 return 0;
8329 }
8330 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008331 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008332 }
8333 }
8334
8335 final long origId = Binder.clearCallingIdentity();
8336
8337 // If this process is running instrumentation, finish it.
8338 if (r != null && r.instrumentationClass != null) {
8339 Log.w(TAG, "Error in app " + r.processName
8340 + " running instrumentation " + r.instrumentationClass + ":");
8341 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8342 if (longMsg != null) Log.w(TAG, " " + longMsg);
8343 Bundle info = new Bundle();
8344 info.putString("shortMsg", shortMsg);
8345 info.putString("longMsg", longMsg);
8346 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8347 Binder.restoreCallingIdentity(origId);
8348 return 0;
8349 }
8350
8351 if (r != null) {
8352 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8353 return 0;
8354 }
8355 } else {
8356 Log.w(TAG, "Some application object " + app + " tag " + tag
8357 + " has crashed, but I don't know who it is.");
8358 Log.w(TAG, "ShortMsg:" + shortMsg);
8359 Log.w(TAG, "LongMsg:" + longMsg);
8360 Binder.restoreCallingIdentity(origId);
8361 return 0;
8362 }
8363
8364 Message msg = Message.obtain();
8365 msg.what = SHOW_ERROR_MSG;
8366 HashMap data = new HashMap();
8367 data.put("result", result);
8368 data.put("app", r);
8369 data.put("flags", flags);
8370 data.put("shortMsg", shortMsg);
8371 data.put("longMsg", longMsg);
8372 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8373 // For system processes, submit crash data to the server.
8374 data.put("crashData", crashData);
8375 }
8376 msg.obj = data;
8377 mHandler.sendMessage(msg);
8378
8379 Binder.restoreCallingIdentity(origId);
8380 }
8381
8382 int res = result.get();
8383
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008384 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008385 synchronized (this) {
8386 if (r != null) {
8387 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8388 SystemClock.uptimeMillis());
8389 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008390 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8391 appErrorIntent = createAppErrorIntentLocked(r);
8392 res = AppErrorDialog.FORCE_QUIT;
8393 }
8394 }
8395
8396 if (appErrorIntent != null) {
8397 try {
8398 mContext.startActivity(appErrorIntent);
8399 } catch (ActivityNotFoundException e) {
8400 Log.w(TAG, "bug report receiver dissappeared", e);
8401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008402 }
8403
8404 return res;
8405 }
8406
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008407 Intent createAppErrorIntentLocked(ProcessRecord r) {
8408 ApplicationErrorReport report = createAppErrorReportLocked(r);
8409 if (report == null) {
8410 return null;
8411 }
8412 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8413 result.setComponent(r.errorReportReceiver);
8414 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8415 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8416 return result;
8417 }
8418
8419 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8420 if (r.errorReportReceiver == null) {
8421 return null;
8422 }
8423
8424 if (!r.crashing && !r.notResponding) {
8425 return null;
8426 }
8427
8428 try {
8429 ApplicationErrorReport report = new ApplicationErrorReport();
8430 report.packageName = r.info.packageName;
8431 report.installerPackageName = r.errorReportReceiver.getPackageName();
8432 report.processName = r.processName;
8433
8434 if (r.crashing) {
8435 report.type = ApplicationErrorReport.TYPE_CRASH;
8436 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8437
8438 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8439 r.crashingReport.crashData);
8440 DataInputStream dataStream = new DataInputStream(byteStream);
8441 CrashData crashData = new CrashData(dataStream);
8442 ThrowableData throwData = crashData.getThrowableData();
8443
8444 report.time = crashData.getTime();
8445 report.crashInfo.stackTrace = throwData.toString();
8446
Jacek Surazskif829a782009-06-11 22:47:02 +02008447 // Extract the source of the exception, useful for report
8448 // clustering. Also extract the "deepest" non-null exception
8449 // message.
8450 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008451 while (throwData.getCause() != null) {
8452 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008453 String msg = throwData.getMessage();
8454 if (msg != null && msg.length() > 0) {
8455 exceptionMessage = msg;
8456 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008457 }
8458 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008459 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008460 report.crashInfo.exceptionClassName = throwData.getType();
8461 report.crashInfo.throwFileName = trace.getFileName();
8462 report.crashInfo.throwClassName = trace.getClassName();
8463 report.crashInfo.throwMethodName = trace.getMethodName();
8464 } else if (r.notResponding) {
8465 report.type = ApplicationErrorReport.TYPE_ANR;
8466 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8467
8468 report.anrInfo.activity = r.notRespondingReport.tag;
8469 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8470 report.anrInfo.info = r.notRespondingReport.longMsg;
8471 }
8472
8473 return report;
8474 } catch (IOException e) {
8475 // we don't send it
8476 }
8477
8478 return null;
8479 }
8480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008481 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8482 // assume our apps are happy - lazy create the list
8483 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8484
8485 synchronized (this) {
8486
8487 // iterate across all processes
8488 final int N = mLRUProcesses.size();
8489 for (int i = 0; i < N; i++) {
8490 ProcessRecord app = mLRUProcesses.get(i);
8491 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8492 // This one's in trouble, so we'll generate a report for it
8493 // crashes are higher priority (in case there's a crash *and* an anr)
8494 ActivityManager.ProcessErrorStateInfo report = null;
8495 if (app.crashing) {
8496 report = app.crashingReport;
8497 } else if (app.notResponding) {
8498 report = app.notRespondingReport;
8499 }
8500
8501 if (report != null) {
8502 if (errList == null) {
8503 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8504 }
8505 errList.add(report);
8506 } else {
8507 Log.w(TAG, "Missing app error report, app = " + app.processName +
8508 " crashing = " + app.crashing +
8509 " notResponding = " + app.notResponding);
8510 }
8511 }
8512 }
8513 }
8514
8515 return errList;
8516 }
8517
8518 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8519 // Lazy instantiation of list
8520 List<ActivityManager.RunningAppProcessInfo> runList = null;
8521 synchronized (this) {
8522 // Iterate across all processes
8523 final int N = mLRUProcesses.size();
8524 for (int i = 0; i < N; i++) {
8525 ProcessRecord app = mLRUProcesses.get(i);
8526 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8527 // Generate process state info for running application
8528 ActivityManager.RunningAppProcessInfo currApp =
8529 new ActivityManager.RunningAppProcessInfo(app.processName,
8530 app.pid, app.getPackageList());
8531 int adj = app.curAdj;
8532 if (adj >= CONTENT_PROVIDER_ADJ) {
8533 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8534 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8535 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008536 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8537 } else if (adj >= HOME_APP_ADJ) {
8538 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8539 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008540 } else if (adj >= SECONDARY_SERVER_ADJ) {
8541 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8542 } else if (adj >= VISIBLE_APP_ADJ) {
8543 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8544 } else {
8545 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8546 }
8547 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8548 // + " lru=" + currApp.lru);
8549 if (runList == null) {
8550 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8551 }
8552 runList.add(currApp);
8553 }
8554 }
8555 }
8556 return runList;
8557 }
8558
8559 @Override
8560 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8561 synchronized (this) {
8562 if (checkCallingPermission(android.Manifest.permission.DUMP)
8563 != PackageManager.PERMISSION_GRANTED) {
8564 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8565 + Binder.getCallingPid()
8566 + ", uid=" + Binder.getCallingUid()
8567 + " without permission "
8568 + android.Manifest.permission.DUMP);
8569 return;
8570 }
8571 if (args.length != 0 && "service".equals(args[0])) {
8572 dumpService(fd, pw, args);
8573 return;
8574 }
8575 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008576 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008577 pw.println(" ");
8578 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008579 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008580 if (mWaitingVisibleActivities.size() > 0) {
8581 pw.println(" ");
8582 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008583 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008584 }
8585 if (mStoppingActivities.size() > 0) {
8586 pw.println(" ");
8587 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008588 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008589 }
8590 if (mFinishingActivities.size() > 0) {
8591 pw.println(" ");
8592 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008593 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008594 }
8595
8596 pw.println(" ");
8597 pw.println(" mPausingActivity: " + mPausingActivity);
8598 pw.println(" mResumedActivity: " + mResumedActivity);
8599 pw.println(" mFocusedActivity: " + mFocusedActivity);
8600 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8601
8602 if (mRecentTasks.size() > 0) {
8603 pw.println(" ");
8604 pw.println("Recent tasks in Current Activity Manager State:");
8605
8606 final int N = mRecentTasks.size();
8607 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008608 TaskRecord tr = mRecentTasks.get(i);
8609 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8610 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008611 mRecentTasks.get(i).dump(pw, " ");
8612 }
8613 }
8614
8615 pw.println(" ");
8616 pw.println(" mCurTask: " + mCurTask);
8617
8618 pw.println(" ");
8619 pw.println("Processes in Current Activity Manager State:");
8620
8621 boolean needSep = false;
8622 int numPers = 0;
8623
8624 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8625 final int NA = procs.size();
8626 for (int ia=0; ia<NA; ia++) {
8627 if (!needSep) {
8628 pw.println(" All known processes:");
8629 needSep = true;
8630 }
8631 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008632 pw.print(r.persistent ? " *PERS*" : " *APP*");
8633 pw.print(" UID "); pw.print(procs.keyAt(ia));
8634 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008635 r.dump(pw, " ");
8636 if (r.persistent) {
8637 numPers++;
8638 }
8639 }
8640 }
8641
8642 if (mLRUProcesses.size() > 0) {
8643 if (needSep) pw.println(" ");
8644 needSep = true;
8645 pw.println(" Running processes (most recent first):");
8646 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008647 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648 needSep = true;
8649 }
8650
8651 synchronized (mPidsSelfLocked) {
8652 if (mPidsSelfLocked.size() > 0) {
8653 if (needSep) pw.println(" ");
8654 needSep = true;
8655 pw.println(" PID mappings:");
8656 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008657 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8658 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008659 }
8660 }
8661 }
8662
8663 if (mForegroundProcesses.size() > 0) {
8664 if (needSep) pw.println(" ");
8665 needSep = true;
8666 pw.println(" Foreground Processes:");
8667 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008668 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8669 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008670 }
8671 }
8672
8673 if (mPersistentStartingProcesses.size() > 0) {
8674 if (needSep) pw.println(" ");
8675 needSep = true;
8676 pw.println(" Persisent processes that are starting:");
8677 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008678 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008679 }
8680
8681 if (mStartingProcesses.size() > 0) {
8682 if (needSep) pw.println(" ");
8683 needSep = true;
8684 pw.println(" Processes that are starting:");
8685 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008686 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008687 }
8688
8689 if (mRemovedProcesses.size() > 0) {
8690 if (needSep) pw.println(" ");
8691 needSep = true;
8692 pw.println(" Processes that are being removed:");
8693 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008694 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008695 }
8696
8697 if (mProcessesOnHold.size() > 0) {
8698 if (needSep) pw.println(" ");
8699 needSep = true;
8700 pw.println(" Processes that are on old until the system is ready:");
8701 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008702 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008703 }
8704
8705 if (mProcessCrashTimes.getMap().size() > 0) {
8706 if (needSep) pw.println(" ");
8707 needSep = true;
8708 pw.println(" Time since processes crashed:");
8709 long now = SystemClock.uptimeMillis();
8710 for (Map.Entry<String, SparseArray<Long>> procs
8711 : mProcessCrashTimes.getMap().entrySet()) {
8712 SparseArray<Long> uids = procs.getValue();
8713 final int N = uids.size();
8714 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008715 pw.print(" Process "); pw.print(procs.getKey());
8716 pw.print(" uid "); pw.print(uids.keyAt(i));
8717 pw.print(": last crashed ");
8718 pw.print((now-uids.valueAt(i)));
8719 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008720 }
8721 }
8722 }
8723
8724 if (mBadProcesses.getMap().size() > 0) {
8725 if (needSep) pw.println(" ");
8726 needSep = true;
8727 pw.println(" Bad processes:");
8728 for (Map.Entry<String, SparseArray<Long>> procs
8729 : mBadProcesses.getMap().entrySet()) {
8730 SparseArray<Long> uids = procs.getValue();
8731 final int N = uids.size();
8732 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008733 pw.print(" Bad process "); pw.print(procs.getKey());
8734 pw.print(" uid "); pw.print(uids.keyAt(i));
8735 pw.print(": crashed at time ");
8736 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008737 }
8738 }
8739 }
8740
8741 pw.println(" ");
8742 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008743 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008744 pw.println(" mConfiguration: " + mConfiguration);
8745 pw.println(" mStartRunning=" + mStartRunning
8746 + " mSystemReady=" + mSystemReady
8747 + " mBooting=" + mBooting
8748 + " mBooted=" + mBooted
8749 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008750 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008751 pw.println(" mGoingToSleep=" + mGoingToSleep);
8752 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8753 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8754 + " mDebugTransient=" + mDebugTransient
8755 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8756 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008757 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008758 }
8759 }
8760
8761 /**
8762 * There are three ways to call this:
8763 * - no service specified: dump all the services
8764 * - a flattened component name that matched an existing service was specified as the
8765 * first arg: dump that one service
8766 * - the first arg isn't the flattened component name of an existing service:
8767 * dump all services whose component contains the first arg as a substring
8768 */
8769 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8770 String[] newArgs;
8771 String componentNameString;
8772 ServiceRecord r;
8773 if (args.length == 1) {
8774 componentNameString = null;
8775 newArgs = EMPTY_STRING_ARRAY;
8776 r = null;
8777 } else {
8778 componentNameString = args[1];
8779 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8780 r = componentName != null ? mServices.get(componentName) : null;
8781 newArgs = new String[args.length - 2];
8782 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8783 }
8784
8785 if (r != null) {
8786 dumpService(fd, pw, r, newArgs);
8787 } else {
8788 for (ServiceRecord r1 : mServices.values()) {
8789 if (componentNameString == null
8790 || r1.name.flattenToString().contains(componentNameString)) {
8791 dumpService(fd, pw, r1, newArgs);
8792 }
8793 }
8794 }
8795 }
8796
8797 /**
8798 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8799 * there is a thread associated with the service.
8800 */
8801 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8802 pw.println(" Service " + r.name.flattenToString());
8803 if (r.app != null && r.app.thread != null) {
8804 try {
8805 // flush anything that is already in the PrintWriter since the thread is going
8806 // to write to the file descriptor directly
8807 pw.flush();
8808 r.app.thread.dumpService(fd, r, args);
8809 pw.print("\n");
8810 } catch (RemoteException e) {
8811 pw.println("got a RemoteException while dumping the service");
8812 }
8813 }
8814 }
8815
8816 void dumpBroadcasts(PrintWriter pw) {
8817 synchronized (this) {
8818 if (checkCallingPermission(android.Manifest.permission.DUMP)
8819 != PackageManager.PERMISSION_GRANTED) {
8820 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8821 + Binder.getCallingPid()
8822 + ", uid=" + Binder.getCallingUid()
8823 + " without permission "
8824 + android.Manifest.permission.DUMP);
8825 return;
8826 }
8827 pw.println("Broadcasts in Current Activity Manager State:");
8828
8829 if (mRegisteredReceivers.size() > 0) {
8830 pw.println(" ");
8831 pw.println(" Registered Receivers:");
8832 Iterator it = mRegisteredReceivers.values().iterator();
8833 while (it.hasNext()) {
8834 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008835 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008836 r.dump(pw, " ");
8837 }
8838 }
8839
8840 pw.println(" ");
8841 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008842 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008843
8844 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8845 || mPendingBroadcast != null) {
8846 if (mParallelBroadcasts.size() > 0) {
8847 pw.println(" ");
8848 pw.println(" Active broadcasts:");
8849 }
8850 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8851 pw.println(" Broadcast #" + i + ":");
8852 mParallelBroadcasts.get(i).dump(pw, " ");
8853 }
8854 if (mOrderedBroadcasts.size() > 0) {
8855 pw.println(" ");
8856 pw.println(" Active serialized broadcasts:");
8857 }
8858 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8859 pw.println(" Serialized Broadcast #" + i + ":");
8860 mOrderedBroadcasts.get(i).dump(pw, " ");
8861 }
8862 pw.println(" ");
8863 pw.println(" Pending broadcast:");
8864 if (mPendingBroadcast != null) {
8865 mPendingBroadcast.dump(pw, " ");
8866 } else {
8867 pw.println(" (null)");
8868 }
8869 }
8870
8871 pw.println(" ");
8872 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8873 if (mStickyBroadcasts != null) {
8874 pw.println(" ");
8875 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008876 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008877 for (Map.Entry<String, ArrayList<Intent>> ent
8878 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008879 pw.print(" * Sticky action "); pw.print(ent.getKey());
8880 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008881 ArrayList<Intent> intents = ent.getValue();
8882 final int N = intents.size();
8883 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008884 sb.setLength(0);
8885 sb.append(" Intent: ");
8886 intents.get(i).toShortString(sb, true, false);
8887 pw.println(sb.toString());
8888 Bundle bundle = intents.get(i).getExtras();
8889 if (bundle != null) {
8890 pw.print(" ");
8891 pw.println(bundle.toString());
8892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008893 }
8894 }
8895 }
8896
8897 pw.println(" ");
8898 pw.println(" mHandler:");
8899 mHandler.dump(new PrintWriterPrinter(pw), " ");
8900 }
8901 }
8902
8903 void dumpServices(PrintWriter pw) {
8904 synchronized (this) {
8905 if (checkCallingPermission(android.Manifest.permission.DUMP)
8906 != PackageManager.PERMISSION_GRANTED) {
8907 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8908 + Binder.getCallingPid()
8909 + ", uid=" + Binder.getCallingUid()
8910 + " without permission "
8911 + android.Manifest.permission.DUMP);
8912 return;
8913 }
8914 pw.println("Services in Current Activity Manager State:");
8915
8916 boolean needSep = false;
8917
8918 if (mServices.size() > 0) {
8919 pw.println(" Active services:");
8920 Iterator<ServiceRecord> it = mServices.values().iterator();
8921 while (it.hasNext()) {
8922 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008923 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008924 r.dump(pw, " ");
8925 }
8926 needSep = true;
8927 }
8928
8929 if (mPendingServices.size() > 0) {
8930 if (needSep) pw.println(" ");
8931 pw.println(" Pending services:");
8932 for (int i=0; i<mPendingServices.size(); i++) {
8933 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008934 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008935 r.dump(pw, " ");
8936 }
8937 needSep = true;
8938 }
8939
8940 if (mRestartingServices.size() > 0) {
8941 if (needSep) pw.println(" ");
8942 pw.println(" Restarting services:");
8943 for (int i=0; i<mRestartingServices.size(); i++) {
8944 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008945 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008946 r.dump(pw, " ");
8947 }
8948 needSep = true;
8949 }
8950
8951 if (mStoppingServices.size() > 0) {
8952 if (needSep) pw.println(" ");
8953 pw.println(" Stopping services:");
8954 for (int i=0; i<mStoppingServices.size(); i++) {
8955 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008956 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008957 r.dump(pw, " ");
8958 }
8959 needSep = true;
8960 }
8961
8962 if (mServiceConnections.size() > 0) {
8963 if (needSep) pw.println(" ");
8964 pw.println(" Connection bindings to services:");
8965 Iterator<ConnectionRecord> it
8966 = mServiceConnections.values().iterator();
8967 while (it.hasNext()) {
8968 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008969 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 r.dump(pw, " ");
8971 }
8972 }
8973 }
8974 }
8975
8976 void dumpProviders(PrintWriter pw) {
8977 synchronized (this) {
8978 if (checkCallingPermission(android.Manifest.permission.DUMP)
8979 != PackageManager.PERMISSION_GRANTED) {
8980 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8981 + Binder.getCallingPid()
8982 + ", uid=" + Binder.getCallingUid()
8983 + " without permission "
8984 + android.Manifest.permission.DUMP);
8985 return;
8986 }
8987
8988 pw.println("Content Providers in Current Activity Manager State:");
8989
8990 boolean needSep = false;
8991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008992 if (mProvidersByClass.size() > 0) {
8993 if (needSep) pw.println(" ");
8994 pw.println(" Published content providers (by class):");
8995 Iterator it = mProvidersByClass.entrySet().iterator();
8996 while (it.hasNext()) {
8997 Map.Entry e = (Map.Entry)it.next();
8998 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008999 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009000 r.dump(pw, " ");
9001 }
9002 needSep = true;
9003 }
9004
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009005 if (mProvidersByName.size() > 0) {
9006 pw.println(" ");
9007 pw.println(" Authority to provider mappings:");
9008 Iterator it = mProvidersByName.entrySet().iterator();
9009 while (it.hasNext()) {
9010 Map.Entry e = (Map.Entry)it.next();
9011 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9012 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9013 pw.println(r);
9014 }
9015 needSep = true;
9016 }
9017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 if (mLaunchingProviders.size() > 0) {
9019 if (needSep) pw.println(" ");
9020 pw.println(" Launching content providers:");
9021 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009022 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9023 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024 }
9025 needSep = true;
9026 }
9027
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009028 if (mGrantedUriPermissions.size() > 0) {
9029 pw.println();
9030 pw.println("Granted Uri Permissions:");
9031 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9032 int uid = mGrantedUriPermissions.keyAt(i);
9033 HashMap<Uri, UriPermission> perms
9034 = mGrantedUriPermissions.valueAt(i);
9035 pw.print(" * UID "); pw.print(uid);
9036 pw.println(" holds:");
9037 for (UriPermission perm : perms.values()) {
9038 pw.print(" "); pw.println(perm);
9039 perm.dump(pw, " ");
9040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009041 }
9042 }
9043 }
9044 }
9045
9046 void dumpSenders(PrintWriter pw) {
9047 synchronized (this) {
9048 if (checkCallingPermission(android.Manifest.permission.DUMP)
9049 != PackageManager.PERMISSION_GRANTED) {
9050 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9051 + Binder.getCallingPid()
9052 + ", uid=" + Binder.getCallingUid()
9053 + " without permission "
9054 + android.Manifest.permission.DUMP);
9055 return;
9056 }
9057
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009058 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009059
9060 if (this.mIntentSenderRecords.size() > 0) {
9061 Iterator<WeakReference<PendingIntentRecord>> it
9062 = mIntentSenderRecords.values().iterator();
9063 while (it.hasNext()) {
9064 WeakReference<PendingIntentRecord> ref = it.next();
9065 PendingIntentRecord rec = ref != null ? ref.get(): null;
9066 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009067 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 rec.dump(pw, " ");
9069 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009070 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 }
9072 }
9073 }
9074 }
9075 }
9076
9077 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009078 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009079 TaskRecord lastTask = null;
9080 for (int i=list.size()-1; i>=0; i--) {
9081 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009082 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009083 if (lastTask != r.task) {
9084 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009085 pw.print(prefix);
9086 pw.print(full ? "* " : " ");
9087 pw.println(lastTask);
9088 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009089 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009091 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009092 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9093 pw.print(" #"); pw.print(i); pw.print(": ");
9094 pw.println(r);
9095 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009096 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009098 }
9099 }
9100
9101 private static final int dumpProcessList(PrintWriter pw, List list,
9102 String prefix, String normalLabel, String persistentLabel,
9103 boolean inclOomAdj) {
9104 int numPers = 0;
9105 for (int i=list.size()-1; i>=0; i--) {
9106 ProcessRecord r = (ProcessRecord)list.get(i);
9107 if (false) {
9108 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9109 + " #" + i + ":");
9110 r.dump(pw, prefix + " ");
9111 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009112 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009113 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009114 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009115 } else {
9116 pw.println(String.format("%s%s #%2d: %s",
9117 prefix, (r.persistent ? persistentLabel : normalLabel),
9118 i, r.toString()));
9119 }
9120 if (r.persistent) {
9121 numPers++;
9122 }
9123 }
9124 return numPers;
9125 }
9126
9127 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9128 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009129 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009130 long uptime = SystemClock.uptimeMillis();
9131 long realtime = SystemClock.elapsedRealtime();
9132
9133 if (isCheckinRequest) {
9134 // short checkin version
9135 pw.println(uptime + "," + realtime);
9136 pw.flush();
9137 } else {
9138 pw.println("Applications Memory Usage (kB):");
9139 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9140 }
9141 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9142 ProcessRecord r = (ProcessRecord)list.get(i);
9143 if (r.thread != null) {
9144 if (!isCheckinRequest) {
9145 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9146 pw.flush();
9147 }
9148 try {
9149 r.thread.asBinder().dump(fd, args);
9150 } catch (RemoteException e) {
9151 if (!isCheckinRequest) {
9152 pw.println("Got RemoteException!");
9153 pw.flush();
9154 }
9155 }
9156 }
9157 }
9158 }
9159
9160 /**
9161 * Searches array of arguments for the specified string
9162 * @param args array of argument strings
9163 * @param value value to search for
9164 * @return true if the value is contained in the array
9165 */
9166 private static boolean scanArgs(String[] args, String value) {
9167 if (args != null) {
9168 for (String arg : args) {
9169 if (value.equals(arg)) {
9170 return true;
9171 }
9172 }
9173 }
9174 return false;
9175 }
9176
Dianne Hackborn75b03852009-06-12 15:43:26 -07009177 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009178 int count = mHistory.size();
9179
9180 // convert the token to an entry in the history.
9181 HistoryRecord r = null;
9182 int index = -1;
9183 for (int i=count-1; i>=0; i--) {
9184 Object o = mHistory.get(i);
9185 if (o == token) {
9186 r = (HistoryRecord)o;
9187 index = i;
9188 break;
9189 }
9190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191
9192 return index;
9193 }
9194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009195 private final void killServicesLocked(ProcessRecord app,
9196 boolean allowRestart) {
9197 // Report disconnected services.
9198 if (false) {
9199 // XXX we are letting the client link to the service for
9200 // death notifications.
9201 if (app.services.size() > 0) {
9202 Iterator it = app.services.iterator();
9203 while (it.hasNext()) {
9204 ServiceRecord r = (ServiceRecord)it.next();
9205 if (r.connections.size() > 0) {
9206 Iterator<ConnectionRecord> jt
9207 = r.connections.values().iterator();
9208 while (jt.hasNext()) {
9209 ConnectionRecord c = jt.next();
9210 if (c.binding.client != app) {
9211 try {
9212 //c.conn.connected(r.className, null);
9213 } catch (Exception e) {
9214 // todo: this should be asynchronous!
9215 Log.w(TAG, "Exception thrown disconnected servce "
9216 + r.shortName
9217 + " from app " + app.processName, e);
9218 }
9219 }
9220 }
9221 }
9222 }
9223 }
9224 }
9225
9226 // Clean up any connections this application has to other services.
9227 if (app.connections.size() > 0) {
9228 Iterator<ConnectionRecord> it = app.connections.iterator();
9229 while (it.hasNext()) {
9230 ConnectionRecord r = it.next();
9231 removeConnectionLocked(r, app, null);
9232 }
9233 }
9234 app.connections.clear();
9235
9236 if (app.services.size() != 0) {
9237 // Any services running in the application need to be placed
9238 // back in the pending list.
9239 Iterator it = app.services.iterator();
9240 while (it.hasNext()) {
9241 ServiceRecord sr = (ServiceRecord)it.next();
9242 synchronized (sr.stats.getBatteryStats()) {
9243 sr.stats.stopLaunchedLocked();
9244 }
9245 sr.app = null;
9246 sr.executeNesting = 0;
9247 mStoppingServices.remove(sr);
9248 if (sr.bindings.size() > 0) {
9249 Iterator<IntentBindRecord> bindings
9250 = sr.bindings.values().iterator();
9251 while (bindings.hasNext()) {
9252 IntentBindRecord b = bindings.next();
9253 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9254 + ": shouldUnbind=" + b.hasBound);
9255 b.binder = null;
9256 b.requested = b.received = b.hasBound = false;
9257 }
9258 }
9259
9260 if (sr.crashCount >= 2) {
9261 Log.w(TAG, "Service crashed " + sr.crashCount
9262 + " times, stopping: " + sr);
9263 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9264 sr.crashCount, sr.shortName, app.pid);
9265 bringDownServiceLocked(sr, true);
9266 } else if (!allowRestart) {
9267 bringDownServiceLocked(sr, true);
9268 } else {
9269 scheduleServiceRestartLocked(sr);
9270 }
9271 }
9272
9273 if (!allowRestart) {
9274 app.services.clear();
9275 }
9276 }
9277
9278 app.executingServices.clear();
9279 }
9280
9281 private final void removeDyingProviderLocked(ProcessRecord proc,
9282 ContentProviderRecord cpr) {
9283 synchronized (cpr) {
9284 cpr.launchingApp = null;
9285 cpr.notifyAll();
9286 }
9287
9288 mProvidersByClass.remove(cpr.info.name);
9289 String names[] = cpr.info.authority.split(";");
9290 for (int j = 0; j < names.length; j++) {
9291 mProvidersByName.remove(names[j]);
9292 }
9293
9294 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9295 while (cit.hasNext()) {
9296 ProcessRecord capp = cit.next();
9297 if (!capp.persistent && capp.thread != null
9298 && capp.pid != 0
9299 && capp.pid != MY_PID) {
9300 Log.i(TAG, "Killing app " + capp.processName
9301 + " (pid " + capp.pid
9302 + ") because provider " + cpr.info.name
9303 + " is in dying process " + proc.processName);
9304 Process.killProcess(capp.pid);
9305 }
9306 }
9307
9308 mLaunchingProviders.remove(cpr);
9309 }
9310
9311 /**
9312 * Main code for cleaning up a process when it has gone away. This is
9313 * called both as a result of the process dying, or directly when stopping
9314 * a process when running in single process mode.
9315 */
9316 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9317 boolean restarting, int index) {
9318 if (index >= 0) {
9319 mLRUProcesses.remove(index);
9320 }
9321
9322 // Dismiss any open dialogs.
9323 if (app.crashDialog != null) {
9324 app.crashDialog.dismiss();
9325 app.crashDialog = null;
9326 }
9327 if (app.anrDialog != null) {
9328 app.anrDialog.dismiss();
9329 app.anrDialog = null;
9330 }
9331 if (app.waitDialog != null) {
9332 app.waitDialog.dismiss();
9333 app.waitDialog = null;
9334 }
9335
9336 app.crashing = false;
9337 app.notResponding = false;
9338
9339 app.resetPackageList();
9340 app.thread = null;
9341 app.forcingToForeground = null;
9342 app.foregroundServices = false;
9343
9344 killServicesLocked(app, true);
9345
9346 boolean restart = false;
9347
9348 int NL = mLaunchingProviders.size();
9349
9350 // Remove published content providers.
9351 if (!app.pubProviders.isEmpty()) {
9352 Iterator it = app.pubProviders.values().iterator();
9353 while (it.hasNext()) {
9354 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9355 cpr.provider = null;
9356 cpr.app = null;
9357
9358 // See if someone is waiting for this provider... in which
9359 // case we don't remove it, but just let it restart.
9360 int i = 0;
9361 if (!app.bad) {
9362 for (; i<NL; i++) {
9363 if (mLaunchingProviders.get(i) == cpr) {
9364 restart = true;
9365 break;
9366 }
9367 }
9368 } else {
9369 i = NL;
9370 }
9371
9372 if (i >= NL) {
9373 removeDyingProviderLocked(app, cpr);
9374 NL = mLaunchingProviders.size();
9375 }
9376 }
9377 app.pubProviders.clear();
9378 }
9379
9380 // Look through the content providers we are waiting to have launched,
9381 // and if any run in this process then either schedule a restart of
9382 // the process or kill the client waiting for it if this process has
9383 // gone bad.
9384 for (int i=0; i<NL; i++) {
9385 ContentProviderRecord cpr = (ContentProviderRecord)
9386 mLaunchingProviders.get(i);
9387 if (cpr.launchingApp == app) {
9388 if (!app.bad) {
9389 restart = true;
9390 } else {
9391 removeDyingProviderLocked(app, cpr);
9392 NL = mLaunchingProviders.size();
9393 }
9394 }
9395 }
9396
9397 // Unregister from connected content providers.
9398 if (!app.conProviders.isEmpty()) {
9399 Iterator it = app.conProviders.iterator();
9400 while (it.hasNext()) {
9401 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9402 cpr.clients.remove(app);
9403 }
9404 app.conProviders.clear();
9405 }
9406
9407 skipCurrentReceiverLocked(app);
9408
9409 // Unregister any receivers.
9410 if (app.receivers.size() > 0) {
9411 Iterator<ReceiverList> it = app.receivers.iterator();
9412 while (it.hasNext()) {
9413 removeReceiverLocked(it.next());
9414 }
9415 app.receivers.clear();
9416 }
9417
Christopher Tate181fafa2009-05-14 11:12:14 -07009418 // If the app is undergoing backup, tell the backup manager about it
9419 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9420 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9421 try {
9422 IBackupManager bm = IBackupManager.Stub.asInterface(
9423 ServiceManager.getService(Context.BACKUP_SERVICE));
9424 bm.agentDisconnected(app.info.packageName);
9425 } catch (RemoteException e) {
9426 // can't happen; backup manager is local
9427 }
9428 }
9429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009430 // If the caller is restarting this app, then leave it in its
9431 // current lists and let the caller take care of it.
9432 if (restarting) {
9433 return;
9434 }
9435
9436 if (!app.persistent) {
9437 if (DEBUG_PROCESSES) Log.v(TAG,
9438 "Removing non-persistent process during cleanup: " + app);
9439 mProcessNames.remove(app.processName, app.info.uid);
9440 } else if (!app.removed) {
9441 // This app is persistent, so we need to keep its record around.
9442 // If it is not already on the pending app list, add it there
9443 // and start a new process for it.
9444 app.thread = null;
9445 app.forcingToForeground = null;
9446 app.foregroundServices = false;
9447 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9448 mPersistentStartingProcesses.add(app);
9449 restart = true;
9450 }
9451 }
9452 mProcessesOnHold.remove(app);
9453
The Android Open Source Project4df24232009-03-05 14:34:35 -08009454 if (app == mHomeProcess) {
9455 mHomeProcess = null;
9456 }
9457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009458 if (restart) {
9459 // We have components that still need to be running in the
9460 // process, so re-launch it.
9461 mProcessNames.put(app.processName, app.info.uid, app);
9462 startProcessLocked(app, "restart", app.processName);
9463 } else if (app.pid > 0 && app.pid != MY_PID) {
9464 // Goodbye!
9465 synchronized (mPidsSelfLocked) {
9466 mPidsSelfLocked.remove(app.pid);
9467 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9468 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009469 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009470 }
9471 }
9472
9473 // =========================================================
9474 // SERVICES
9475 // =========================================================
9476
9477 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9478 ActivityManager.RunningServiceInfo info =
9479 new ActivityManager.RunningServiceInfo();
9480 info.service = r.name;
9481 if (r.app != null) {
9482 info.pid = r.app.pid;
9483 }
9484 info.process = r.processName;
9485 info.foreground = r.isForeground;
9486 info.activeSince = r.createTime;
9487 info.started = r.startRequested;
9488 info.clientCount = r.connections.size();
9489 info.crashCount = r.crashCount;
9490 info.lastActivityTime = r.lastActivity;
9491 return info;
9492 }
9493
9494 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9495 int flags) {
9496 synchronized (this) {
9497 ArrayList<ActivityManager.RunningServiceInfo> res
9498 = new ArrayList<ActivityManager.RunningServiceInfo>();
9499
9500 if (mServices.size() > 0) {
9501 Iterator<ServiceRecord> it = mServices.values().iterator();
9502 while (it.hasNext() && res.size() < maxNum) {
9503 res.add(makeRunningServiceInfoLocked(it.next()));
9504 }
9505 }
9506
9507 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9508 ServiceRecord r = mRestartingServices.get(i);
9509 ActivityManager.RunningServiceInfo info =
9510 makeRunningServiceInfoLocked(r);
9511 info.restarting = r.nextRestartTime;
9512 res.add(info);
9513 }
9514
9515 return res;
9516 }
9517 }
9518
9519 private final ServiceRecord findServiceLocked(ComponentName name,
9520 IBinder token) {
9521 ServiceRecord r = mServices.get(name);
9522 return r == token ? r : null;
9523 }
9524
9525 private final class ServiceLookupResult {
9526 final ServiceRecord record;
9527 final String permission;
9528
9529 ServiceLookupResult(ServiceRecord _record, String _permission) {
9530 record = _record;
9531 permission = _permission;
9532 }
9533 };
9534
9535 private ServiceLookupResult findServiceLocked(Intent service,
9536 String resolvedType) {
9537 ServiceRecord r = null;
9538 if (service.getComponent() != null) {
9539 r = mServices.get(service.getComponent());
9540 }
9541 if (r == null) {
9542 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9543 r = mServicesByIntent.get(filter);
9544 }
9545
9546 if (r == null) {
9547 try {
9548 ResolveInfo rInfo =
9549 ActivityThread.getPackageManager().resolveService(
9550 service, resolvedType, 0);
9551 ServiceInfo sInfo =
9552 rInfo != null ? rInfo.serviceInfo : null;
9553 if (sInfo == null) {
9554 return null;
9555 }
9556
9557 ComponentName name = new ComponentName(
9558 sInfo.applicationInfo.packageName, sInfo.name);
9559 r = mServices.get(name);
9560 } catch (RemoteException ex) {
9561 // pm is in same process, this will never happen.
9562 }
9563 }
9564 if (r != null) {
9565 int callingPid = Binder.getCallingPid();
9566 int callingUid = Binder.getCallingUid();
9567 if (checkComponentPermission(r.permission,
9568 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9569 != PackageManager.PERMISSION_GRANTED) {
9570 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9571 + " from pid=" + callingPid
9572 + ", uid=" + callingUid
9573 + " requires " + r.permission);
9574 return new ServiceLookupResult(null, r.permission);
9575 }
9576 return new ServiceLookupResult(r, null);
9577 }
9578 return null;
9579 }
9580
9581 private class ServiceRestarter implements Runnable {
9582 private ServiceRecord mService;
9583
9584 void setService(ServiceRecord service) {
9585 mService = service;
9586 }
9587
9588 public void run() {
9589 synchronized(ActivityManagerService.this) {
9590 performServiceRestartLocked(mService);
9591 }
9592 }
9593 }
9594
9595 private ServiceLookupResult retrieveServiceLocked(Intent service,
9596 String resolvedType, int callingPid, int callingUid) {
9597 ServiceRecord r = null;
9598 if (service.getComponent() != null) {
9599 r = mServices.get(service.getComponent());
9600 }
9601 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9602 r = mServicesByIntent.get(filter);
9603 if (r == null) {
9604 try {
9605 ResolveInfo rInfo =
9606 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009607 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009608 ServiceInfo sInfo =
9609 rInfo != null ? rInfo.serviceInfo : null;
9610 if (sInfo == null) {
9611 Log.w(TAG, "Unable to start service " + service +
9612 ": not found");
9613 return null;
9614 }
9615
9616 ComponentName name = new ComponentName(
9617 sInfo.applicationInfo.packageName, sInfo.name);
9618 r = mServices.get(name);
9619 if (r == null) {
9620 filter = new Intent.FilterComparison(service.cloneFilter());
9621 ServiceRestarter res = new ServiceRestarter();
9622 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9623 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9624 synchronized (stats) {
9625 ss = stats.getServiceStatsLocked(
9626 sInfo.applicationInfo.uid, sInfo.packageName,
9627 sInfo.name);
9628 }
9629 r = new ServiceRecord(ss, name, filter, sInfo, res);
9630 res.setService(r);
9631 mServices.put(name, r);
9632 mServicesByIntent.put(filter, r);
9633
9634 // Make sure this component isn't in the pending list.
9635 int N = mPendingServices.size();
9636 for (int i=0; i<N; i++) {
9637 ServiceRecord pr = mPendingServices.get(i);
9638 if (pr.name.equals(name)) {
9639 mPendingServices.remove(i);
9640 i--;
9641 N--;
9642 }
9643 }
9644 }
9645 } catch (RemoteException ex) {
9646 // pm is in same process, this will never happen.
9647 }
9648 }
9649 if (r != null) {
9650 if (checkComponentPermission(r.permission,
9651 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9652 != PackageManager.PERMISSION_GRANTED) {
9653 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9654 + " from pid=" + Binder.getCallingPid()
9655 + ", uid=" + Binder.getCallingUid()
9656 + " requires " + r.permission);
9657 return new ServiceLookupResult(null, r.permission);
9658 }
9659 return new ServiceLookupResult(r, null);
9660 }
9661 return null;
9662 }
9663
9664 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9665 long now = SystemClock.uptimeMillis();
9666 if (r.executeNesting == 0 && r.app != null) {
9667 if (r.app.executingServices.size() == 0) {
9668 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9669 msg.obj = r.app;
9670 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9671 }
9672 r.app.executingServices.add(r);
9673 }
9674 r.executeNesting++;
9675 r.executingStart = now;
9676 }
9677
9678 private final void sendServiceArgsLocked(ServiceRecord r,
9679 boolean oomAdjusted) {
9680 final int N = r.startArgs.size();
9681 if (N == 0) {
9682 return;
9683 }
9684
9685 final int BASEID = r.lastStartId - N + 1;
9686 int i = 0;
9687 while (i < N) {
9688 try {
9689 Intent args = r.startArgs.get(i);
9690 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9691 + r.name + " " + r.intent + " args=" + args);
9692 bumpServiceExecutingLocked(r);
9693 if (!oomAdjusted) {
9694 oomAdjusted = true;
9695 updateOomAdjLocked(r.app);
9696 }
9697 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9698 i++;
9699 } catch (Exception e) {
9700 break;
9701 }
9702 }
9703 if (i == N) {
9704 r.startArgs.clear();
9705 } else {
9706 while (i > 0) {
9707 r.startArgs.remove(0);
9708 i--;
9709 }
9710 }
9711 }
9712
9713 private final boolean requestServiceBindingLocked(ServiceRecord r,
9714 IntentBindRecord i, boolean rebind) {
9715 if (r.app == null || r.app.thread == null) {
9716 // If service is not currently running, can't yet bind.
9717 return false;
9718 }
9719 if ((!i.requested || rebind) && i.apps.size() > 0) {
9720 try {
9721 bumpServiceExecutingLocked(r);
9722 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9723 + ": shouldUnbind=" + i.hasBound);
9724 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9725 if (!rebind) {
9726 i.requested = true;
9727 }
9728 i.hasBound = true;
9729 i.doRebind = false;
9730 } catch (RemoteException e) {
9731 return false;
9732 }
9733 }
9734 return true;
9735 }
9736
9737 private final void requestServiceBindingsLocked(ServiceRecord r) {
9738 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9739 while (bindings.hasNext()) {
9740 IntentBindRecord i = bindings.next();
9741 if (!requestServiceBindingLocked(r, i, false)) {
9742 break;
9743 }
9744 }
9745 }
9746
9747 private final void realStartServiceLocked(ServiceRecord r,
9748 ProcessRecord app) throws RemoteException {
9749 if (app.thread == null) {
9750 throw new RemoteException();
9751 }
9752
9753 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009754 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009755
9756 app.services.add(r);
9757 bumpServiceExecutingLocked(r);
9758 updateLRUListLocked(app, true);
9759
9760 boolean created = false;
9761 try {
9762 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9763 + r.name + " " + r.intent);
9764 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9765 System.identityHashCode(r), r.shortName,
9766 r.intent.getIntent().toString(), r.app.pid);
9767 synchronized (r.stats.getBatteryStats()) {
9768 r.stats.startLaunchedLocked();
9769 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009770 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009771 app.thread.scheduleCreateService(r, r.serviceInfo);
9772 created = true;
9773 } finally {
9774 if (!created) {
9775 app.services.remove(r);
9776 scheduleServiceRestartLocked(r);
9777 }
9778 }
9779
9780 requestServiceBindingsLocked(r);
9781 sendServiceArgsLocked(r, true);
9782 }
9783
9784 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9785 r.totalRestartCount++;
9786 if (r.restartDelay == 0) {
9787 r.restartCount++;
9788 r.restartDelay = SERVICE_RESTART_DURATION;
9789 } else {
9790 // If it has been a "reasonably long time" since the service
9791 // was started, then reset our restart duration back to
9792 // the beginning, so we don't infinitely increase the duration
9793 // on a service that just occasionally gets killed (which is
9794 // a normal case, due to process being killed to reclaim memory).
9795 long now = SystemClock.uptimeMillis();
9796 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9797 r.restartCount = 1;
9798 r.restartDelay = SERVICE_RESTART_DURATION;
9799 } else {
9800 r.restartDelay *= 2;
9801 }
9802 }
9803 if (!mRestartingServices.contains(r)) {
9804 mRestartingServices.add(r);
9805 }
9806 mHandler.removeCallbacks(r.restarter);
9807 mHandler.postDelayed(r.restarter, r.restartDelay);
9808 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9809 Log.w(TAG, "Scheduling restart of crashed service "
9810 + r.shortName + " in " + r.restartDelay + "ms");
9811 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9812 r.shortName, r.restartDelay);
9813
9814 Message msg = Message.obtain();
9815 msg.what = SERVICE_ERROR_MSG;
9816 msg.obj = r;
9817 mHandler.sendMessage(msg);
9818 }
9819
9820 final void performServiceRestartLocked(ServiceRecord r) {
9821 if (!mRestartingServices.contains(r)) {
9822 return;
9823 }
9824 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9825 }
9826
9827 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9828 if (r.restartDelay == 0) {
9829 return false;
9830 }
9831 r.resetRestartCounter();
9832 mRestartingServices.remove(r);
9833 mHandler.removeCallbacks(r.restarter);
9834 return true;
9835 }
9836
9837 private final boolean bringUpServiceLocked(ServiceRecord r,
9838 int intentFlags, boolean whileRestarting) {
9839 //Log.i(TAG, "Bring up service:");
9840 //r.dump(" ");
9841
9842 if (r.app != null) {
9843 sendServiceArgsLocked(r, false);
9844 return true;
9845 }
9846
9847 if (!whileRestarting && r.restartDelay > 0) {
9848 // If waiting for a restart, then do nothing.
9849 return true;
9850 }
9851
9852 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9853 + " " + r.intent);
9854
9855 final String appName = r.processName;
9856 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9857 if (app != null && app.thread != null) {
9858 try {
9859 realStartServiceLocked(r, app);
9860 return true;
9861 } catch (RemoteException e) {
9862 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9863 }
9864
9865 // If a dead object exception was thrown -- fall through to
9866 // restart the application.
9867 }
9868
9869 if (!mPendingServices.contains(r)) {
9870 // Not running -- get it started, and enqueue this service record
9871 // to be executed when the app comes up.
9872 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9873 "service", r.name) == null) {
9874 Log.w(TAG, "Unable to launch app "
9875 + r.appInfo.packageName + "/"
9876 + r.appInfo.uid + " for service "
9877 + r.intent.getIntent() + ": process is bad");
9878 bringDownServiceLocked(r, true);
9879 return false;
9880 }
9881 mPendingServices.add(r);
9882 }
9883 return true;
9884 }
9885
9886 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9887 //Log.i(TAG, "Bring down service:");
9888 //r.dump(" ");
9889
9890 // Does it still need to run?
9891 if (!force && r.startRequested) {
9892 return;
9893 }
9894 if (r.connections.size() > 0) {
9895 if (!force) {
9896 // XXX should probably keep a count of the number of auto-create
9897 // connections directly in the service.
9898 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9899 while (it.hasNext()) {
9900 ConnectionRecord cr = it.next();
9901 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9902 return;
9903 }
9904 }
9905 }
9906
9907 // Report to all of the connections that the service is no longer
9908 // available.
9909 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9910 while (it.hasNext()) {
9911 ConnectionRecord c = it.next();
9912 try {
9913 // todo: shouldn't be a synchronous call!
9914 c.conn.connected(r.name, null);
9915 } catch (Exception e) {
9916 Log.w(TAG, "Failure disconnecting service " + r.name +
9917 " to connection " + c.conn.asBinder() +
9918 " (in " + c.binding.client.processName + ")", e);
9919 }
9920 }
9921 }
9922
9923 // Tell the service that it has been unbound.
9924 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9925 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9926 while (it.hasNext()) {
9927 IntentBindRecord ibr = it.next();
9928 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9929 + ": hasBound=" + ibr.hasBound);
9930 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9931 try {
9932 bumpServiceExecutingLocked(r);
9933 updateOomAdjLocked(r.app);
9934 ibr.hasBound = false;
9935 r.app.thread.scheduleUnbindService(r,
9936 ibr.intent.getIntent());
9937 } catch (Exception e) {
9938 Log.w(TAG, "Exception when unbinding service "
9939 + r.shortName, e);
9940 serviceDoneExecutingLocked(r, true);
9941 }
9942 }
9943 }
9944 }
9945
9946 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9947 + " " + r.intent);
9948 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9949 System.identityHashCode(r), r.shortName,
9950 (r.app != null) ? r.app.pid : -1);
9951
9952 mServices.remove(r.name);
9953 mServicesByIntent.remove(r.intent);
9954 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9955 r.totalRestartCount = 0;
9956 unscheduleServiceRestartLocked(r);
9957
9958 // Also make sure it is not on the pending list.
9959 int N = mPendingServices.size();
9960 for (int i=0; i<N; i++) {
9961 if (mPendingServices.get(i) == r) {
9962 mPendingServices.remove(i);
9963 if (DEBUG_SERVICE) Log.v(
9964 TAG, "Removed pending service: " + r.shortName);
9965 i--;
9966 N--;
9967 }
9968 }
9969
9970 if (r.app != null) {
9971 synchronized (r.stats.getBatteryStats()) {
9972 r.stats.stopLaunchedLocked();
9973 }
9974 r.app.services.remove(r);
9975 if (r.app.thread != null) {
9976 updateServiceForegroundLocked(r.app, false);
9977 try {
9978 Log.i(TAG, "Stopping service: " + r.shortName);
9979 bumpServiceExecutingLocked(r);
9980 mStoppingServices.add(r);
9981 updateOomAdjLocked(r.app);
9982 r.app.thread.scheduleStopService(r);
9983 } catch (Exception e) {
9984 Log.w(TAG, "Exception when stopping service "
9985 + r.shortName, e);
9986 serviceDoneExecutingLocked(r, true);
9987 }
9988 } else {
9989 if (DEBUG_SERVICE) Log.v(
9990 TAG, "Removed service that has no process: " + r.shortName);
9991 }
9992 } else {
9993 if (DEBUG_SERVICE) Log.v(
9994 TAG, "Removed service that is not running: " + r.shortName);
9995 }
9996 }
9997
9998 ComponentName startServiceLocked(IApplicationThread caller,
9999 Intent service, String resolvedType,
10000 int callingPid, int callingUid) {
10001 synchronized(this) {
10002 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10003 + " type=" + resolvedType + " args=" + service.getExtras());
10004
10005 if (caller != null) {
10006 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10007 if (callerApp == null) {
10008 throw new SecurityException(
10009 "Unable to find app for caller " + caller
10010 + " (pid=" + Binder.getCallingPid()
10011 + ") when starting service " + service);
10012 }
10013 }
10014
10015 ServiceLookupResult res =
10016 retrieveServiceLocked(service, resolvedType,
10017 callingPid, callingUid);
10018 if (res == null) {
10019 return null;
10020 }
10021 if (res.record == null) {
10022 return new ComponentName("!", res.permission != null
10023 ? res.permission : "private to package");
10024 }
10025 ServiceRecord r = res.record;
10026 if (unscheduleServiceRestartLocked(r)) {
10027 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10028 + r.shortName);
10029 }
10030 r.startRequested = true;
10031 r.startArgs.add(service);
10032 r.lastStartId++;
10033 if (r.lastStartId < 1) {
10034 r.lastStartId = 1;
10035 }
10036 r.lastActivity = SystemClock.uptimeMillis();
10037 synchronized (r.stats.getBatteryStats()) {
10038 r.stats.startRunningLocked();
10039 }
10040 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10041 return new ComponentName("!", "Service process is bad");
10042 }
10043 return r.name;
10044 }
10045 }
10046
10047 public ComponentName startService(IApplicationThread caller, Intent service,
10048 String resolvedType) {
10049 // Refuse possible leaked file descriptors
10050 if (service != null && service.hasFileDescriptors() == true) {
10051 throw new IllegalArgumentException("File descriptors passed in Intent");
10052 }
10053
10054 synchronized(this) {
10055 final int callingPid = Binder.getCallingPid();
10056 final int callingUid = Binder.getCallingUid();
10057 final long origId = Binder.clearCallingIdentity();
10058 ComponentName res = startServiceLocked(caller, service,
10059 resolvedType, callingPid, callingUid);
10060 Binder.restoreCallingIdentity(origId);
10061 return res;
10062 }
10063 }
10064
10065 ComponentName startServiceInPackage(int uid,
10066 Intent service, String resolvedType) {
10067 synchronized(this) {
10068 final long origId = Binder.clearCallingIdentity();
10069 ComponentName res = startServiceLocked(null, service,
10070 resolvedType, -1, uid);
10071 Binder.restoreCallingIdentity(origId);
10072 return res;
10073 }
10074 }
10075
10076 public int stopService(IApplicationThread caller, Intent service,
10077 String resolvedType) {
10078 // Refuse possible leaked file descriptors
10079 if (service != null && service.hasFileDescriptors() == true) {
10080 throw new IllegalArgumentException("File descriptors passed in Intent");
10081 }
10082
10083 synchronized(this) {
10084 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10085 + " type=" + resolvedType);
10086
10087 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10088 if (caller != null && callerApp == null) {
10089 throw new SecurityException(
10090 "Unable to find app for caller " + caller
10091 + " (pid=" + Binder.getCallingPid()
10092 + ") when stopping service " + service);
10093 }
10094
10095 // If this service is active, make sure it is stopped.
10096 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10097 if (r != null) {
10098 if (r.record != null) {
10099 synchronized (r.record.stats.getBatteryStats()) {
10100 r.record.stats.stopRunningLocked();
10101 }
10102 r.record.startRequested = false;
10103 final long origId = Binder.clearCallingIdentity();
10104 bringDownServiceLocked(r.record, false);
10105 Binder.restoreCallingIdentity(origId);
10106 return 1;
10107 }
10108 return -1;
10109 }
10110 }
10111
10112 return 0;
10113 }
10114
10115 public IBinder peekService(Intent service, String resolvedType) {
10116 // Refuse possible leaked file descriptors
10117 if (service != null && service.hasFileDescriptors() == true) {
10118 throw new IllegalArgumentException("File descriptors passed in Intent");
10119 }
10120
10121 IBinder ret = null;
10122
10123 synchronized(this) {
10124 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10125
10126 if (r != null) {
10127 // r.record is null if findServiceLocked() failed the caller permission check
10128 if (r.record == null) {
10129 throw new SecurityException(
10130 "Permission Denial: Accessing service " + r.record.name
10131 + " from pid=" + Binder.getCallingPid()
10132 + ", uid=" + Binder.getCallingUid()
10133 + " requires " + r.permission);
10134 }
10135 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10136 if (ib != null) {
10137 ret = ib.binder;
10138 }
10139 }
10140 }
10141
10142 return ret;
10143 }
10144
10145 public boolean stopServiceToken(ComponentName className, IBinder token,
10146 int startId) {
10147 synchronized(this) {
10148 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10149 + " " + token + " startId=" + startId);
10150 ServiceRecord r = findServiceLocked(className, token);
10151 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10152 synchronized (r.stats.getBatteryStats()) {
10153 r.stats.stopRunningLocked();
10154 r.startRequested = false;
10155 }
10156 final long origId = Binder.clearCallingIdentity();
10157 bringDownServiceLocked(r, false);
10158 Binder.restoreCallingIdentity(origId);
10159 return true;
10160 }
10161 }
10162 return false;
10163 }
10164
10165 public void setServiceForeground(ComponentName className, IBinder token,
10166 boolean isForeground) {
10167 synchronized(this) {
10168 ServiceRecord r = findServiceLocked(className, token);
10169 if (r != null) {
10170 if (r.isForeground != isForeground) {
10171 final long origId = Binder.clearCallingIdentity();
10172 r.isForeground = isForeground;
10173 if (r.app != null) {
10174 updateServiceForegroundLocked(r.app, true);
10175 }
10176 Binder.restoreCallingIdentity(origId);
10177 }
10178 }
10179 }
10180 }
10181
10182 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10183 boolean anyForeground = false;
10184 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10185 if (sr.isForeground) {
10186 anyForeground = true;
10187 break;
10188 }
10189 }
10190 if (anyForeground != proc.foregroundServices) {
10191 proc.foregroundServices = anyForeground;
10192 if (oomAdj) {
10193 updateOomAdjLocked();
10194 }
10195 }
10196 }
10197
10198 public int bindService(IApplicationThread caller, IBinder token,
10199 Intent service, String resolvedType,
10200 IServiceConnection connection, int flags) {
10201 // Refuse possible leaked file descriptors
10202 if (service != null && service.hasFileDescriptors() == true) {
10203 throw new IllegalArgumentException("File descriptors passed in Intent");
10204 }
10205
10206 synchronized(this) {
10207 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10208 + " type=" + resolvedType + " conn=" + connection.asBinder()
10209 + " flags=0x" + Integer.toHexString(flags));
10210 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10211 if (callerApp == null) {
10212 throw new SecurityException(
10213 "Unable to find app for caller " + caller
10214 + " (pid=" + Binder.getCallingPid()
10215 + ") when binding service " + service);
10216 }
10217
10218 HistoryRecord activity = null;
10219 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010220 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010221 if (aindex < 0) {
10222 Log.w(TAG, "Binding with unknown activity: " + token);
10223 return 0;
10224 }
10225 activity = (HistoryRecord)mHistory.get(aindex);
10226 }
10227
10228 ServiceLookupResult res =
10229 retrieveServiceLocked(service, resolvedType,
10230 Binder.getCallingPid(), Binder.getCallingUid());
10231 if (res == null) {
10232 return 0;
10233 }
10234 if (res.record == null) {
10235 return -1;
10236 }
10237 ServiceRecord s = res.record;
10238
10239 final long origId = Binder.clearCallingIdentity();
10240
10241 if (unscheduleServiceRestartLocked(s)) {
10242 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10243 + s.shortName);
10244 }
10245
10246 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10247 ConnectionRecord c = new ConnectionRecord(b, activity,
10248 connection, flags);
10249
10250 IBinder binder = connection.asBinder();
10251 s.connections.put(binder, c);
10252 b.connections.add(c);
10253 if (activity != null) {
10254 if (activity.connections == null) {
10255 activity.connections = new HashSet<ConnectionRecord>();
10256 }
10257 activity.connections.add(c);
10258 }
10259 b.client.connections.add(c);
10260 mServiceConnections.put(binder, c);
10261
10262 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10263 s.lastActivity = SystemClock.uptimeMillis();
10264 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10265 return 0;
10266 }
10267 }
10268
10269 if (s.app != null) {
10270 // This could have made the service more important.
10271 updateOomAdjLocked(s.app);
10272 }
10273
10274 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10275 + ": received=" + b.intent.received
10276 + " apps=" + b.intent.apps.size()
10277 + " doRebind=" + b.intent.doRebind);
10278
10279 if (s.app != null && b.intent.received) {
10280 // Service is already running, so we can immediately
10281 // publish the connection.
10282 try {
10283 c.conn.connected(s.name, b.intent.binder);
10284 } catch (Exception e) {
10285 Log.w(TAG, "Failure sending service " + s.shortName
10286 + " to connection " + c.conn.asBinder()
10287 + " (in " + c.binding.client.processName + ")", e);
10288 }
10289
10290 // If this is the first app connected back to this binding,
10291 // and the service had previously asked to be told when
10292 // rebound, then do so.
10293 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10294 requestServiceBindingLocked(s, b.intent, true);
10295 }
10296 } else if (!b.intent.requested) {
10297 requestServiceBindingLocked(s, b.intent, false);
10298 }
10299
10300 Binder.restoreCallingIdentity(origId);
10301 }
10302
10303 return 1;
10304 }
10305
10306 private void removeConnectionLocked(
10307 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10308 IBinder binder = c.conn.asBinder();
10309 AppBindRecord b = c.binding;
10310 ServiceRecord s = b.service;
10311 s.connections.remove(binder);
10312 b.connections.remove(c);
10313 if (c.activity != null && c.activity != skipAct) {
10314 if (c.activity.connections != null) {
10315 c.activity.connections.remove(c);
10316 }
10317 }
10318 if (b.client != skipApp) {
10319 b.client.connections.remove(c);
10320 }
10321 mServiceConnections.remove(binder);
10322
10323 if (b.connections.size() == 0) {
10324 b.intent.apps.remove(b.client);
10325 }
10326
10327 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10328 + ": shouldUnbind=" + b.intent.hasBound);
10329 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10330 && b.intent.hasBound) {
10331 try {
10332 bumpServiceExecutingLocked(s);
10333 updateOomAdjLocked(s.app);
10334 b.intent.hasBound = false;
10335 // Assume the client doesn't want to know about a rebind;
10336 // we will deal with that later if it asks for one.
10337 b.intent.doRebind = false;
10338 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10339 } catch (Exception e) {
10340 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10341 serviceDoneExecutingLocked(s, true);
10342 }
10343 }
10344
10345 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10346 bringDownServiceLocked(s, false);
10347 }
10348 }
10349
10350 public boolean unbindService(IServiceConnection connection) {
10351 synchronized (this) {
10352 IBinder binder = connection.asBinder();
10353 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10354 ConnectionRecord r = mServiceConnections.get(binder);
10355 if (r == null) {
10356 Log.w(TAG, "Unbind failed: could not find connection for "
10357 + connection.asBinder());
10358 return false;
10359 }
10360
10361 final long origId = Binder.clearCallingIdentity();
10362
10363 removeConnectionLocked(r, null, null);
10364
10365 if (r.binding.service.app != null) {
10366 // This could have made the service less important.
10367 updateOomAdjLocked(r.binding.service.app);
10368 }
10369
10370 Binder.restoreCallingIdentity(origId);
10371 }
10372
10373 return true;
10374 }
10375
10376 public void publishService(IBinder token, Intent intent, IBinder service) {
10377 // Refuse possible leaked file descriptors
10378 if (intent != null && intent.hasFileDescriptors() == true) {
10379 throw new IllegalArgumentException("File descriptors passed in Intent");
10380 }
10381
10382 synchronized(this) {
10383 if (!(token instanceof ServiceRecord)) {
10384 throw new IllegalArgumentException("Invalid service token");
10385 }
10386 ServiceRecord r = (ServiceRecord)token;
10387
10388 final long origId = Binder.clearCallingIdentity();
10389
10390 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10391 + " " + intent + ": " + service);
10392 if (r != null) {
10393 Intent.FilterComparison filter
10394 = new Intent.FilterComparison(intent);
10395 IntentBindRecord b = r.bindings.get(filter);
10396 if (b != null && !b.received) {
10397 b.binder = service;
10398 b.requested = true;
10399 b.received = true;
10400 if (r.connections.size() > 0) {
10401 Iterator<ConnectionRecord> it
10402 = r.connections.values().iterator();
10403 while (it.hasNext()) {
10404 ConnectionRecord c = it.next();
10405 if (!filter.equals(c.binding.intent.intent)) {
10406 if (DEBUG_SERVICE) Log.v(
10407 TAG, "Not publishing to: " + c);
10408 if (DEBUG_SERVICE) Log.v(
10409 TAG, "Bound intent: " + c.binding.intent.intent);
10410 if (DEBUG_SERVICE) Log.v(
10411 TAG, "Published intent: " + intent);
10412 continue;
10413 }
10414 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10415 try {
10416 c.conn.connected(r.name, service);
10417 } catch (Exception e) {
10418 Log.w(TAG, "Failure sending service " + r.name +
10419 " to connection " + c.conn.asBinder() +
10420 " (in " + c.binding.client.processName + ")", e);
10421 }
10422 }
10423 }
10424 }
10425
10426 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10427
10428 Binder.restoreCallingIdentity(origId);
10429 }
10430 }
10431 }
10432
10433 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10434 // Refuse possible leaked file descriptors
10435 if (intent != null && intent.hasFileDescriptors() == true) {
10436 throw new IllegalArgumentException("File descriptors passed in Intent");
10437 }
10438
10439 synchronized(this) {
10440 if (!(token instanceof ServiceRecord)) {
10441 throw new IllegalArgumentException("Invalid service token");
10442 }
10443 ServiceRecord r = (ServiceRecord)token;
10444
10445 final long origId = Binder.clearCallingIdentity();
10446
10447 if (r != null) {
10448 Intent.FilterComparison filter
10449 = new Intent.FilterComparison(intent);
10450 IntentBindRecord b = r.bindings.get(filter);
10451 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10452 + " at " + b + ": apps="
10453 + (b != null ? b.apps.size() : 0));
10454 if (b != null) {
10455 if (b.apps.size() > 0) {
10456 // Applications have already bound since the last
10457 // unbind, so just rebind right here.
10458 requestServiceBindingLocked(r, b, true);
10459 } else {
10460 // Note to tell the service the next time there is
10461 // a new client.
10462 b.doRebind = true;
10463 }
10464 }
10465
10466 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10467
10468 Binder.restoreCallingIdentity(origId);
10469 }
10470 }
10471 }
10472
10473 public void serviceDoneExecuting(IBinder token) {
10474 synchronized(this) {
10475 if (!(token instanceof ServiceRecord)) {
10476 throw new IllegalArgumentException("Invalid service token");
10477 }
10478 ServiceRecord r = (ServiceRecord)token;
10479 boolean inStopping = mStoppingServices.contains(token);
10480 if (r != null) {
10481 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10482 + ": nesting=" + r.executeNesting
10483 + ", inStopping=" + inStopping);
10484 if (r != token) {
10485 Log.w(TAG, "Done executing service " + r.name
10486 + " with incorrect token: given " + token
10487 + ", expected " + r);
10488 return;
10489 }
10490
10491 final long origId = Binder.clearCallingIdentity();
10492 serviceDoneExecutingLocked(r, inStopping);
10493 Binder.restoreCallingIdentity(origId);
10494 } else {
10495 Log.w(TAG, "Done executing unknown service " + r.name
10496 + " with token " + token);
10497 }
10498 }
10499 }
10500
10501 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10502 r.executeNesting--;
10503 if (r.executeNesting <= 0 && r.app != null) {
10504 r.app.executingServices.remove(r);
10505 if (r.app.executingServices.size() == 0) {
10506 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10507 }
10508 if (inStopping) {
10509 mStoppingServices.remove(r);
10510 }
10511 updateOomAdjLocked(r.app);
10512 }
10513 }
10514
10515 void serviceTimeout(ProcessRecord proc) {
10516 synchronized(this) {
10517 if (proc.executingServices.size() == 0 || proc.thread == null) {
10518 return;
10519 }
10520 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10521 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10522 ServiceRecord timeout = null;
10523 long nextTime = 0;
10524 while (it.hasNext()) {
10525 ServiceRecord sr = it.next();
10526 if (sr.executingStart < maxTime) {
10527 timeout = sr;
10528 break;
10529 }
10530 if (sr.executingStart > nextTime) {
10531 nextTime = sr.executingStart;
10532 }
10533 }
10534 if (timeout != null && mLRUProcesses.contains(proc)) {
10535 Log.w(TAG, "Timeout executing service: " + timeout);
10536 appNotRespondingLocked(proc, null, "Executing service "
10537 + timeout.name);
10538 } else {
10539 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10540 msg.obj = proc;
10541 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10542 }
10543 }
10544 }
10545
10546 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010547 // BACKUP AND RESTORE
10548 // =========================================================
10549
10550 // Cause the target app to be launched if necessary and its backup agent
10551 // instantiated. The backup agent will invoke backupAgentCreated() on the
10552 // activity manager to announce its creation.
10553 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10554 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10555 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10556
10557 synchronized(this) {
10558 // !!! TODO: currently no check here that we're already bound
10559 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10560 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10561 synchronized (stats) {
10562 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10563 }
10564
10565 BackupRecord r = new BackupRecord(ss, app, backupMode);
10566 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10567 // startProcessLocked() returns existing proc's record if it's already running
10568 ProcessRecord proc = startProcessLocked(app.processName, app,
10569 false, 0, "backup", hostingName);
10570 if (proc == null) {
10571 Log.e(TAG, "Unable to start backup agent process " + r);
10572 return false;
10573 }
10574
10575 r.app = proc;
10576 mBackupTarget = r;
10577 mBackupAppName = app.packageName;
10578
Christopher Tate6fa95972009-06-05 18:43:55 -070010579 // Try not to kill the process during backup
10580 updateOomAdjLocked(proc);
10581
Christopher Tate181fafa2009-05-14 11:12:14 -070010582 // If the process is already attached, schedule the creation of the backup agent now.
10583 // If it is not yet live, this will be done when it attaches to the framework.
10584 if (proc.thread != null) {
10585 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10586 try {
10587 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10588 } catch (RemoteException e) {
10589 // !!! TODO: notify the backup manager that we crashed, or rely on
10590 // death notices, or...?
10591 }
10592 } else {
10593 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10594 }
10595 // Invariants: at this point, the target app process exists and the application
10596 // is either already running or in the process of coming up. mBackupTarget and
10597 // mBackupAppName describe the app, so that when it binds back to the AM we
10598 // know that it's scheduled for a backup-agent operation.
10599 }
10600
10601 return true;
10602 }
10603
10604 // A backup agent has just come up
10605 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10606 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10607 + " = " + agent);
10608
10609 synchronized(this) {
10610 if (!agentPackageName.equals(mBackupAppName)) {
10611 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10612 return;
10613 }
10614
Christopher Tate043dadc2009-06-02 16:11:00 -070010615 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010616 try {
10617 IBackupManager bm = IBackupManager.Stub.asInterface(
10618 ServiceManager.getService(Context.BACKUP_SERVICE));
10619 bm.agentConnected(agentPackageName, agent);
10620 } catch (RemoteException e) {
10621 // can't happen; the backup manager service is local
10622 } catch (Exception e) {
10623 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10624 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010625 } finally {
10626 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010627 }
10628 }
10629 }
10630
10631 // done with this agent
10632 public void unbindBackupAgent(ApplicationInfo appInfo) {
10633 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010634 if (appInfo == null) {
10635 Log.w(TAG, "unbind backup agent for null app");
10636 return;
10637 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010638
10639 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010640 if (mBackupAppName == null) {
10641 Log.w(TAG, "Unbinding backup agent with no active backup");
10642 return;
10643 }
10644
Christopher Tate181fafa2009-05-14 11:12:14 -070010645 if (!mBackupAppName.equals(appInfo.packageName)) {
10646 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10647 return;
10648 }
10649
Christopher Tate6fa95972009-06-05 18:43:55 -070010650 ProcessRecord proc = mBackupTarget.app;
10651 mBackupTarget = null;
10652 mBackupAppName = null;
10653
10654 // Not backing this app up any more; reset its OOM adjustment
10655 updateOomAdjLocked(proc);
10656
Christopher Tatec7b31e32009-06-10 15:49:30 -070010657 // If the app crashed during backup, 'thread' will be null here
10658 if (proc.thread != null) {
10659 try {
10660 proc.thread.scheduleDestroyBackupAgent(appInfo);
10661 } catch (Exception e) {
10662 Log.e(TAG, "Exception when unbinding backup agent:");
10663 e.printStackTrace();
10664 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010665 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010666 }
10667 }
10668 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010669 // BROADCASTS
10670 // =========================================================
10671
10672 private final List getStickies(String action, IntentFilter filter,
10673 List cur) {
10674 final ContentResolver resolver = mContext.getContentResolver();
10675 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10676 if (list == null) {
10677 return cur;
10678 }
10679 int N = list.size();
10680 for (int i=0; i<N; i++) {
10681 Intent intent = list.get(i);
10682 if (filter.match(resolver, intent, true, TAG) >= 0) {
10683 if (cur == null) {
10684 cur = new ArrayList<Intent>();
10685 }
10686 cur.add(intent);
10687 }
10688 }
10689 return cur;
10690 }
10691
10692 private final void scheduleBroadcastsLocked() {
10693 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10694 + mBroadcastsScheduled);
10695
10696 if (mBroadcastsScheduled) {
10697 return;
10698 }
10699 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10700 mBroadcastsScheduled = true;
10701 }
10702
10703 public Intent registerReceiver(IApplicationThread caller,
10704 IIntentReceiver receiver, IntentFilter filter, String permission) {
10705 synchronized(this) {
10706 ProcessRecord callerApp = null;
10707 if (caller != null) {
10708 callerApp = getRecordForAppLocked(caller);
10709 if (callerApp == null) {
10710 throw new SecurityException(
10711 "Unable to find app for caller " + caller
10712 + " (pid=" + Binder.getCallingPid()
10713 + ") when registering receiver " + receiver);
10714 }
10715 }
10716
10717 List allSticky = null;
10718
10719 // Look for any matching sticky broadcasts...
10720 Iterator actions = filter.actionsIterator();
10721 if (actions != null) {
10722 while (actions.hasNext()) {
10723 String action = (String)actions.next();
10724 allSticky = getStickies(action, filter, allSticky);
10725 }
10726 } else {
10727 allSticky = getStickies(null, filter, allSticky);
10728 }
10729
10730 // The first sticky in the list is returned directly back to
10731 // the client.
10732 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10733
10734 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10735 + ": " + sticky);
10736
10737 if (receiver == null) {
10738 return sticky;
10739 }
10740
10741 ReceiverList rl
10742 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10743 if (rl == null) {
10744 rl = new ReceiverList(this, callerApp,
10745 Binder.getCallingPid(),
10746 Binder.getCallingUid(), receiver);
10747 if (rl.app != null) {
10748 rl.app.receivers.add(rl);
10749 } else {
10750 try {
10751 receiver.asBinder().linkToDeath(rl, 0);
10752 } catch (RemoteException e) {
10753 return sticky;
10754 }
10755 rl.linkedToDeath = true;
10756 }
10757 mRegisteredReceivers.put(receiver.asBinder(), rl);
10758 }
10759 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10760 rl.add(bf);
10761 if (!bf.debugCheck()) {
10762 Log.w(TAG, "==> For Dynamic broadast");
10763 }
10764 mReceiverResolver.addFilter(bf);
10765
10766 // Enqueue broadcasts for all existing stickies that match
10767 // this filter.
10768 if (allSticky != null) {
10769 ArrayList receivers = new ArrayList();
10770 receivers.add(bf);
10771
10772 int N = allSticky.size();
10773 for (int i=0; i<N; i++) {
10774 Intent intent = (Intent)allSticky.get(i);
10775 BroadcastRecord r = new BroadcastRecord(intent, null,
10776 null, -1, -1, null, receivers, null, 0, null, null,
10777 false);
10778 if (mParallelBroadcasts.size() == 0) {
10779 scheduleBroadcastsLocked();
10780 }
10781 mParallelBroadcasts.add(r);
10782 }
10783 }
10784
10785 return sticky;
10786 }
10787 }
10788
10789 public void unregisterReceiver(IIntentReceiver receiver) {
10790 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10791
10792 boolean doNext = false;
10793
10794 synchronized(this) {
10795 ReceiverList rl
10796 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10797 if (rl != null) {
10798 if (rl.curBroadcast != null) {
10799 BroadcastRecord r = rl.curBroadcast;
10800 doNext = finishReceiverLocked(
10801 receiver.asBinder(), r.resultCode, r.resultData,
10802 r.resultExtras, r.resultAbort, true);
10803 }
10804
10805 if (rl.app != null) {
10806 rl.app.receivers.remove(rl);
10807 }
10808 removeReceiverLocked(rl);
10809 if (rl.linkedToDeath) {
10810 rl.linkedToDeath = false;
10811 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10812 }
10813 }
10814 }
10815
10816 if (!doNext) {
10817 return;
10818 }
10819
10820 final long origId = Binder.clearCallingIdentity();
10821 processNextBroadcast(false);
10822 trimApplications();
10823 Binder.restoreCallingIdentity(origId);
10824 }
10825
10826 void removeReceiverLocked(ReceiverList rl) {
10827 mRegisteredReceivers.remove(rl.receiver.asBinder());
10828 int N = rl.size();
10829 for (int i=0; i<N; i++) {
10830 mReceiverResolver.removeFilter(rl.get(i));
10831 }
10832 }
10833
10834 private final int broadcastIntentLocked(ProcessRecord callerApp,
10835 String callerPackage, Intent intent, String resolvedType,
10836 IIntentReceiver resultTo, int resultCode, String resultData,
10837 Bundle map, String requiredPermission,
10838 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10839 intent = new Intent(intent);
10840
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010841 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010842 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10843 + " ordered=" + ordered);
10844 if ((resultTo != null) && !ordered) {
10845 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10846 }
10847
10848 // Handle special intents: if this broadcast is from the package
10849 // manager about a package being removed, we need to remove all of
10850 // its activities from the history stack.
10851 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10852 intent.getAction());
10853 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10854 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10855 || uidRemoved) {
10856 if (checkComponentPermission(
10857 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10858 callingPid, callingUid, -1)
10859 == PackageManager.PERMISSION_GRANTED) {
10860 if (uidRemoved) {
10861 final Bundle intentExtras = intent.getExtras();
10862 final int uid = intentExtras != null
10863 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10864 if (uid >= 0) {
10865 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10866 synchronized (bs) {
10867 bs.removeUidStatsLocked(uid);
10868 }
10869 }
10870 } else {
10871 Uri data = intent.getData();
10872 String ssp;
10873 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10874 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10875 uninstallPackageLocked(ssp,
10876 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010877 AttributeCache ac = AttributeCache.instance();
10878 if (ac != null) {
10879 ac.removePackage(ssp);
10880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010881 }
10882 }
10883 }
10884 } else {
10885 String msg = "Permission Denial: " + intent.getAction()
10886 + " broadcast from " + callerPackage + " (pid=" + callingPid
10887 + ", uid=" + callingUid + ")"
10888 + " requires "
10889 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10890 Log.w(TAG, msg);
10891 throw new SecurityException(msg);
10892 }
10893 }
10894
10895 /*
10896 * If this is the time zone changed action, queue up a message that will reset the timezone
10897 * of all currently running processes. This message will get queued up before the broadcast
10898 * happens.
10899 */
10900 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10901 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10902 }
10903
Dianne Hackborn854060af2009-07-09 18:14:31 -070010904 /*
10905 * Prevent non-system code (defined here to be non-persistent
10906 * processes) from sending protected broadcasts.
10907 */
10908 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10909 || callingUid == Process.SHELL_UID || callingUid == 0) {
10910 // Always okay.
10911 } else if (callerApp == null || !callerApp.persistent) {
10912 try {
10913 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10914 intent.getAction())) {
10915 String msg = "Permission Denial: not allowed to send broadcast "
10916 + intent.getAction() + " from pid="
10917 + callingPid + ", uid=" + callingUid;
10918 Log.w(TAG, msg);
10919 throw new SecurityException(msg);
10920 }
10921 } catch (RemoteException e) {
10922 Log.w(TAG, "Remote exception", e);
10923 return BROADCAST_SUCCESS;
10924 }
10925 }
10926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010927 // Add to the sticky list if requested.
10928 if (sticky) {
10929 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10930 callingPid, callingUid)
10931 != PackageManager.PERMISSION_GRANTED) {
10932 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10933 + callingPid + ", uid=" + callingUid
10934 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10935 Log.w(TAG, msg);
10936 throw new SecurityException(msg);
10937 }
10938 if (requiredPermission != null) {
10939 Log.w(TAG, "Can't broadcast sticky intent " + intent
10940 + " and enforce permission " + requiredPermission);
10941 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10942 }
10943 if (intent.getComponent() != null) {
10944 throw new SecurityException(
10945 "Sticky broadcasts can't target a specific component");
10946 }
10947 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10948 if (list == null) {
10949 list = new ArrayList<Intent>();
10950 mStickyBroadcasts.put(intent.getAction(), list);
10951 }
10952 int N = list.size();
10953 int i;
10954 for (i=0; i<N; i++) {
10955 if (intent.filterEquals(list.get(i))) {
10956 // This sticky already exists, replace it.
10957 list.set(i, new Intent(intent));
10958 break;
10959 }
10960 }
10961 if (i >= N) {
10962 list.add(new Intent(intent));
10963 }
10964 }
10965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010966 // Figure out who all will receive this broadcast.
10967 List receivers = null;
10968 List<BroadcastFilter> registeredReceivers = null;
10969 try {
10970 if (intent.getComponent() != null) {
10971 // Broadcast is going to one specific receiver class...
10972 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010973 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010974 if (ai != null) {
10975 receivers = new ArrayList();
10976 ResolveInfo ri = new ResolveInfo();
10977 ri.activityInfo = ai;
10978 receivers.add(ri);
10979 }
10980 } else {
10981 // Need to resolve the intent to interested receivers...
10982 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10983 == 0) {
10984 receivers =
10985 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010986 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010987 }
Mihai Preda074edef2009-05-18 17:13:31 +020010988 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010989 }
10990 } catch (RemoteException ex) {
10991 // pm is in same process, this will never happen.
10992 }
10993
10994 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10995 if (!ordered && NR > 0) {
10996 // If we are not serializing this broadcast, then send the
10997 // registered receivers separately so they don't wait for the
10998 // components to be launched.
10999 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11000 callerPackage, callingPid, callingUid, requiredPermission,
11001 registeredReceivers, resultTo, resultCode, resultData, map,
11002 ordered);
11003 if (DEBUG_BROADCAST) Log.v(
11004 TAG, "Enqueueing parallel broadcast " + r
11005 + ": prev had " + mParallelBroadcasts.size());
11006 mParallelBroadcasts.add(r);
11007 scheduleBroadcastsLocked();
11008 registeredReceivers = null;
11009 NR = 0;
11010 }
11011
11012 // Merge into one list.
11013 int ir = 0;
11014 if (receivers != null) {
11015 // A special case for PACKAGE_ADDED: do not allow the package
11016 // being added to see this broadcast. This prevents them from
11017 // using this as a back door to get run as soon as they are
11018 // installed. Maybe in the future we want to have a special install
11019 // broadcast or such for apps, but we'd like to deliberately make
11020 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011021 boolean skip = false;
11022 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011023 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011024 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11025 skip = true;
11026 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11027 skip = true;
11028 }
11029 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011030 ? intent.getData().getSchemeSpecificPart()
11031 : null;
11032 if (skipPackage != null && receivers != null) {
11033 int NT = receivers.size();
11034 for (int it=0; it<NT; it++) {
11035 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11036 if (curt.activityInfo.packageName.equals(skipPackage)) {
11037 receivers.remove(it);
11038 it--;
11039 NT--;
11040 }
11041 }
11042 }
11043
11044 int NT = receivers != null ? receivers.size() : 0;
11045 int it = 0;
11046 ResolveInfo curt = null;
11047 BroadcastFilter curr = null;
11048 while (it < NT && ir < NR) {
11049 if (curt == null) {
11050 curt = (ResolveInfo)receivers.get(it);
11051 }
11052 if (curr == null) {
11053 curr = registeredReceivers.get(ir);
11054 }
11055 if (curr.getPriority() >= curt.priority) {
11056 // Insert this broadcast record into the final list.
11057 receivers.add(it, curr);
11058 ir++;
11059 curr = null;
11060 it++;
11061 NT++;
11062 } else {
11063 // Skip to the next ResolveInfo in the final list.
11064 it++;
11065 curt = null;
11066 }
11067 }
11068 }
11069 while (ir < NR) {
11070 if (receivers == null) {
11071 receivers = new ArrayList();
11072 }
11073 receivers.add(registeredReceivers.get(ir));
11074 ir++;
11075 }
11076
11077 if ((receivers != null && receivers.size() > 0)
11078 || resultTo != null) {
11079 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11080 callerPackage, callingPid, callingUid, requiredPermission,
11081 receivers, resultTo, resultCode, resultData, map, ordered);
11082 if (DEBUG_BROADCAST) Log.v(
11083 TAG, "Enqueueing ordered broadcast " + r
11084 + ": prev had " + mOrderedBroadcasts.size());
11085 if (DEBUG_BROADCAST) {
11086 int seq = r.intent.getIntExtra("seq", -1);
11087 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11088 }
11089 mOrderedBroadcasts.add(r);
11090 scheduleBroadcastsLocked();
11091 }
11092
11093 return BROADCAST_SUCCESS;
11094 }
11095
11096 public final int broadcastIntent(IApplicationThread caller,
11097 Intent intent, String resolvedType, IIntentReceiver resultTo,
11098 int resultCode, String resultData, Bundle map,
11099 String requiredPermission, boolean serialized, boolean sticky) {
11100 // Refuse possible leaked file descriptors
11101 if (intent != null && intent.hasFileDescriptors() == true) {
11102 throw new IllegalArgumentException("File descriptors passed in Intent");
11103 }
11104
11105 synchronized(this) {
11106 if (!mSystemReady) {
11107 // if the caller really truly claims to know what they're doing, go
11108 // ahead and allow the broadcast without launching any receivers
11109 int flags = intent.getFlags();
11110 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11111 intent = new Intent(intent);
11112 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11113 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11114 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11115 + " before boot completion");
11116 throw new IllegalStateException("Cannot broadcast before boot completed");
11117 }
11118 }
11119
11120 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11121 final int callingPid = Binder.getCallingPid();
11122 final int callingUid = Binder.getCallingUid();
11123 final long origId = Binder.clearCallingIdentity();
11124 int res = broadcastIntentLocked(callerApp,
11125 callerApp != null ? callerApp.info.packageName : null,
11126 intent, resolvedType, resultTo,
11127 resultCode, resultData, map, requiredPermission, serialized,
11128 sticky, callingPid, callingUid);
11129 Binder.restoreCallingIdentity(origId);
11130 return res;
11131 }
11132 }
11133
11134 int broadcastIntentInPackage(String packageName, int uid,
11135 Intent intent, String resolvedType, IIntentReceiver resultTo,
11136 int resultCode, String resultData, Bundle map,
11137 String requiredPermission, boolean serialized, boolean sticky) {
11138 synchronized(this) {
11139 final long origId = Binder.clearCallingIdentity();
11140 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11141 resultTo, resultCode, resultData, map, requiredPermission,
11142 serialized, sticky, -1, uid);
11143 Binder.restoreCallingIdentity(origId);
11144 return res;
11145 }
11146 }
11147
11148 public final void unbroadcastIntent(IApplicationThread caller,
11149 Intent intent) {
11150 // Refuse possible leaked file descriptors
11151 if (intent != null && intent.hasFileDescriptors() == true) {
11152 throw new IllegalArgumentException("File descriptors passed in Intent");
11153 }
11154
11155 synchronized(this) {
11156 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11157 != PackageManager.PERMISSION_GRANTED) {
11158 String msg = "Permission Denial: unbroadcastIntent() from pid="
11159 + Binder.getCallingPid()
11160 + ", uid=" + Binder.getCallingUid()
11161 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11162 Log.w(TAG, msg);
11163 throw new SecurityException(msg);
11164 }
11165 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11166 if (list != null) {
11167 int N = list.size();
11168 int i;
11169 for (i=0; i<N; i++) {
11170 if (intent.filterEquals(list.get(i))) {
11171 list.remove(i);
11172 break;
11173 }
11174 }
11175 }
11176 }
11177 }
11178
11179 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11180 String resultData, Bundle resultExtras, boolean resultAbort,
11181 boolean explicit) {
11182 if (mOrderedBroadcasts.size() == 0) {
11183 if (explicit) {
11184 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11185 }
11186 return false;
11187 }
11188 BroadcastRecord r = mOrderedBroadcasts.get(0);
11189 if (r.receiver == null) {
11190 if (explicit) {
11191 Log.w(TAG, "finishReceiver called but none active");
11192 }
11193 return false;
11194 }
11195 if (r.receiver != receiver) {
11196 Log.w(TAG, "finishReceiver called but active receiver is different");
11197 return false;
11198 }
11199 int state = r.state;
11200 r.state = r.IDLE;
11201 if (state == r.IDLE) {
11202 if (explicit) {
11203 Log.w(TAG, "finishReceiver called but state is IDLE");
11204 }
11205 }
11206 r.receiver = null;
11207 r.intent.setComponent(null);
11208 if (r.curApp != null) {
11209 r.curApp.curReceiver = null;
11210 }
11211 if (r.curFilter != null) {
11212 r.curFilter.receiverList.curBroadcast = null;
11213 }
11214 r.curFilter = null;
11215 r.curApp = null;
11216 r.curComponent = null;
11217 r.curReceiver = null;
11218 mPendingBroadcast = null;
11219
11220 r.resultCode = resultCode;
11221 r.resultData = resultData;
11222 r.resultExtras = resultExtras;
11223 r.resultAbort = resultAbort;
11224
11225 // We will process the next receiver right now if this is finishing
11226 // an app receiver (which is always asynchronous) or after we have
11227 // come back from calling a receiver.
11228 return state == BroadcastRecord.APP_RECEIVE
11229 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11230 }
11231
11232 public void finishReceiver(IBinder who, int resultCode, String resultData,
11233 Bundle resultExtras, boolean resultAbort) {
11234 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11235
11236 // Refuse possible leaked file descriptors
11237 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11238 throw new IllegalArgumentException("File descriptors passed in Bundle");
11239 }
11240
11241 boolean doNext;
11242
11243 final long origId = Binder.clearCallingIdentity();
11244
11245 synchronized(this) {
11246 doNext = finishReceiverLocked(
11247 who, resultCode, resultData, resultExtras, resultAbort, true);
11248 }
11249
11250 if (doNext) {
11251 processNextBroadcast(false);
11252 }
11253 trimApplications();
11254
11255 Binder.restoreCallingIdentity(origId);
11256 }
11257
11258 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11259 if (r.nextReceiver > 0) {
11260 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11261 if (curReceiver instanceof BroadcastFilter) {
11262 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11263 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11264 System.identityHashCode(r),
11265 r.intent.getAction(),
11266 r.nextReceiver - 1,
11267 System.identityHashCode(bf));
11268 } else {
11269 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11270 System.identityHashCode(r),
11271 r.intent.getAction(),
11272 r.nextReceiver - 1,
11273 ((ResolveInfo)curReceiver).toString());
11274 }
11275 } else {
11276 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11277 + r);
11278 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11279 System.identityHashCode(r),
11280 r.intent.getAction(),
11281 r.nextReceiver,
11282 "NONE");
11283 }
11284 }
11285
11286 private final void broadcastTimeout() {
11287 synchronized (this) {
11288 if (mOrderedBroadcasts.size() == 0) {
11289 return;
11290 }
11291 long now = SystemClock.uptimeMillis();
11292 BroadcastRecord r = mOrderedBroadcasts.get(0);
11293 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11294 if (DEBUG_BROADCAST) Log.v(TAG,
11295 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11296 + (r.startTime + BROADCAST_TIMEOUT));
11297 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11298 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11299 return;
11300 }
11301
11302 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11303 r.startTime = now;
11304 r.anrCount++;
11305
11306 // Current receiver has passed its expiration date.
11307 if (r.nextReceiver <= 0) {
11308 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11309 return;
11310 }
11311
11312 ProcessRecord app = null;
11313
11314 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11315 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11316 logBroadcastReceiverDiscard(r);
11317 if (curReceiver instanceof BroadcastFilter) {
11318 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11319 if (bf.receiverList.pid != 0
11320 && bf.receiverList.pid != MY_PID) {
11321 synchronized (this.mPidsSelfLocked) {
11322 app = this.mPidsSelfLocked.get(
11323 bf.receiverList.pid);
11324 }
11325 }
11326 } else {
11327 app = r.curApp;
11328 }
11329
11330 if (app != null) {
11331 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11332 }
11333
11334 if (mPendingBroadcast == r) {
11335 mPendingBroadcast = null;
11336 }
11337
11338 // Move on to the next receiver.
11339 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11340 r.resultExtras, r.resultAbort, true);
11341 scheduleBroadcastsLocked();
11342 }
11343 }
11344
11345 private final void processCurBroadcastLocked(BroadcastRecord r,
11346 ProcessRecord app) throws RemoteException {
11347 if (app.thread == null) {
11348 throw new RemoteException();
11349 }
11350 r.receiver = app.thread.asBinder();
11351 r.curApp = app;
11352 app.curReceiver = r;
11353 updateLRUListLocked(app, true);
11354
11355 // Tell the application to launch this receiver.
11356 r.intent.setComponent(r.curComponent);
11357
11358 boolean started = false;
11359 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011360 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011361 "Delivering to component " + r.curComponent
11362 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011363 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011364 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11365 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11366 started = true;
11367 } finally {
11368 if (!started) {
11369 r.receiver = null;
11370 r.curApp = null;
11371 app.curReceiver = null;
11372 }
11373 }
11374
11375 }
11376
11377 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11378 Intent intent, int resultCode, String data,
11379 Bundle extras, boolean ordered) throws RemoteException {
11380 if (app != null && app.thread != null) {
11381 // If we have an app thread, do the call through that so it is
11382 // correctly ordered with other one-way calls.
11383 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11384 data, extras, ordered);
11385 } else {
11386 receiver.performReceive(intent, resultCode, data, extras, ordered);
11387 }
11388 }
11389
11390 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11391 BroadcastFilter filter, boolean ordered) {
11392 boolean skip = false;
11393 if (filter.requiredPermission != null) {
11394 int perm = checkComponentPermission(filter.requiredPermission,
11395 r.callingPid, r.callingUid, -1);
11396 if (perm != PackageManager.PERMISSION_GRANTED) {
11397 Log.w(TAG, "Permission Denial: broadcasting "
11398 + r.intent.toString()
11399 + " from " + r.callerPackage + " (pid="
11400 + r.callingPid + ", uid=" + r.callingUid + ")"
11401 + " requires " + filter.requiredPermission
11402 + " due to registered receiver " + filter);
11403 skip = true;
11404 }
11405 }
11406 if (r.requiredPermission != null) {
11407 int perm = checkComponentPermission(r.requiredPermission,
11408 filter.receiverList.pid, filter.receiverList.uid, -1);
11409 if (perm != PackageManager.PERMISSION_GRANTED) {
11410 Log.w(TAG, "Permission Denial: receiving "
11411 + r.intent.toString()
11412 + " to " + filter.receiverList.app
11413 + " (pid=" + filter.receiverList.pid
11414 + ", uid=" + filter.receiverList.uid + ")"
11415 + " requires " + r.requiredPermission
11416 + " due to sender " + r.callerPackage
11417 + " (uid " + r.callingUid + ")");
11418 skip = true;
11419 }
11420 }
11421
11422 if (!skip) {
11423 // If this is not being sent as an ordered broadcast, then we
11424 // don't want to touch the fields that keep track of the current
11425 // state of ordered broadcasts.
11426 if (ordered) {
11427 r.receiver = filter.receiverList.receiver.asBinder();
11428 r.curFilter = filter;
11429 filter.receiverList.curBroadcast = r;
11430 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011431 if (filter.receiverList.app != null) {
11432 // Bump hosting application to no longer be in background
11433 // scheduling class. Note that we can't do that if there
11434 // isn't an app... but we can only be in that case for
11435 // things that directly call the IActivityManager API, which
11436 // are already core system stuff so don't matter for this.
11437 r.curApp = filter.receiverList.app;
11438 filter.receiverList.app.curReceiver = r;
11439 updateOomAdjLocked();
11440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011441 }
11442 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011443 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011444 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011445 Log.i(TAG, "Delivering to " + filter.receiverList.app
11446 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011447 }
11448 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11449 new Intent(r.intent), r.resultCode,
11450 r.resultData, r.resultExtras, r.ordered);
11451 if (ordered) {
11452 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11453 }
11454 } catch (RemoteException e) {
11455 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11456 if (ordered) {
11457 r.receiver = null;
11458 r.curFilter = null;
11459 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011460 if (filter.receiverList.app != null) {
11461 filter.receiverList.app.curReceiver = null;
11462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011463 }
11464 }
11465 }
11466 }
11467
11468 private final void processNextBroadcast(boolean fromMsg) {
11469 synchronized(this) {
11470 BroadcastRecord r;
11471
11472 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11473 + mParallelBroadcasts.size() + " broadcasts, "
11474 + mOrderedBroadcasts.size() + " serialized broadcasts");
11475
11476 updateCpuStats();
11477
11478 if (fromMsg) {
11479 mBroadcastsScheduled = false;
11480 }
11481
11482 // First, deliver any non-serialized broadcasts right away.
11483 while (mParallelBroadcasts.size() > 0) {
11484 r = mParallelBroadcasts.remove(0);
11485 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011486 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11487 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011488 for (int i=0; i<N; i++) {
11489 Object target = r.receivers.get(i);
11490 if (DEBUG_BROADCAST) Log.v(TAG,
11491 "Delivering non-serialized to registered "
11492 + target + ": " + r);
11493 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11494 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011495 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11496 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011497 }
11498
11499 // Now take care of the next serialized one...
11500
11501 // If we are waiting for a process to come up to handle the next
11502 // broadcast, then do nothing at this point. Just in case, we
11503 // check that the process we're waiting for still exists.
11504 if (mPendingBroadcast != null) {
11505 Log.i(TAG, "processNextBroadcast: waiting for "
11506 + mPendingBroadcast.curApp);
11507
11508 boolean isDead;
11509 synchronized (mPidsSelfLocked) {
11510 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11511 }
11512 if (!isDead) {
11513 // It's still alive, so keep waiting
11514 return;
11515 } else {
11516 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11517 + " died before responding to broadcast");
11518 mPendingBroadcast = null;
11519 }
11520 }
11521
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011522 boolean looped = false;
11523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011524 do {
11525 if (mOrderedBroadcasts.size() == 0) {
11526 // No more broadcasts pending, so all done!
11527 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011528 if (looped) {
11529 // If we had finished the last ordered broadcast, then
11530 // make sure all processes have correct oom and sched
11531 // adjustments.
11532 updateOomAdjLocked();
11533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011534 return;
11535 }
11536 r = mOrderedBroadcasts.get(0);
11537 boolean forceReceive = false;
11538
11539 // Ensure that even if something goes awry with the timeout
11540 // detection, we catch "hung" broadcasts here, discard them,
11541 // and continue to make progress.
11542 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11543 long now = SystemClock.uptimeMillis();
11544 if (r.dispatchTime > 0) {
11545 if ((numReceivers > 0) &&
11546 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11547 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11548 + " now=" + now
11549 + " dispatchTime=" + r.dispatchTime
11550 + " startTime=" + r.startTime
11551 + " intent=" + r.intent
11552 + " numReceivers=" + numReceivers
11553 + " nextReceiver=" + r.nextReceiver
11554 + " state=" + r.state);
11555 broadcastTimeout(); // forcibly finish this broadcast
11556 forceReceive = true;
11557 r.state = BroadcastRecord.IDLE;
11558 }
11559 }
11560
11561 if (r.state != BroadcastRecord.IDLE) {
11562 if (DEBUG_BROADCAST) Log.d(TAG,
11563 "processNextBroadcast() called when not idle (state="
11564 + r.state + ")");
11565 return;
11566 }
11567
11568 if (r.receivers == null || r.nextReceiver >= numReceivers
11569 || r.resultAbort || forceReceive) {
11570 // No more receivers for this broadcast! Send the final
11571 // result if requested...
11572 if (r.resultTo != null) {
11573 try {
11574 if (DEBUG_BROADCAST) {
11575 int seq = r.intent.getIntExtra("seq", -1);
11576 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11577 + " seq=" + seq + " app=" + r.callerApp);
11578 }
11579 performReceive(r.callerApp, r.resultTo,
11580 new Intent(r.intent), r.resultCode,
11581 r.resultData, r.resultExtras, false);
11582 } catch (RemoteException e) {
11583 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11584 }
11585 }
11586
11587 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11588 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11589
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011590 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11591 + r);
11592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011593 // ... and on to the next...
11594 mOrderedBroadcasts.remove(0);
11595 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011596 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011597 continue;
11598 }
11599 } while (r == null);
11600
11601 // Get the next receiver...
11602 int recIdx = r.nextReceiver++;
11603
11604 // Keep track of when this receiver started, and make sure there
11605 // is a timeout message pending to kill it if need be.
11606 r.startTime = SystemClock.uptimeMillis();
11607 if (recIdx == 0) {
11608 r.dispatchTime = r.startTime;
11609
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011610 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11611 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011612 if (DEBUG_BROADCAST) Log.v(TAG,
11613 "Submitting BROADCAST_TIMEOUT_MSG for "
11614 + (r.startTime + BROADCAST_TIMEOUT));
11615 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11616 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11617 }
11618
11619 Object nextReceiver = r.receivers.get(recIdx);
11620 if (nextReceiver instanceof BroadcastFilter) {
11621 // Simple case: this is a registered receiver who gets
11622 // a direct call.
11623 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11624 if (DEBUG_BROADCAST) Log.v(TAG,
11625 "Delivering serialized to registered "
11626 + filter + ": " + r);
11627 deliverToRegisteredReceiver(r, filter, r.ordered);
11628 if (r.receiver == null || !r.ordered) {
11629 // The receiver has already finished, so schedule to
11630 // process the next one.
11631 r.state = BroadcastRecord.IDLE;
11632 scheduleBroadcastsLocked();
11633 }
11634 return;
11635 }
11636
11637 // Hard case: need to instantiate the receiver, possibly
11638 // starting its application process to host it.
11639
11640 ResolveInfo info =
11641 (ResolveInfo)nextReceiver;
11642
11643 boolean skip = false;
11644 int perm = checkComponentPermission(info.activityInfo.permission,
11645 r.callingPid, r.callingUid,
11646 info.activityInfo.exported
11647 ? -1 : info.activityInfo.applicationInfo.uid);
11648 if (perm != PackageManager.PERMISSION_GRANTED) {
11649 Log.w(TAG, "Permission Denial: broadcasting "
11650 + r.intent.toString()
11651 + " from " + r.callerPackage + " (pid=" + r.callingPid
11652 + ", uid=" + r.callingUid + ")"
11653 + " requires " + info.activityInfo.permission
11654 + " due to receiver " + info.activityInfo.packageName
11655 + "/" + info.activityInfo.name);
11656 skip = true;
11657 }
11658 if (r.callingUid != Process.SYSTEM_UID &&
11659 r.requiredPermission != null) {
11660 try {
11661 perm = ActivityThread.getPackageManager().
11662 checkPermission(r.requiredPermission,
11663 info.activityInfo.applicationInfo.packageName);
11664 } catch (RemoteException e) {
11665 perm = PackageManager.PERMISSION_DENIED;
11666 }
11667 if (perm != PackageManager.PERMISSION_GRANTED) {
11668 Log.w(TAG, "Permission Denial: receiving "
11669 + r.intent + " to "
11670 + info.activityInfo.applicationInfo.packageName
11671 + " requires " + r.requiredPermission
11672 + " due to sender " + r.callerPackage
11673 + " (uid " + r.callingUid + ")");
11674 skip = true;
11675 }
11676 }
11677 if (r.curApp != null && r.curApp.crashing) {
11678 // If the target process is crashing, just skip it.
11679 skip = true;
11680 }
11681
11682 if (skip) {
11683 r.receiver = null;
11684 r.curFilter = null;
11685 r.state = BroadcastRecord.IDLE;
11686 scheduleBroadcastsLocked();
11687 return;
11688 }
11689
11690 r.state = BroadcastRecord.APP_RECEIVE;
11691 String targetProcess = info.activityInfo.processName;
11692 r.curComponent = new ComponentName(
11693 info.activityInfo.applicationInfo.packageName,
11694 info.activityInfo.name);
11695 r.curReceiver = info.activityInfo;
11696
11697 // Is this receiver's application already running?
11698 ProcessRecord app = getProcessRecordLocked(targetProcess,
11699 info.activityInfo.applicationInfo.uid);
11700 if (app != null && app.thread != null) {
11701 try {
11702 processCurBroadcastLocked(r, app);
11703 return;
11704 } catch (RemoteException e) {
11705 Log.w(TAG, "Exception when sending broadcast to "
11706 + r.curComponent, e);
11707 }
11708
11709 // If a dead object exception was thrown -- fall through to
11710 // restart the application.
11711 }
11712
11713 // Not running -- get it started, and enqueue this history record
11714 // to be executed when the app comes up.
11715 if ((r.curApp=startProcessLocked(targetProcess,
11716 info.activityInfo.applicationInfo, true,
11717 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11718 "broadcast", r.curComponent)) == null) {
11719 // Ah, this recipient is unavailable. Finish it if necessary,
11720 // and mark the broadcast record as ready for the next.
11721 Log.w(TAG, "Unable to launch app "
11722 + info.activityInfo.applicationInfo.packageName + "/"
11723 + info.activityInfo.applicationInfo.uid + " for broadcast "
11724 + r.intent + ": process is bad");
11725 logBroadcastReceiverDiscard(r);
11726 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11727 r.resultExtras, r.resultAbort, true);
11728 scheduleBroadcastsLocked();
11729 r.state = BroadcastRecord.IDLE;
11730 return;
11731 }
11732
11733 mPendingBroadcast = r;
11734 }
11735 }
11736
11737 // =========================================================
11738 // INSTRUMENTATION
11739 // =========================================================
11740
11741 public boolean startInstrumentation(ComponentName className,
11742 String profileFile, int flags, Bundle arguments,
11743 IInstrumentationWatcher watcher) {
11744 // Refuse possible leaked file descriptors
11745 if (arguments != null && arguments.hasFileDescriptors()) {
11746 throw new IllegalArgumentException("File descriptors passed in Bundle");
11747 }
11748
11749 synchronized(this) {
11750 InstrumentationInfo ii = null;
11751 ApplicationInfo ai = null;
11752 try {
11753 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011754 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011755 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011756 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011757 } catch (PackageManager.NameNotFoundException e) {
11758 }
11759 if (ii == null) {
11760 reportStartInstrumentationFailure(watcher, className,
11761 "Unable to find instrumentation info for: " + className);
11762 return false;
11763 }
11764 if (ai == null) {
11765 reportStartInstrumentationFailure(watcher, className,
11766 "Unable to find instrumentation target package: " + ii.targetPackage);
11767 return false;
11768 }
11769
11770 int match = mContext.getPackageManager().checkSignatures(
11771 ii.targetPackage, ii.packageName);
11772 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11773 String msg = "Permission Denial: starting instrumentation "
11774 + className + " from pid="
11775 + Binder.getCallingPid()
11776 + ", uid=" + Binder.getCallingPid()
11777 + " not allowed because package " + ii.packageName
11778 + " does not have a signature matching the target "
11779 + ii.targetPackage;
11780 reportStartInstrumentationFailure(watcher, className, msg);
11781 throw new SecurityException(msg);
11782 }
11783
11784 final long origId = Binder.clearCallingIdentity();
11785 uninstallPackageLocked(ii.targetPackage, -1, true);
11786 ProcessRecord app = addAppLocked(ai);
11787 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011788 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011789 app.instrumentationProfileFile = profileFile;
11790 app.instrumentationArguments = arguments;
11791 app.instrumentationWatcher = watcher;
11792 app.instrumentationResultClass = className;
11793 Binder.restoreCallingIdentity(origId);
11794 }
11795
11796 return true;
11797 }
11798
11799 /**
11800 * Report errors that occur while attempting to start Instrumentation. Always writes the
11801 * error to the logs, but if somebody is watching, send the report there too. This enables
11802 * the "am" command to report errors with more information.
11803 *
11804 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11805 * @param cn The component name of the instrumentation.
11806 * @param report The error report.
11807 */
11808 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11809 ComponentName cn, String report) {
11810 Log.w(TAG, report);
11811 try {
11812 if (watcher != null) {
11813 Bundle results = new Bundle();
11814 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11815 results.putString("Error", report);
11816 watcher.instrumentationStatus(cn, -1, results);
11817 }
11818 } catch (RemoteException e) {
11819 Log.w(TAG, e);
11820 }
11821 }
11822
11823 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11824 if (app.instrumentationWatcher != null) {
11825 try {
11826 // NOTE: IInstrumentationWatcher *must* be oneway here
11827 app.instrumentationWatcher.instrumentationFinished(
11828 app.instrumentationClass,
11829 resultCode,
11830 results);
11831 } catch (RemoteException e) {
11832 }
11833 }
11834 app.instrumentationWatcher = null;
11835 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011836 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011837 app.instrumentationProfileFile = null;
11838 app.instrumentationArguments = null;
11839
11840 uninstallPackageLocked(app.processName, -1, false);
11841 }
11842
11843 public void finishInstrumentation(IApplicationThread target,
11844 int resultCode, Bundle results) {
11845 // Refuse possible leaked file descriptors
11846 if (results != null && results.hasFileDescriptors()) {
11847 throw new IllegalArgumentException("File descriptors passed in Intent");
11848 }
11849
11850 synchronized(this) {
11851 ProcessRecord app = getRecordForAppLocked(target);
11852 if (app == null) {
11853 Log.w(TAG, "finishInstrumentation: no app for " + target);
11854 return;
11855 }
11856 final long origId = Binder.clearCallingIdentity();
11857 finishInstrumentationLocked(app, resultCode, results);
11858 Binder.restoreCallingIdentity(origId);
11859 }
11860 }
11861
11862 // =========================================================
11863 // CONFIGURATION
11864 // =========================================================
11865
11866 public ConfigurationInfo getDeviceConfigurationInfo() {
11867 ConfigurationInfo config = new ConfigurationInfo();
11868 synchronized (this) {
11869 config.reqTouchScreen = mConfiguration.touchscreen;
11870 config.reqKeyboardType = mConfiguration.keyboard;
11871 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011872 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11873 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011874 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11875 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011876 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11877 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011878 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11879 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070011880 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011881 }
11882 return config;
11883 }
11884
11885 public Configuration getConfiguration() {
11886 Configuration ci;
11887 synchronized(this) {
11888 ci = new Configuration(mConfiguration);
11889 }
11890 return ci;
11891 }
11892
11893 public void updateConfiguration(Configuration values) {
11894 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11895 "updateConfiguration()");
11896
11897 synchronized(this) {
11898 if (values == null && mWindowManager != null) {
11899 // sentinel: fetch the current configuration from the window manager
11900 values = mWindowManager.computeNewConfiguration();
11901 }
11902
11903 final long origId = Binder.clearCallingIdentity();
11904 updateConfigurationLocked(values, null);
11905 Binder.restoreCallingIdentity(origId);
11906 }
11907 }
11908
11909 /**
11910 * Do either or both things: (1) change the current configuration, and (2)
11911 * make sure the given activity is running with the (now) current
11912 * configuration. Returns true if the activity has been left running, or
11913 * false if <var>starting</var> is being destroyed to match the new
11914 * configuration.
11915 */
11916 public boolean updateConfigurationLocked(Configuration values,
11917 HistoryRecord starting) {
11918 int changes = 0;
11919
11920 boolean kept = true;
11921
11922 if (values != null) {
11923 Configuration newConfig = new Configuration(mConfiguration);
11924 changes = newConfig.updateFrom(values);
11925 if (changes != 0) {
11926 if (DEBUG_SWITCH) {
11927 Log.i(TAG, "Updating configuration to: " + values);
11928 }
11929
11930 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11931
11932 if (values.locale != null) {
11933 saveLocaleLocked(values.locale,
11934 !values.locale.equals(mConfiguration.locale),
11935 values.userSetLocale);
11936 }
11937
11938 mConfiguration = newConfig;
11939
11940 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11941 msg.obj = new Configuration(mConfiguration);
11942 mHandler.sendMessage(msg);
11943
11944 final int N = mLRUProcesses.size();
11945 for (int i=0; i<N; i++) {
11946 ProcessRecord app = mLRUProcesses.get(i);
11947 try {
11948 if (app.thread != null) {
11949 app.thread.scheduleConfigurationChanged(mConfiguration);
11950 }
11951 } catch (Exception e) {
11952 }
11953 }
11954 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11955 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11956 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011957
11958 AttributeCache ac = AttributeCache.instance();
11959 if (ac != null) {
11960 ac.updateConfiguration(mConfiguration);
11961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011962 }
11963 }
11964
11965 if (changes != 0 && starting == null) {
11966 // If the configuration changed, and the caller is not already
11967 // in the process of starting an activity, then find the top
11968 // activity to check if its configuration needs to change.
11969 starting = topRunningActivityLocked(null);
11970 }
11971
11972 if (starting != null) {
11973 kept = ensureActivityConfigurationLocked(starting, changes);
11974 if (kept) {
11975 // If this didn't result in the starting activity being
11976 // destroyed, then we need to make sure at this point that all
11977 // other activities are made visible.
11978 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11979 + ", ensuring others are correct.");
11980 ensureActivitiesVisibleLocked(starting, changes);
11981 }
11982 }
11983
11984 return kept;
11985 }
11986
11987 private final boolean relaunchActivityLocked(HistoryRecord r,
11988 int changes, boolean andResume) {
11989 List<ResultInfo> results = null;
11990 List<Intent> newIntents = null;
11991 if (andResume) {
11992 results = r.results;
11993 newIntents = r.newIntents;
11994 }
11995 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11996 + " with results=" + results + " newIntents=" + newIntents
11997 + " andResume=" + andResume);
11998 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11999 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12000 r.task.taskId, r.shortComponentName);
12001
12002 r.startFreezingScreenLocked(r.app, 0);
12003
12004 try {
12005 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12006 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12007 changes, !andResume);
12008 // Note: don't need to call pauseIfSleepingLocked() here, because
12009 // the caller will only pass in 'andResume' if this activity is
12010 // currently resumed, which implies we aren't sleeping.
12011 } catch (RemoteException e) {
12012 return false;
12013 }
12014
12015 if (andResume) {
12016 r.results = null;
12017 r.newIntents = null;
12018 }
12019
12020 return true;
12021 }
12022
12023 /**
12024 * Make sure the given activity matches the current configuration. Returns
12025 * false if the activity had to be destroyed. Returns true if the
12026 * configuration is the same, or the activity will remain running as-is
12027 * for whatever reason. Ensures the HistoryRecord is updated with the
12028 * correct configuration and all other bookkeeping is handled.
12029 */
12030 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12031 int globalChanges) {
12032 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12033
12034 // Short circuit: if the two configurations are the exact same
12035 // object (the common case), then there is nothing to do.
12036 Configuration newConfig = mConfiguration;
12037 if (r.configuration == newConfig) {
12038 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12039 return true;
12040 }
12041
12042 // We don't worry about activities that are finishing.
12043 if (r.finishing) {
12044 if (DEBUG_SWITCH) Log.i(TAG,
12045 "Configuration doesn't matter in finishing " + r);
12046 r.stopFreezingScreenLocked(false);
12047 return true;
12048 }
12049
12050 // Okay we now are going to make this activity have the new config.
12051 // But then we need to figure out how it needs to deal with that.
12052 Configuration oldConfig = r.configuration;
12053 r.configuration = newConfig;
12054
12055 // If the activity isn't currently running, just leave the new
12056 // configuration and it will pick that up next time it starts.
12057 if (r.app == null || r.app.thread == null) {
12058 if (DEBUG_SWITCH) Log.i(TAG,
12059 "Configuration doesn't matter not running " + r);
12060 r.stopFreezingScreenLocked(false);
12061 return true;
12062 }
12063
12064 // If the activity isn't persistent, there is a chance we will
12065 // need to restart it.
12066 if (!r.persistent) {
12067
12068 // Figure out what has changed between the two configurations.
12069 int changes = oldConfig.diff(newConfig);
12070 if (DEBUG_SWITCH) {
12071 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12072 + Integer.toHexString(changes) + ", handles=0x"
12073 + Integer.toHexString(r.info.configChanges));
12074 }
12075 if ((changes&(~r.info.configChanges)) != 0) {
12076 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12077 r.configChangeFlags |= changes;
12078 r.startFreezingScreenLocked(r.app, globalChanges);
12079 if (r.app == null || r.app.thread == null) {
12080 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12081 destroyActivityLocked(r, true);
12082 } else if (r.state == ActivityState.PAUSING) {
12083 // A little annoying: we are waiting for this activity to
12084 // finish pausing. Let's not do anything now, but just
12085 // flag that it needs to be restarted when done pausing.
12086 r.configDestroy = true;
12087 return true;
12088 } else if (r.state == ActivityState.RESUMED) {
12089 // Try to optimize this case: the configuration is changing
12090 // and we need to restart the top, resumed activity.
12091 // Instead of doing the normal handshaking, just say
12092 // "restart!".
12093 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12094 relaunchActivityLocked(r, r.configChangeFlags, true);
12095 r.configChangeFlags = 0;
12096 } else {
12097 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12098 relaunchActivityLocked(r, r.configChangeFlags, false);
12099 r.configChangeFlags = 0;
12100 }
12101
12102 // All done... tell the caller we weren't able to keep this
12103 // activity around.
12104 return false;
12105 }
12106 }
12107
12108 // Default case: the activity can handle this new configuration, so
12109 // hand it over. Note that we don't need to give it the new
12110 // configuration, since we always send configuration changes to all
12111 // process when they happen so it can just use whatever configuration
12112 // it last got.
12113 if (r.app != null && r.app.thread != null) {
12114 try {
12115 r.app.thread.scheduleActivityConfigurationChanged(r);
12116 } catch (RemoteException e) {
12117 // If process died, whatever.
12118 }
12119 }
12120 r.stopFreezingScreenLocked(false);
12121
12122 return true;
12123 }
12124
12125 /**
12126 * Save the locale. You must be inside a synchronized (this) block.
12127 */
12128 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12129 if(isDiff) {
12130 SystemProperties.set("user.language", l.getLanguage());
12131 SystemProperties.set("user.region", l.getCountry());
12132 }
12133
12134 if(isPersist) {
12135 SystemProperties.set("persist.sys.language", l.getLanguage());
12136 SystemProperties.set("persist.sys.country", l.getCountry());
12137 SystemProperties.set("persist.sys.localevar", l.getVariant());
12138 }
12139 }
12140
12141 // =========================================================
12142 // LIFETIME MANAGEMENT
12143 // =========================================================
12144
12145 private final int computeOomAdjLocked(
12146 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12147 if (mAdjSeq == app.adjSeq) {
12148 // This adjustment has already been computed.
12149 return app.curAdj;
12150 }
12151
12152 if (app.thread == null) {
12153 app.adjSeq = mAdjSeq;
12154 return (app.curAdj=EMPTY_APP_ADJ);
12155 }
12156
12157 app.isForeground = false;
12158
The Android Open Source Project4df24232009-03-05 14:34:35 -080012159 // Determine the importance of the process, starting with most
12160 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012161 int adj;
12162 int N;
12163 if (app == TOP_APP || app.instrumentationClass != null
12164 || app.persistentActivities > 0) {
12165 // The last app on the list is the foreground app.
12166 adj = FOREGROUND_APP_ADJ;
12167 app.isForeground = true;
12168 } else if (app.curReceiver != null ||
12169 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12170 // An app that is currently receiving a broadcast also
12171 // counts as being in the foreground.
12172 adj = FOREGROUND_APP_ADJ;
12173 } else if (app.executingServices.size() > 0) {
12174 // An app that is currently executing a service callback also
12175 // counts as being in the foreground.
12176 adj = FOREGROUND_APP_ADJ;
12177 } else if (app.foregroundServices || app.forcingToForeground != null) {
12178 // The user is aware of this app, so make it visible.
12179 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012180 } else if (app == mHomeProcess) {
12181 // This process is hosting what we currently consider to be the
12182 // home app, so we don't want to let it go into the background.
12183 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012184 } else if ((N=app.activities.size()) != 0) {
12185 // This app is in the background with paused activities.
12186 adj = hiddenAdj;
12187 for (int j=0; j<N; j++) {
12188 if (((HistoryRecord)app.activities.get(j)).visible) {
12189 // This app has a visible activity!
12190 adj = VISIBLE_APP_ADJ;
12191 break;
12192 }
12193 }
12194 } else {
12195 // A very not-needed process.
12196 adj = EMPTY_APP_ADJ;
12197 }
12198
The Android Open Source Project4df24232009-03-05 14:34:35 -080012199 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012200 // there are applications dependent on our services or providers, but
12201 // this gives us a baseline and makes sure we don't get into an
12202 // infinite recursion.
12203 app.adjSeq = mAdjSeq;
12204 app.curRawAdj = adj;
12205 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12206
Christopher Tate6fa95972009-06-05 18:43:55 -070012207 if (mBackupTarget != null && app == mBackupTarget.app) {
12208 // If possible we want to avoid killing apps while they're being backed up
12209 if (adj > BACKUP_APP_ADJ) {
12210 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12211 adj = BACKUP_APP_ADJ;
12212 }
12213 }
12214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012215 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12216 // If this process has active services running in it, we would
12217 // like to avoid killing it unless it would prevent the current
12218 // application from running.
12219 if (adj > hiddenAdj) {
12220 adj = hiddenAdj;
12221 }
12222 final long now = SystemClock.uptimeMillis();
12223 // This process is more important if the top activity is
12224 // bound to the service.
12225 Iterator jt = app.services.iterator();
12226 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12227 ServiceRecord s = (ServiceRecord)jt.next();
12228 if (s.startRequested) {
12229 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12230 // This service has seen some activity within
12231 // recent memory, so we will keep its process ahead
12232 // of the background processes.
12233 if (adj > SECONDARY_SERVER_ADJ) {
12234 adj = SECONDARY_SERVER_ADJ;
12235 }
12236 } else {
12237 // This service has been inactive for too long, just
12238 // put it with the rest of the background processes.
12239 if (adj > hiddenAdj) {
12240 adj = hiddenAdj;
12241 }
12242 }
12243 }
12244 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12245 Iterator<ConnectionRecord> kt
12246 = s.connections.values().iterator();
12247 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12248 // XXX should compute this based on the max of
12249 // all connected clients.
12250 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012251 if (cr.binding.client == app) {
12252 // Binding to ourself is not interesting.
12253 continue;
12254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012255 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12256 ProcessRecord client = cr.binding.client;
12257 int myHiddenAdj = hiddenAdj;
12258 if (myHiddenAdj > client.hiddenAdj) {
12259 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12260 myHiddenAdj = client.hiddenAdj;
12261 } else {
12262 myHiddenAdj = VISIBLE_APP_ADJ;
12263 }
12264 }
12265 int clientAdj = computeOomAdjLocked(
12266 client, myHiddenAdj, TOP_APP);
12267 if (adj > clientAdj) {
12268 adj = clientAdj > VISIBLE_APP_ADJ
12269 ? clientAdj : VISIBLE_APP_ADJ;
12270 }
12271 }
12272 HistoryRecord a = cr.activity;
12273 //if (a != null) {
12274 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12275 //}
12276 if (a != null && adj > FOREGROUND_APP_ADJ &&
12277 (a.state == ActivityState.RESUMED
12278 || a.state == ActivityState.PAUSING)) {
12279 adj = FOREGROUND_APP_ADJ;
12280 }
12281 }
12282 }
12283 }
12284 }
12285
12286 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12287 // If this process has published any content providers, then
12288 // its adjustment makes it at least as important as any of the
12289 // processes using those providers, and no less important than
12290 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12291 if (adj > CONTENT_PROVIDER_ADJ) {
12292 adj = CONTENT_PROVIDER_ADJ;
12293 }
12294 Iterator jt = app.pubProviders.values().iterator();
12295 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12296 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12297 if (cpr.clients.size() != 0) {
12298 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12299 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12300 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012301 if (client == app) {
12302 // Being our own client is not interesting.
12303 continue;
12304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012305 int myHiddenAdj = hiddenAdj;
12306 if (myHiddenAdj > client.hiddenAdj) {
12307 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12308 myHiddenAdj = client.hiddenAdj;
12309 } else {
12310 myHiddenAdj = FOREGROUND_APP_ADJ;
12311 }
12312 }
12313 int clientAdj = computeOomAdjLocked(
12314 client, myHiddenAdj, TOP_APP);
12315 if (adj > clientAdj) {
12316 adj = clientAdj > FOREGROUND_APP_ADJ
12317 ? clientAdj : FOREGROUND_APP_ADJ;
12318 }
12319 }
12320 }
12321 // If the provider has external (non-framework) process
12322 // dependencies, ensure that its adjustment is at least
12323 // FOREGROUND_APP_ADJ.
12324 if (cpr.externals != 0) {
12325 if (adj > FOREGROUND_APP_ADJ) {
12326 adj = FOREGROUND_APP_ADJ;
12327 }
12328 }
12329 }
12330 }
12331
12332 app.curRawAdj = adj;
12333
12334 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12335 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12336 if (adj > app.maxAdj) {
12337 adj = app.maxAdj;
12338 }
12339
12340 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012341 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12342 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12343 : Process.THREAD_GROUP_DEFAULT;
12344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012345 return adj;
12346 }
12347
12348 /**
12349 * Ask a given process to GC right now.
12350 */
12351 final void performAppGcLocked(ProcessRecord app) {
12352 try {
12353 app.lastRequestedGc = SystemClock.uptimeMillis();
12354 if (app.thread != null) {
12355 app.thread.processInBackground();
12356 }
12357 } catch (Exception e) {
12358 // whatever.
12359 }
12360 }
12361
12362 /**
12363 * Returns true if things are idle enough to perform GCs.
12364 */
12365 private final boolean canGcNow() {
12366 return mParallelBroadcasts.size() == 0
12367 && mOrderedBroadcasts.size() == 0
12368 && (mSleeping || (mResumedActivity != null &&
12369 mResumedActivity.idle));
12370 }
12371
12372 /**
12373 * Perform GCs on all processes that are waiting for it, but only
12374 * if things are idle.
12375 */
12376 final void performAppGcsLocked() {
12377 final int N = mProcessesToGc.size();
12378 if (N <= 0) {
12379 return;
12380 }
12381 if (canGcNow()) {
12382 while (mProcessesToGc.size() > 0) {
12383 ProcessRecord proc = mProcessesToGc.remove(0);
12384 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12385 // To avoid spamming the system, we will GC processes one
12386 // at a time, waiting a few seconds between each.
12387 performAppGcLocked(proc);
12388 scheduleAppGcsLocked();
12389 return;
12390 }
12391 }
12392 }
12393 }
12394
12395 /**
12396 * If all looks good, perform GCs on all processes waiting for them.
12397 */
12398 final void performAppGcsIfAppropriateLocked() {
12399 if (canGcNow()) {
12400 performAppGcsLocked();
12401 return;
12402 }
12403 // Still not idle, wait some more.
12404 scheduleAppGcsLocked();
12405 }
12406
12407 /**
12408 * Schedule the execution of all pending app GCs.
12409 */
12410 final void scheduleAppGcsLocked() {
12411 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12412 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12413 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12414 }
12415
12416 /**
12417 * Set up to ask a process to GC itself. This will either do it
12418 * immediately, or put it on the list of processes to gc the next
12419 * time things are idle.
12420 */
12421 final void scheduleAppGcLocked(ProcessRecord app) {
12422 long now = SystemClock.uptimeMillis();
12423 if ((app.lastRequestedGc+5000) > now) {
12424 return;
12425 }
12426 if (!mProcessesToGc.contains(app)) {
12427 mProcessesToGc.add(app);
12428 scheduleAppGcsLocked();
12429 }
12430 }
12431
12432 private final boolean updateOomAdjLocked(
12433 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12434 app.hiddenAdj = hiddenAdj;
12435
12436 if (app.thread == null) {
12437 return true;
12438 }
12439
12440 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12441
12442 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12443 //Thread priority adjustment is disabled out to see
12444 //how the kernel scheduler performs.
12445 if (false) {
12446 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12447 app.setIsForeground = app.isForeground;
12448 if (app.pid != MY_PID) {
12449 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12450 + " to " + (app.isForeground
12451 ? Process.THREAD_PRIORITY_FOREGROUND
12452 : Process.THREAD_PRIORITY_DEFAULT));
12453 try {
12454 Process.setThreadPriority(app.pid, app.isForeground
12455 ? Process.THREAD_PRIORITY_FOREGROUND
12456 : Process.THREAD_PRIORITY_DEFAULT);
12457 } catch (RuntimeException e) {
12458 Log.w(TAG, "Exception trying to set priority of application thread "
12459 + app.pid, e);
12460 }
12461 }
12462 }
12463 }
12464 if (app.pid != 0 && app.pid != MY_PID) {
12465 if (app.curRawAdj != app.setRawAdj) {
12466 if (app.curRawAdj > FOREGROUND_APP_ADJ
12467 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12468 // If this app is transitioning from foreground to
12469 // non-foreground, have it do a gc.
12470 scheduleAppGcLocked(app);
12471 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12472 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12473 // Likewise do a gc when an app is moving in to the
12474 // background (such as a service stopping).
12475 scheduleAppGcLocked(app);
12476 }
12477 app.setRawAdj = app.curRawAdj;
12478 }
12479 if (adj != app.setAdj) {
12480 if (Process.setOomAdj(app.pid, adj)) {
12481 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12482 TAG, "Set app " + app.processName +
12483 " oom adj to " + adj);
12484 app.setAdj = adj;
12485 } else {
12486 return false;
12487 }
12488 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012489 if (app.setSchedGroup != app.curSchedGroup) {
12490 app.setSchedGroup = app.curSchedGroup;
12491 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12492 "Setting process group of " + app.processName
12493 + " to " + app.curSchedGroup);
12494 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012495 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012496 try {
12497 Process.setProcessGroup(app.pid, app.curSchedGroup);
12498 } catch (Exception e) {
12499 Log.w(TAG, "Failed setting process group of " + app.pid
12500 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012501 e.printStackTrace();
12502 } finally {
12503 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012504 }
12505 }
12506 if (false) {
12507 if (app.thread != null) {
12508 try {
12509 app.thread.setSchedulingGroup(app.curSchedGroup);
12510 } catch (RemoteException e) {
12511 }
12512 }
12513 }
12514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012515 }
12516
12517 return true;
12518 }
12519
12520 private final HistoryRecord resumedAppLocked() {
12521 HistoryRecord resumedActivity = mResumedActivity;
12522 if (resumedActivity == null || resumedActivity.app == null) {
12523 resumedActivity = mPausingActivity;
12524 if (resumedActivity == null || resumedActivity.app == null) {
12525 resumedActivity = topRunningActivityLocked(null);
12526 }
12527 }
12528 return resumedActivity;
12529 }
12530
12531 private final boolean updateOomAdjLocked(ProcessRecord app) {
12532 final HistoryRecord TOP_ACT = resumedAppLocked();
12533 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12534 int curAdj = app.curAdj;
12535 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12536 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12537
12538 mAdjSeq++;
12539
12540 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12541 if (res) {
12542 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12543 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12544 if (nowHidden != wasHidden) {
12545 // Changed to/from hidden state, so apps after it in the LRU
12546 // list may also be changed.
12547 updateOomAdjLocked();
12548 }
12549 }
12550 return res;
12551 }
12552
12553 private final boolean updateOomAdjLocked() {
12554 boolean didOomAdj = true;
12555 final HistoryRecord TOP_ACT = resumedAppLocked();
12556 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12557
12558 if (false) {
12559 RuntimeException e = new RuntimeException();
12560 e.fillInStackTrace();
12561 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12562 }
12563
12564 mAdjSeq++;
12565
12566 // First try updating the OOM adjustment for each of the
12567 // application processes based on their current state.
12568 int i = mLRUProcesses.size();
12569 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12570 while (i > 0) {
12571 i--;
12572 ProcessRecord app = mLRUProcesses.get(i);
12573 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12574 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12575 && app.curAdj == curHiddenAdj) {
12576 curHiddenAdj++;
12577 }
12578 } else {
12579 didOomAdj = false;
12580 }
12581 }
12582
12583 // todo: for now pretend like OOM ADJ didn't work, because things
12584 // aren't behaving as expected on Linux -- it's not killing processes.
12585 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12586 }
12587
12588 private final void trimApplications() {
12589 synchronized (this) {
12590 int i;
12591
12592 // First remove any unused application processes whose package
12593 // has been removed.
12594 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12595 final ProcessRecord app = mRemovedProcesses.get(i);
12596 if (app.activities.size() == 0
12597 && app.curReceiver == null && app.services.size() == 0) {
12598 Log.i(
12599 TAG, "Exiting empty application process "
12600 + app.processName + " ("
12601 + (app.thread != null ? app.thread.asBinder() : null)
12602 + ")\n");
12603 if (app.pid > 0 && app.pid != MY_PID) {
12604 Process.killProcess(app.pid);
12605 } else {
12606 try {
12607 app.thread.scheduleExit();
12608 } catch (Exception e) {
12609 // Ignore exceptions.
12610 }
12611 }
12612 cleanUpApplicationRecordLocked(app, false, -1);
12613 mRemovedProcesses.remove(i);
12614
12615 if (app.persistent) {
12616 if (app.persistent) {
12617 addAppLocked(app.info);
12618 }
12619 }
12620 }
12621 }
12622
12623 // Now try updating the OOM adjustment for each of the
12624 // application processes based on their current state.
12625 // If the setOomAdj() API is not supported, then go with our
12626 // back-up plan...
12627 if (!updateOomAdjLocked()) {
12628
12629 // Count how many processes are running services.
12630 int numServiceProcs = 0;
12631 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12632 final ProcessRecord app = mLRUProcesses.get(i);
12633
12634 if (app.persistent || app.services.size() != 0
12635 || app.curReceiver != null
12636 || app.persistentActivities > 0) {
12637 // Don't count processes holding services against our
12638 // maximum process count.
12639 if (localLOGV) Log.v(
12640 TAG, "Not trimming app " + app + " with services: "
12641 + app.services);
12642 numServiceProcs++;
12643 }
12644 }
12645
12646 int curMaxProcs = mProcessLimit;
12647 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12648 if (mAlwaysFinishActivities) {
12649 curMaxProcs = 1;
12650 }
12651 curMaxProcs += numServiceProcs;
12652
12653 // Quit as many processes as we can to get down to the desired
12654 // process count. First remove any processes that no longer
12655 // have activites running in them.
12656 for ( i=0;
12657 i<mLRUProcesses.size()
12658 && mLRUProcesses.size() > curMaxProcs;
12659 i++) {
12660 final ProcessRecord app = mLRUProcesses.get(i);
12661 // Quit an application only if it is not currently
12662 // running any activities.
12663 if (!app.persistent && app.activities.size() == 0
12664 && app.curReceiver == null && app.services.size() == 0) {
12665 Log.i(
12666 TAG, "Exiting empty application process "
12667 + app.processName + " ("
12668 + (app.thread != null ? app.thread.asBinder() : null)
12669 + ")\n");
12670 if (app.pid > 0 && app.pid != MY_PID) {
12671 Process.killProcess(app.pid);
12672 } else {
12673 try {
12674 app.thread.scheduleExit();
12675 } catch (Exception e) {
12676 // Ignore exceptions.
12677 }
12678 }
12679 // todo: For now we assume the application is not buggy
12680 // or evil, and will quit as a result of our request.
12681 // Eventually we need to drive this off of the death
12682 // notification, and kill the process if it takes too long.
12683 cleanUpApplicationRecordLocked(app, false, i);
12684 i--;
12685 }
12686 }
12687
12688 // If we still have too many processes, now from the least
12689 // recently used process we start finishing activities.
12690 if (Config.LOGV) Log.v(
12691 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12692 " of " + curMaxProcs + " processes");
12693 for ( i=0;
12694 i<mLRUProcesses.size()
12695 && mLRUProcesses.size() > curMaxProcs;
12696 i++) {
12697 final ProcessRecord app = mLRUProcesses.get(i);
12698 // Quit the application only if we have a state saved for
12699 // all of its activities.
12700 boolean canQuit = !app.persistent && app.curReceiver == null
12701 && app.services.size() == 0
12702 && app.persistentActivities == 0;
12703 int NUMA = app.activities.size();
12704 int j;
12705 if (Config.LOGV) Log.v(
12706 TAG, "Looking to quit " + app.processName);
12707 for (j=0; j<NUMA && canQuit; j++) {
12708 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12709 if (Config.LOGV) Log.v(
12710 TAG, " " + r.intent.getComponent().flattenToShortString()
12711 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12712 canQuit = (r.haveState || !r.stateNotNeeded)
12713 && !r.visible && r.stopped;
12714 }
12715 if (canQuit) {
12716 // Finish all of the activities, and then the app itself.
12717 for (j=0; j<NUMA; j++) {
12718 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12719 if (!r.finishing) {
12720 destroyActivityLocked(r, false);
12721 }
12722 r.resultTo = null;
12723 }
12724 Log.i(TAG, "Exiting application process "
12725 + app.processName + " ("
12726 + (app.thread != null ? app.thread.asBinder() : null)
12727 + ")\n");
12728 if (app.pid > 0 && app.pid != MY_PID) {
12729 Process.killProcess(app.pid);
12730 } else {
12731 try {
12732 app.thread.scheduleExit();
12733 } catch (Exception e) {
12734 // Ignore exceptions.
12735 }
12736 }
12737 // todo: For now we assume the application is not buggy
12738 // or evil, and will quit as a result of our request.
12739 // Eventually we need to drive this off of the death
12740 // notification, and kill the process if it takes too long.
12741 cleanUpApplicationRecordLocked(app, false, i);
12742 i--;
12743 //dump();
12744 }
12745 }
12746
12747 }
12748
12749 int curMaxActivities = MAX_ACTIVITIES;
12750 if (mAlwaysFinishActivities) {
12751 curMaxActivities = 1;
12752 }
12753
12754 // Finally, if there are too many activities now running, try to
12755 // finish as many as we can to get back down to the limit.
12756 for ( i=0;
12757 i<mLRUActivities.size()
12758 && mLRUActivities.size() > curMaxActivities;
12759 i++) {
12760 final HistoryRecord r
12761 = (HistoryRecord)mLRUActivities.get(i);
12762
12763 // We can finish this one if we have its icicle saved and
12764 // it is not persistent.
12765 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12766 && r.stopped && !r.persistent && !r.finishing) {
12767 final int origSize = mLRUActivities.size();
12768 destroyActivityLocked(r, true);
12769
12770 // This will remove it from the LRU list, so keep
12771 // our index at the same value. Note that this check to
12772 // see if the size changes is just paranoia -- if
12773 // something unexpected happens, we don't want to end up
12774 // in an infinite loop.
12775 if (origSize > mLRUActivities.size()) {
12776 i--;
12777 }
12778 }
12779 }
12780 }
12781 }
12782
12783 /** This method sends the specified signal to each of the persistent apps */
12784 public void signalPersistentProcesses(int sig) throws RemoteException {
12785 if (sig != Process.SIGNAL_USR1) {
12786 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12787 }
12788
12789 synchronized (this) {
12790 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12791 != PackageManager.PERMISSION_GRANTED) {
12792 throw new SecurityException("Requires permission "
12793 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12794 }
12795
12796 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12797 ProcessRecord r = mLRUProcesses.get(i);
12798 if (r.thread != null && r.persistent) {
12799 Process.sendSignal(r.pid, sig);
12800 }
12801 }
12802 }
12803 }
12804
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012805 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012806 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012807
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012808 try {
12809 synchronized (this) {
12810 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12811 // its own permission.
12812 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12813 != PackageManager.PERMISSION_GRANTED) {
12814 throw new SecurityException("Requires permission "
12815 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012816 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012817
12818 if (start && fd == null) {
12819 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012820 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012821
12822 ProcessRecord proc = null;
12823 try {
12824 int pid = Integer.parseInt(process);
12825 synchronized (mPidsSelfLocked) {
12826 proc = mPidsSelfLocked.get(pid);
12827 }
12828 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012829 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012830
12831 if (proc == null) {
12832 HashMap<String, SparseArray<ProcessRecord>> all
12833 = mProcessNames.getMap();
12834 SparseArray<ProcessRecord> procs = all.get(process);
12835 if (procs != null && procs.size() > 0) {
12836 proc = procs.valueAt(0);
12837 }
12838 }
12839
12840 if (proc == null || proc.thread == null) {
12841 throw new IllegalArgumentException("Unknown process: " + process);
12842 }
12843
12844 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12845 if (isSecure) {
12846 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12847 throw new SecurityException("Process not debuggable: " + proc);
12848 }
12849 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012850
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012851 proc.thread.profilerControl(start, path, fd);
12852 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012853 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012854 }
12855 } catch (RemoteException e) {
12856 throw new IllegalStateException("Process disappeared");
12857 } finally {
12858 if (fd != null) {
12859 try {
12860 fd.close();
12861 } catch (IOException e) {
12862 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012863 }
12864 }
12865 }
12866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012867 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12868 public void monitor() {
12869 synchronized (this) { }
12870 }
12871}