blob: 81a715d972e2ea79c51d36feb3acee2a16b1cbd5 [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 }
4739
4740 private void restartPackageLocked(final String packageName, int uid) {
4741 uninstallPackageLocked(packageName, uid, false);
4742 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4743 Uri.fromParts("package", packageName, null));
4744 intent.putExtra(Intent.EXTRA_UID, uid);
4745 broadcastIntentLocked(null, null, intent,
4746 null, null, 0, null, null, null,
4747 false, false, MY_PID, Process.SYSTEM_UID);
4748 }
4749
4750 private final void uninstallPackageLocked(String name, int uid,
4751 boolean callerWillRestart) {
4752 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4753
4754 int i, N;
4755
4756 final String procNamePrefix = name + ":";
4757 if (uid < 0) {
4758 try {
4759 uid = ActivityThread.getPackageManager().getPackageUid(name);
4760 } catch (RemoteException e) {
4761 }
4762 }
4763
4764 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4765 while (badApps.hasNext()) {
4766 SparseArray<Long> ba = badApps.next();
4767 if (ba.get(uid) != null) {
4768 badApps.remove();
4769 }
4770 }
4771
4772 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4773
4774 // Remove all processes this package may have touched: all with the
4775 // same UID (except for the system or root user), and all whose name
4776 // matches the package name.
4777 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4778 final int NA = apps.size();
4779 for (int ia=0; ia<NA; ia++) {
4780 ProcessRecord app = apps.valueAt(ia);
4781 if (app.removed) {
4782 procs.add(app);
4783 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4784 || app.processName.equals(name)
4785 || app.processName.startsWith(procNamePrefix)) {
4786 app.removed = true;
4787 procs.add(app);
4788 }
4789 }
4790 }
4791
4792 N = procs.size();
4793 for (i=0; i<N; i++) {
4794 removeProcessLocked(procs.get(i), callerWillRestart);
4795 }
4796
4797 for (i=mHistory.size()-1; i>=0; i--) {
4798 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4799 if (r.packageName.equals(name)) {
4800 if (Config.LOGD) Log.d(
4801 TAG, " Force finishing activity "
4802 + r.intent.getComponent().flattenToShortString());
4803 if (r.app != null) {
4804 r.app.removed = true;
4805 }
4806 r.app = null;
4807 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4808 }
4809 }
4810
4811 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4812 for (ServiceRecord service : mServices.values()) {
4813 if (service.packageName.equals(name)) {
4814 if (service.app != null) {
4815 service.app.removed = true;
4816 }
4817 service.app = null;
4818 services.add(service);
4819 }
4820 }
4821
4822 N = services.size();
4823 for (i=0; i<N; i++) {
4824 bringDownServiceLocked(services.get(i), true);
4825 }
4826
4827 resumeTopActivityLocked(null);
4828 }
4829
4830 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4831 final String name = app.processName;
4832 final int uid = app.info.uid;
4833 if (Config.LOGD) Log.d(
4834 TAG, "Force removing process " + app + " (" + name
4835 + "/" + uid + ")");
4836
4837 mProcessNames.remove(name, uid);
4838 boolean needRestart = false;
4839 if (app.pid > 0 && app.pid != MY_PID) {
4840 int pid = app.pid;
4841 synchronized (mPidsSelfLocked) {
4842 mPidsSelfLocked.remove(pid);
4843 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4844 }
4845 handleAppDiedLocked(app, true);
4846 mLRUProcesses.remove(app);
4847 Process.killProcess(pid);
4848
4849 if (app.persistent) {
4850 if (!callerWillRestart) {
4851 addAppLocked(app.info);
4852 } else {
4853 needRestart = true;
4854 }
4855 }
4856 } else {
4857 mRemovedProcesses.add(app);
4858 }
4859
4860 return needRestart;
4861 }
4862
4863 private final void processStartTimedOutLocked(ProcessRecord app) {
4864 final int pid = app.pid;
4865 boolean gone = false;
4866 synchronized (mPidsSelfLocked) {
4867 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4868 if (knownApp != null && knownApp.thread == null) {
4869 mPidsSelfLocked.remove(pid);
4870 gone = true;
4871 }
4872 }
4873
4874 if (gone) {
4875 Log.w(TAG, "Process " + app + " failed to attach");
4876 mProcessNames.remove(app.processName, app.info.uid);
4877 Process.killProcess(pid);
4878 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4879 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4880 mPendingBroadcast = null;
4881 scheduleBroadcastsLocked();
4882 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004883 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4884 Log.w(TAG, "Unattached app died before backup, skipping");
4885 try {
4886 IBackupManager bm = IBackupManager.Stub.asInterface(
4887 ServiceManager.getService(Context.BACKUP_SERVICE));
4888 bm.agentDisconnected(app.info.packageName);
4889 } catch (RemoteException e) {
4890 // Can't happen; the backup manager is local
4891 }
4892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004893 } else {
4894 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4895 }
4896 }
4897
4898 private final boolean attachApplicationLocked(IApplicationThread thread,
4899 int pid) {
4900
4901 // Find the application record that is being attached... either via
4902 // the pid if we are running in multiple processes, or just pull the
4903 // next app record if we are emulating process with anonymous threads.
4904 ProcessRecord app;
4905 if (pid != MY_PID && pid >= 0) {
4906 synchronized (mPidsSelfLocked) {
4907 app = mPidsSelfLocked.get(pid);
4908 }
4909 } else if (mStartingProcesses.size() > 0) {
4910 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004911 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004912 } else {
4913 app = null;
4914 }
4915
4916 if (app == null) {
4917 Log.w(TAG, "No pending application record for pid " + pid
4918 + " (IApplicationThread " + thread + "); dropping process");
4919 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4920 if (pid > 0 && pid != MY_PID) {
4921 Process.killProcess(pid);
4922 } else {
4923 try {
4924 thread.scheduleExit();
4925 } catch (Exception e) {
4926 // Ignore exceptions.
4927 }
4928 }
4929 return false;
4930 }
4931
4932 // If this application record is still attached to a previous
4933 // process, clean it up now.
4934 if (app.thread != null) {
4935 handleAppDiedLocked(app, true);
4936 }
4937
4938 // Tell the process all about itself.
4939
4940 if (localLOGV) Log.v(
4941 TAG, "Binding process pid " + pid + " to record " + app);
4942
4943 String processName = app.processName;
4944 try {
4945 thread.asBinder().linkToDeath(new AppDeathRecipient(
4946 app, pid, thread), 0);
4947 } catch (RemoteException e) {
4948 app.resetPackageList();
4949 startProcessLocked(app, "link fail", processName);
4950 return false;
4951 }
4952
4953 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4954
4955 app.thread = thread;
4956 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004957 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004958 app.forcingToForeground = null;
4959 app.foregroundServices = false;
4960 app.debugging = false;
4961
4962 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4963
4964 List providers = generateApplicationProvidersLocked(app);
4965
4966 if (localLOGV) Log.v(
4967 TAG, "New app record " + app
4968 + " thread=" + thread.asBinder() + " pid=" + pid);
4969 try {
4970 int testMode = IApplicationThread.DEBUG_OFF;
4971 if (mDebugApp != null && mDebugApp.equals(processName)) {
4972 testMode = mWaitForDebugger
4973 ? IApplicationThread.DEBUG_WAIT
4974 : IApplicationThread.DEBUG_ON;
4975 app.debugging = true;
4976 if (mDebugTransient) {
4977 mDebugApp = mOrigDebugApp;
4978 mWaitForDebugger = mOrigWaitForDebugger;
4979 }
4980 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004981 // If the app is being launched for restore or full backup, set it up specially
4982 boolean isRestrictedBackupMode = false;
4983 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4984 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4985 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4986 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004987 ensurePackageDexOpt(app.instrumentationInfo != null
4988 ? app.instrumentationInfo.packageName
4989 : app.info.packageName);
4990 if (app.instrumentationClass != null) {
4991 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004992 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004993 thread.bindApplication(processName, app.instrumentationInfo != null
4994 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004995 app.instrumentationClass, app.instrumentationProfileFile,
4996 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004997 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004998 updateLRUListLocked(app, false);
4999 app.lastRequestedGc = SystemClock.uptimeMillis();
5000 } catch (Exception e) {
5001 // todo: Yikes! What should we do? For now we will try to
5002 // start another process, but that could easily get us in
5003 // an infinite loop of restarting processes...
5004 Log.w(TAG, "Exception thrown during bind!", e);
5005
5006 app.resetPackageList();
5007 startProcessLocked(app, "bind fail", processName);
5008 return false;
5009 }
5010
5011 // Remove this record from the list of starting applications.
5012 mPersistentStartingProcesses.remove(app);
5013 mProcessesOnHold.remove(app);
5014
5015 boolean badApp = false;
5016 boolean didSomething = false;
5017
5018 // See if the top visible activity is waiting to run in this process...
5019 HistoryRecord hr = topRunningActivityLocked(null);
5020 if (hr != null) {
5021 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5022 && processName.equals(hr.processName)) {
5023 try {
5024 if (realStartActivityLocked(hr, app, true, true)) {
5025 didSomething = true;
5026 }
5027 } catch (Exception e) {
5028 Log.w(TAG, "Exception in new application when starting activity "
5029 + hr.intent.getComponent().flattenToShortString(), e);
5030 badApp = true;
5031 }
5032 } else {
5033 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5034 }
5035 }
5036
5037 // Find any services that should be running in this process...
5038 if (!badApp && mPendingServices.size() > 0) {
5039 ServiceRecord sr = null;
5040 try {
5041 for (int i=0; i<mPendingServices.size(); i++) {
5042 sr = mPendingServices.get(i);
5043 if (app.info.uid != sr.appInfo.uid
5044 || !processName.equals(sr.processName)) {
5045 continue;
5046 }
5047
5048 mPendingServices.remove(i);
5049 i--;
5050 realStartServiceLocked(sr, app);
5051 didSomething = true;
5052 }
5053 } catch (Exception e) {
5054 Log.w(TAG, "Exception in new application when starting service "
5055 + sr.shortName, e);
5056 badApp = true;
5057 }
5058 }
5059
5060 // Check if the next broadcast receiver is in this process...
5061 BroadcastRecord br = mPendingBroadcast;
5062 if (!badApp && br != null && br.curApp == app) {
5063 try {
5064 mPendingBroadcast = null;
5065 processCurBroadcastLocked(br, app);
5066 didSomething = true;
5067 } catch (Exception e) {
5068 Log.w(TAG, "Exception in new application when starting receiver "
5069 + br.curComponent.flattenToShortString(), e);
5070 badApp = true;
5071 logBroadcastReceiverDiscard(br);
5072 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5073 br.resultExtras, br.resultAbort, true);
5074 scheduleBroadcastsLocked();
5075 }
5076 }
5077
Christopher Tate181fafa2009-05-14 11:12:14 -07005078 // Check whether the next backup agent is in this process...
5079 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5080 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005081 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005082 try {
5083 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5084 } catch (Exception e) {
5085 Log.w(TAG, "Exception scheduling backup agent creation: ");
5086 e.printStackTrace();
5087 }
5088 }
5089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005090 if (badApp) {
5091 // todo: Also need to kill application to deal with all
5092 // kinds of exceptions.
5093 handleAppDiedLocked(app, false);
5094 return false;
5095 }
5096
5097 if (!didSomething) {
5098 updateOomAdjLocked();
5099 }
5100
5101 return true;
5102 }
5103
5104 public final void attachApplication(IApplicationThread thread) {
5105 synchronized (this) {
5106 int callingPid = Binder.getCallingPid();
5107 final long origId = Binder.clearCallingIdentity();
5108 attachApplicationLocked(thread, callingPid);
5109 Binder.restoreCallingIdentity(origId);
5110 }
5111 }
5112
5113 public final void activityIdle(IBinder token) {
5114 final long origId = Binder.clearCallingIdentity();
5115 activityIdleInternal(token, false);
5116 Binder.restoreCallingIdentity(origId);
5117 }
5118
5119 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5120 boolean remove) {
5121 int N = mStoppingActivities.size();
5122 if (N <= 0) return null;
5123
5124 ArrayList<HistoryRecord> stops = null;
5125
5126 final boolean nowVisible = mResumedActivity != null
5127 && mResumedActivity.nowVisible
5128 && !mResumedActivity.waitingVisible;
5129 for (int i=0; i<N; i++) {
5130 HistoryRecord s = mStoppingActivities.get(i);
5131 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5132 + nowVisible + " waitingVisible=" + s.waitingVisible
5133 + " finishing=" + s.finishing);
5134 if (s.waitingVisible && nowVisible) {
5135 mWaitingVisibleActivities.remove(s);
5136 s.waitingVisible = false;
5137 if (s.finishing) {
5138 // If this activity is finishing, it is sitting on top of
5139 // everyone else but we now know it is no longer needed...
5140 // so get rid of it. Otherwise, we need to go through the
5141 // normal flow and hide it once we determine that it is
5142 // hidden by the activities in front of it.
5143 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5144 mWindowManager.setAppVisibility(s, false);
5145 }
5146 }
5147 if (!s.waitingVisible && remove) {
5148 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5149 if (stops == null) {
5150 stops = new ArrayList<HistoryRecord>();
5151 }
5152 stops.add(s);
5153 mStoppingActivities.remove(i);
5154 N--;
5155 i--;
5156 }
5157 }
5158
5159 return stops;
5160 }
5161
5162 void enableScreenAfterBoot() {
5163 mWindowManager.enableScreenAfterBoot();
5164 }
5165
5166 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5167 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5168
5169 ArrayList<HistoryRecord> stops = null;
5170 ArrayList<HistoryRecord> finishes = null;
5171 ArrayList<HistoryRecord> thumbnails = null;
5172 int NS = 0;
5173 int NF = 0;
5174 int NT = 0;
5175 IApplicationThread sendThumbnail = null;
5176 boolean booting = false;
5177 boolean enableScreen = false;
5178
5179 synchronized (this) {
5180 if (token != null) {
5181 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5182 }
5183
5184 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005185 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005186 if (index >= 0) {
5187 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5188
5189 // No longer need to keep the device awake.
5190 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5191 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5192 mLaunchingActivity.release();
5193 }
5194
5195 // We are now idle. If someone is waiting for a thumbnail from
5196 // us, we can now deliver.
5197 r.idle = true;
5198 scheduleAppGcsLocked();
5199 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5200 sendThumbnail = r.app.thread;
5201 r.thumbnailNeeded = false;
5202 }
5203
5204 // If this activity is fullscreen, set up to hide those under it.
5205
5206 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5207 ensureActivitiesVisibleLocked(null, 0);
5208
5209 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5210 if (!mBooted && !fromTimeout) {
5211 mBooted = true;
5212 enableScreen = true;
5213 }
5214 }
5215
5216 // Atomically retrieve all of the other things to do.
5217 stops = processStoppingActivitiesLocked(true);
5218 NS = stops != null ? stops.size() : 0;
5219 if ((NF=mFinishingActivities.size()) > 0) {
5220 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5221 mFinishingActivities.clear();
5222 }
5223 if ((NT=mCancelledThumbnails.size()) > 0) {
5224 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5225 mCancelledThumbnails.clear();
5226 }
5227
5228 booting = mBooting;
5229 mBooting = false;
5230 }
5231
5232 int i;
5233
5234 // Send thumbnail if requested.
5235 if (sendThumbnail != null) {
5236 try {
5237 sendThumbnail.requestThumbnail(token);
5238 } catch (Exception e) {
5239 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5240 sendPendingThumbnail(null, token, null, null, true);
5241 }
5242 }
5243
5244 // Stop any activities that are scheduled to do so but have been
5245 // waiting for the next one to start.
5246 for (i=0; i<NS; i++) {
5247 HistoryRecord r = (HistoryRecord)stops.get(i);
5248 synchronized (this) {
5249 if (r.finishing) {
5250 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5251 } else {
5252 stopActivityLocked(r);
5253 }
5254 }
5255 }
5256
5257 // Finish any activities that are scheduled to do so but have been
5258 // waiting for the next one to start.
5259 for (i=0; i<NF; i++) {
5260 HistoryRecord r = (HistoryRecord)finishes.get(i);
5261 synchronized (this) {
5262 destroyActivityLocked(r, true);
5263 }
5264 }
5265
5266 // Report back to any thumbnail receivers.
5267 for (i=0; i<NT; i++) {
5268 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5269 sendPendingThumbnail(r, null, null, null, true);
5270 }
5271
5272 if (booting) {
5273 // Ensure that any processes we had put on hold are now started
5274 // up.
5275 final int NP = mProcessesOnHold.size();
5276 if (NP > 0) {
5277 ArrayList<ProcessRecord> procs =
5278 new ArrayList<ProcessRecord>(mProcessesOnHold);
5279 for (int ip=0; ip<NP; ip++) {
5280 this.startProcessLocked(procs.get(ip), "on-hold", null);
5281 }
5282 }
5283 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5284 // Tell anyone interested that we are done booting!
5285 synchronized (this) {
5286 broadcastIntentLocked(null, null,
5287 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5288 null, null, 0, null, null,
5289 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5290 false, false, MY_PID, Process.SYSTEM_UID);
5291 }
5292 }
5293 }
5294
5295 trimApplications();
5296 //dump();
5297 //mWindowManager.dump();
5298
5299 if (enableScreen) {
5300 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5301 SystemClock.uptimeMillis());
5302 enableScreenAfterBoot();
5303 }
5304 }
5305
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005306 final void ensureScreenEnabled() {
5307 boolean enableScreen;
5308 synchronized (this) {
5309 enableScreen = !mBooted;
5310 mBooted = true;
5311 }
5312
5313 if (enableScreen) {
5314 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5315 SystemClock.uptimeMillis());
5316 enableScreenAfterBoot();
5317 }
5318 }
5319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005320 public final void activityPaused(IBinder token, Bundle icicle) {
5321 // Refuse possible leaked file descriptors
5322 if (icicle != null && icicle.hasFileDescriptors()) {
5323 throw new IllegalArgumentException("File descriptors passed in Bundle");
5324 }
5325
5326 final long origId = Binder.clearCallingIdentity();
5327 activityPaused(token, icicle, false);
5328 Binder.restoreCallingIdentity(origId);
5329 }
5330
5331 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5332 if (DEBUG_PAUSE) Log.v(
5333 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5334 + ", timeout=" + timeout);
5335
5336 HistoryRecord r = null;
5337
5338 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005339 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005340 if (index >= 0) {
5341 r = (HistoryRecord)mHistory.get(index);
5342 if (!timeout) {
5343 r.icicle = icicle;
5344 r.haveState = true;
5345 }
5346 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5347 if (mPausingActivity == r) {
5348 r.state = ActivityState.PAUSED;
5349 completePauseLocked();
5350 } else {
5351 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5352 System.identityHashCode(r), r.shortComponentName,
5353 mPausingActivity != null
5354 ? mPausingActivity.shortComponentName : "(none)");
5355 }
5356 }
5357 }
5358 }
5359
5360 public final void activityStopped(IBinder token, Bitmap thumbnail,
5361 CharSequence description) {
5362 if (localLOGV) Log.v(
5363 TAG, "Activity stopped: token=" + token);
5364
5365 HistoryRecord r = null;
5366
5367 final long origId = Binder.clearCallingIdentity();
5368
5369 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005370 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005371 if (index >= 0) {
5372 r = (HistoryRecord)mHistory.get(index);
5373 r.thumbnail = thumbnail;
5374 r.description = description;
5375 r.stopped = true;
5376 r.state = ActivityState.STOPPED;
5377 if (!r.finishing) {
5378 if (r.configDestroy) {
5379 destroyActivityLocked(r, true);
5380 resumeTopActivityLocked(null);
5381 }
5382 }
5383 }
5384 }
5385
5386 if (r != null) {
5387 sendPendingThumbnail(r, null, null, null, false);
5388 }
5389
5390 trimApplications();
5391
5392 Binder.restoreCallingIdentity(origId);
5393 }
5394
5395 public final void activityDestroyed(IBinder token) {
5396 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5397 synchronized (this) {
5398 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5399
Dianne Hackborn75b03852009-06-12 15:43:26 -07005400 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 if (index >= 0) {
5402 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5403 if (r.state == ActivityState.DESTROYING) {
5404 final long origId = Binder.clearCallingIdentity();
5405 removeActivityFromHistoryLocked(r);
5406 Binder.restoreCallingIdentity(origId);
5407 }
5408 }
5409 }
5410 }
5411
5412 public String getCallingPackage(IBinder token) {
5413 synchronized (this) {
5414 HistoryRecord r = getCallingRecordLocked(token);
5415 return r != null && r.app != null ? r.app.processName : null;
5416 }
5417 }
5418
5419 public ComponentName getCallingActivity(IBinder token) {
5420 synchronized (this) {
5421 HistoryRecord r = getCallingRecordLocked(token);
5422 return r != null ? r.intent.getComponent() : null;
5423 }
5424 }
5425
5426 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005427 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005428 if (index >= 0) {
5429 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5430 if (r != null) {
5431 return r.resultTo;
5432 }
5433 }
5434 return null;
5435 }
5436
5437 public ComponentName getActivityClassForToken(IBinder token) {
5438 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005439 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005440 if (index >= 0) {
5441 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5442 return r.intent.getComponent();
5443 }
5444 return null;
5445 }
5446 }
5447
5448 public String getPackageForToken(IBinder token) {
5449 synchronized(this) {
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 return r.packageName;
5454 }
5455 return null;
5456 }
5457 }
5458
5459 public IIntentSender getIntentSender(int type,
5460 String packageName, IBinder token, String resultWho,
5461 int requestCode, Intent intent, String resolvedType, int flags) {
5462 // Refuse possible leaked file descriptors
5463 if (intent != null && intent.hasFileDescriptors() == true) {
5464 throw new IllegalArgumentException("File descriptors passed in Intent");
5465 }
5466
5467 synchronized(this) {
5468 int callingUid = Binder.getCallingUid();
5469 try {
5470 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5471 Process.supportsProcesses()) {
5472 int uid = ActivityThread.getPackageManager()
5473 .getPackageUid(packageName);
5474 if (uid != Binder.getCallingUid()) {
5475 String msg = "Permission Denial: getIntentSender() from pid="
5476 + Binder.getCallingPid()
5477 + ", uid=" + Binder.getCallingUid()
5478 + ", (need uid=" + uid + ")"
5479 + " is not allowed to send as package " + packageName;
5480 Log.w(TAG, msg);
5481 throw new SecurityException(msg);
5482 }
5483 }
5484 } catch (RemoteException e) {
5485 throw new SecurityException(e);
5486 }
5487 HistoryRecord activity = null;
5488 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005489 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005490 if (index < 0) {
5491 return null;
5492 }
5493 activity = (HistoryRecord)mHistory.get(index);
5494 if (activity.finishing) {
5495 return null;
5496 }
5497 }
5498
5499 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5500 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5501 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5502 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5503 |PendingIntent.FLAG_UPDATE_CURRENT);
5504
5505 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5506 type, packageName, activity, resultWho,
5507 requestCode, intent, resolvedType, flags);
5508 WeakReference<PendingIntentRecord> ref;
5509 ref = mIntentSenderRecords.get(key);
5510 PendingIntentRecord rec = ref != null ? ref.get() : null;
5511 if (rec != null) {
5512 if (!cancelCurrent) {
5513 if (updateCurrent) {
5514 rec.key.requestIntent.replaceExtras(intent);
5515 }
5516 return rec;
5517 }
5518 rec.canceled = true;
5519 mIntentSenderRecords.remove(key);
5520 }
5521 if (noCreate) {
5522 return rec;
5523 }
5524 rec = new PendingIntentRecord(this, key, callingUid);
5525 mIntentSenderRecords.put(key, rec.ref);
5526 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5527 if (activity.pendingResults == null) {
5528 activity.pendingResults
5529 = new HashSet<WeakReference<PendingIntentRecord>>();
5530 }
5531 activity.pendingResults.add(rec.ref);
5532 }
5533 return rec;
5534 }
5535 }
5536
5537 public void cancelIntentSender(IIntentSender sender) {
5538 if (!(sender instanceof PendingIntentRecord)) {
5539 return;
5540 }
5541 synchronized(this) {
5542 PendingIntentRecord rec = (PendingIntentRecord)sender;
5543 try {
5544 int uid = ActivityThread.getPackageManager()
5545 .getPackageUid(rec.key.packageName);
5546 if (uid != Binder.getCallingUid()) {
5547 String msg = "Permission Denial: cancelIntentSender() from pid="
5548 + Binder.getCallingPid()
5549 + ", uid=" + Binder.getCallingUid()
5550 + " is not allowed to cancel packges "
5551 + rec.key.packageName;
5552 Log.w(TAG, msg);
5553 throw new SecurityException(msg);
5554 }
5555 } catch (RemoteException e) {
5556 throw new SecurityException(e);
5557 }
5558 cancelIntentSenderLocked(rec, true);
5559 }
5560 }
5561
5562 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5563 rec.canceled = true;
5564 mIntentSenderRecords.remove(rec.key);
5565 if (cleanActivity && rec.key.activity != null) {
5566 rec.key.activity.pendingResults.remove(rec.ref);
5567 }
5568 }
5569
5570 public String getPackageForIntentSender(IIntentSender pendingResult) {
5571 if (!(pendingResult instanceof PendingIntentRecord)) {
5572 return null;
5573 }
5574 synchronized(this) {
5575 try {
5576 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5577 return res.key.packageName;
5578 } catch (ClassCastException e) {
5579 }
5580 }
5581 return null;
5582 }
5583
5584 public void setProcessLimit(int max) {
5585 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5586 "setProcessLimit()");
5587 mProcessLimit = max;
5588 }
5589
5590 public int getProcessLimit() {
5591 return mProcessLimit;
5592 }
5593
5594 void foregroundTokenDied(ForegroundToken token) {
5595 synchronized (ActivityManagerService.this) {
5596 synchronized (mPidsSelfLocked) {
5597 ForegroundToken cur
5598 = mForegroundProcesses.get(token.pid);
5599 if (cur != token) {
5600 return;
5601 }
5602 mForegroundProcesses.remove(token.pid);
5603 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5604 if (pr == null) {
5605 return;
5606 }
5607 pr.forcingToForeground = null;
5608 pr.foregroundServices = false;
5609 }
5610 updateOomAdjLocked();
5611 }
5612 }
5613
5614 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5615 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5616 "setProcessForeground()");
5617 synchronized(this) {
5618 boolean changed = false;
5619
5620 synchronized (mPidsSelfLocked) {
5621 ProcessRecord pr = mPidsSelfLocked.get(pid);
5622 if (pr == null) {
5623 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5624 return;
5625 }
5626 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5627 if (oldToken != null) {
5628 oldToken.token.unlinkToDeath(oldToken, 0);
5629 mForegroundProcesses.remove(pid);
5630 pr.forcingToForeground = null;
5631 changed = true;
5632 }
5633 if (isForeground && token != null) {
5634 ForegroundToken newToken = new ForegroundToken() {
5635 public void binderDied() {
5636 foregroundTokenDied(this);
5637 }
5638 };
5639 newToken.pid = pid;
5640 newToken.token = token;
5641 try {
5642 token.linkToDeath(newToken, 0);
5643 mForegroundProcesses.put(pid, newToken);
5644 pr.forcingToForeground = token;
5645 changed = true;
5646 } catch (RemoteException e) {
5647 // If the process died while doing this, we will later
5648 // do the cleanup with the process death link.
5649 }
5650 }
5651 }
5652
5653 if (changed) {
5654 updateOomAdjLocked();
5655 }
5656 }
5657 }
5658
5659 // =========================================================
5660 // PERMISSIONS
5661 // =========================================================
5662
5663 static class PermissionController extends IPermissionController.Stub {
5664 ActivityManagerService mActivityManagerService;
5665 PermissionController(ActivityManagerService activityManagerService) {
5666 mActivityManagerService = activityManagerService;
5667 }
5668
5669 public boolean checkPermission(String permission, int pid, int uid) {
5670 return mActivityManagerService.checkPermission(permission, pid,
5671 uid) == PackageManager.PERMISSION_GRANTED;
5672 }
5673 }
5674
5675 /**
5676 * This can be called with or without the global lock held.
5677 */
5678 int checkComponentPermission(String permission, int pid, int uid,
5679 int reqUid) {
5680 // We might be performing an operation on behalf of an indirect binder
5681 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5682 // client identity accordingly before proceeding.
5683 Identity tlsIdentity = sCallerIdentity.get();
5684 if (tlsIdentity != null) {
5685 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5686 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5687 uid = tlsIdentity.uid;
5688 pid = tlsIdentity.pid;
5689 }
5690
5691 // Root, system server and our own process get to do everything.
5692 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5693 !Process.supportsProcesses()) {
5694 return PackageManager.PERMISSION_GRANTED;
5695 }
5696 // If the target requires a specific UID, always fail for others.
5697 if (reqUid >= 0 && uid != reqUid) {
5698 return PackageManager.PERMISSION_DENIED;
5699 }
5700 if (permission == null) {
5701 return PackageManager.PERMISSION_GRANTED;
5702 }
5703 try {
5704 return ActivityThread.getPackageManager()
5705 .checkUidPermission(permission, uid);
5706 } catch (RemoteException e) {
5707 // Should never happen, but if it does... deny!
5708 Log.e(TAG, "PackageManager is dead?!?", e);
5709 }
5710 return PackageManager.PERMISSION_DENIED;
5711 }
5712
5713 /**
5714 * As the only public entry point for permissions checking, this method
5715 * can enforce the semantic that requesting a check on a null global
5716 * permission is automatically denied. (Internally a null permission
5717 * string is used when calling {@link #checkComponentPermission} in cases
5718 * when only uid-based security is needed.)
5719 *
5720 * This can be called with or without the global lock held.
5721 */
5722 public int checkPermission(String permission, int pid, int uid) {
5723 if (permission == null) {
5724 return PackageManager.PERMISSION_DENIED;
5725 }
5726 return checkComponentPermission(permission, pid, uid, -1);
5727 }
5728
5729 /**
5730 * Binder IPC calls go through the public entry point.
5731 * This can be called with or without the global lock held.
5732 */
5733 int checkCallingPermission(String permission) {
5734 return checkPermission(permission,
5735 Binder.getCallingPid(),
5736 Binder.getCallingUid());
5737 }
5738
5739 /**
5740 * This can be called with or without the global lock held.
5741 */
5742 void enforceCallingPermission(String permission, String func) {
5743 if (checkCallingPermission(permission)
5744 == PackageManager.PERMISSION_GRANTED) {
5745 return;
5746 }
5747
5748 String msg = "Permission Denial: " + func + " from pid="
5749 + Binder.getCallingPid()
5750 + ", uid=" + Binder.getCallingUid()
5751 + " requires " + permission;
5752 Log.w(TAG, msg);
5753 throw new SecurityException(msg);
5754 }
5755
5756 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5757 ProviderInfo pi, int uid, int modeFlags) {
5758 try {
5759 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5760 if ((pi.readPermission != null) &&
5761 (pm.checkUidPermission(pi.readPermission, uid)
5762 != PackageManager.PERMISSION_GRANTED)) {
5763 return false;
5764 }
5765 }
5766 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5767 if ((pi.writePermission != null) &&
5768 (pm.checkUidPermission(pi.writePermission, uid)
5769 != PackageManager.PERMISSION_GRANTED)) {
5770 return false;
5771 }
5772 }
5773 return true;
5774 } catch (RemoteException e) {
5775 return false;
5776 }
5777 }
5778
5779 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5780 int modeFlags) {
5781 // Root gets to do everything.
5782 if (uid == 0 || !Process.supportsProcesses()) {
5783 return true;
5784 }
5785 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5786 if (perms == null) return false;
5787 UriPermission perm = perms.get(uri);
5788 if (perm == null) return false;
5789 return (modeFlags&perm.modeFlags) == modeFlags;
5790 }
5791
5792 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5793 // Another redirected-binder-call permissions check as in
5794 // {@link checkComponentPermission}.
5795 Identity tlsIdentity = sCallerIdentity.get();
5796 if (tlsIdentity != null) {
5797 uid = tlsIdentity.uid;
5798 pid = tlsIdentity.pid;
5799 }
5800
5801 // Our own process gets to do everything.
5802 if (pid == MY_PID) {
5803 return PackageManager.PERMISSION_GRANTED;
5804 }
5805 synchronized(this) {
5806 return checkUriPermissionLocked(uri, uid, modeFlags)
5807 ? PackageManager.PERMISSION_GRANTED
5808 : PackageManager.PERMISSION_DENIED;
5809 }
5810 }
5811
5812 private void grantUriPermissionLocked(int callingUid,
5813 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5814 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5815 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5816 if (modeFlags == 0) {
5817 return;
5818 }
5819
5820 final IPackageManager pm = ActivityThread.getPackageManager();
5821
5822 // If this is not a content: uri, we can't do anything with it.
5823 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5824 return;
5825 }
5826
5827 String name = uri.getAuthority();
5828 ProviderInfo pi = null;
5829 ContentProviderRecord cpr
5830 = (ContentProviderRecord)mProvidersByName.get(name);
5831 if (cpr != null) {
5832 pi = cpr.info;
5833 } else {
5834 try {
5835 pi = pm.resolveContentProvider(name,
5836 PackageManager.GET_URI_PERMISSION_PATTERNS);
5837 } catch (RemoteException ex) {
5838 }
5839 }
5840 if (pi == null) {
5841 Log.w(TAG, "No content provider found for: " + name);
5842 return;
5843 }
5844
5845 int targetUid;
5846 try {
5847 targetUid = pm.getPackageUid(targetPkg);
5848 if (targetUid < 0) {
5849 return;
5850 }
5851 } catch (RemoteException ex) {
5852 return;
5853 }
5854
5855 // First... does the target actually need this permission?
5856 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5857 // No need to grant the target this permission.
5858 return;
5859 }
5860
5861 // Second... maybe someone else has already granted the
5862 // permission?
5863 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5864 // No need to grant the target this permission.
5865 return;
5866 }
5867
5868 // Third... is the provider allowing granting of URI permissions?
5869 if (!pi.grantUriPermissions) {
5870 throw new SecurityException("Provider " + pi.packageName
5871 + "/" + pi.name
5872 + " does not allow granting of Uri permissions (uri "
5873 + uri + ")");
5874 }
5875 if (pi.uriPermissionPatterns != null) {
5876 final int N = pi.uriPermissionPatterns.length;
5877 boolean allowed = false;
5878 for (int i=0; i<N; i++) {
5879 if (pi.uriPermissionPatterns[i] != null
5880 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5881 allowed = true;
5882 break;
5883 }
5884 }
5885 if (!allowed) {
5886 throw new SecurityException("Provider " + pi.packageName
5887 + "/" + pi.name
5888 + " does not allow granting of permission to path of Uri "
5889 + uri);
5890 }
5891 }
5892
5893 // Fourth... does the caller itself have permission to access
5894 // this uri?
5895 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5896 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5897 throw new SecurityException("Uid " + callingUid
5898 + " does not have permission to uri " + uri);
5899 }
5900 }
5901
5902 // Okay! So here we are: the caller has the assumed permission
5903 // to the uri, and the target doesn't. Let's now give this to
5904 // the target.
5905
5906 HashMap<Uri, UriPermission> targetUris
5907 = mGrantedUriPermissions.get(targetUid);
5908 if (targetUris == null) {
5909 targetUris = new HashMap<Uri, UriPermission>();
5910 mGrantedUriPermissions.put(targetUid, targetUris);
5911 }
5912
5913 UriPermission perm = targetUris.get(uri);
5914 if (perm == null) {
5915 perm = new UriPermission(targetUid, uri);
5916 targetUris.put(uri, perm);
5917
5918 }
5919 perm.modeFlags |= modeFlags;
5920 if (activity == null) {
5921 perm.globalModeFlags |= modeFlags;
5922 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5923 perm.readActivities.add(activity);
5924 if (activity.readUriPermissions == null) {
5925 activity.readUriPermissions = new HashSet<UriPermission>();
5926 }
5927 activity.readUriPermissions.add(perm);
5928 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5929 perm.writeActivities.add(activity);
5930 if (activity.writeUriPermissions == null) {
5931 activity.writeUriPermissions = new HashSet<UriPermission>();
5932 }
5933 activity.writeUriPermissions.add(perm);
5934 }
5935 }
5936
5937 private void grantUriPermissionFromIntentLocked(int callingUid,
5938 String targetPkg, Intent intent, HistoryRecord activity) {
5939 if (intent == null) {
5940 return;
5941 }
5942 Uri data = intent.getData();
5943 if (data == null) {
5944 return;
5945 }
5946 grantUriPermissionLocked(callingUid, targetPkg, data,
5947 intent.getFlags(), activity);
5948 }
5949
5950 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5951 Uri uri, int modeFlags) {
5952 synchronized(this) {
5953 final ProcessRecord r = getRecordForAppLocked(caller);
5954 if (r == null) {
5955 throw new SecurityException("Unable to find app for caller "
5956 + caller
5957 + " when granting permission to uri " + uri);
5958 }
5959 if (targetPkg == null) {
5960 Log.w(TAG, "grantUriPermission: null target");
5961 return;
5962 }
5963 if (uri == null) {
5964 Log.w(TAG, "grantUriPermission: null uri");
5965 return;
5966 }
5967
5968 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5969 null);
5970 }
5971 }
5972
5973 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5974 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5975 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5976 HashMap<Uri, UriPermission> perms
5977 = mGrantedUriPermissions.get(perm.uid);
5978 if (perms != null) {
5979 perms.remove(perm.uri);
5980 if (perms.size() == 0) {
5981 mGrantedUriPermissions.remove(perm.uid);
5982 }
5983 }
5984 }
5985 }
5986
5987 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5988 if (activity.readUriPermissions != null) {
5989 for (UriPermission perm : activity.readUriPermissions) {
5990 perm.readActivities.remove(activity);
5991 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5992 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5993 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5994 removeUriPermissionIfNeededLocked(perm);
5995 }
5996 }
5997 }
5998 if (activity.writeUriPermissions != null) {
5999 for (UriPermission perm : activity.writeUriPermissions) {
6000 perm.writeActivities.remove(activity);
6001 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6002 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6003 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6004 removeUriPermissionIfNeededLocked(perm);
6005 }
6006 }
6007 }
6008 }
6009
6010 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6011 int modeFlags) {
6012 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6013 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6014 if (modeFlags == 0) {
6015 return;
6016 }
6017
6018 final IPackageManager pm = ActivityThread.getPackageManager();
6019
6020 final String authority = uri.getAuthority();
6021 ProviderInfo pi = null;
6022 ContentProviderRecord cpr
6023 = (ContentProviderRecord)mProvidersByName.get(authority);
6024 if (cpr != null) {
6025 pi = cpr.info;
6026 } else {
6027 try {
6028 pi = pm.resolveContentProvider(authority,
6029 PackageManager.GET_URI_PERMISSION_PATTERNS);
6030 } catch (RemoteException ex) {
6031 }
6032 }
6033 if (pi == null) {
6034 Log.w(TAG, "No content provider found for: " + authority);
6035 return;
6036 }
6037
6038 // Does the caller have this permission on the URI?
6039 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6040 // Right now, if you are not the original owner of the permission,
6041 // you are not allowed to revoke it.
6042 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6043 throw new SecurityException("Uid " + callingUid
6044 + " does not have permission to uri " + uri);
6045 //}
6046 }
6047
6048 // Go through all of the permissions and remove any that match.
6049 final List<String> SEGMENTS = uri.getPathSegments();
6050 if (SEGMENTS != null) {
6051 final int NS = SEGMENTS.size();
6052 int N = mGrantedUriPermissions.size();
6053 for (int i=0; i<N; i++) {
6054 HashMap<Uri, UriPermission> perms
6055 = mGrantedUriPermissions.valueAt(i);
6056 Iterator<UriPermission> it = perms.values().iterator();
6057 toploop:
6058 while (it.hasNext()) {
6059 UriPermission perm = it.next();
6060 Uri targetUri = perm.uri;
6061 if (!authority.equals(targetUri.getAuthority())) {
6062 continue;
6063 }
6064 List<String> targetSegments = targetUri.getPathSegments();
6065 if (targetSegments == null) {
6066 continue;
6067 }
6068 if (targetSegments.size() < NS) {
6069 continue;
6070 }
6071 for (int j=0; j<NS; j++) {
6072 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6073 continue toploop;
6074 }
6075 }
6076 perm.clearModes(modeFlags);
6077 if (perm.modeFlags == 0) {
6078 it.remove();
6079 }
6080 }
6081 if (perms.size() == 0) {
6082 mGrantedUriPermissions.remove(
6083 mGrantedUriPermissions.keyAt(i));
6084 N--;
6085 i--;
6086 }
6087 }
6088 }
6089 }
6090
6091 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6092 int modeFlags) {
6093 synchronized(this) {
6094 final ProcessRecord r = getRecordForAppLocked(caller);
6095 if (r == null) {
6096 throw new SecurityException("Unable to find app for caller "
6097 + caller
6098 + " when revoking permission to uri " + uri);
6099 }
6100 if (uri == null) {
6101 Log.w(TAG, "revokeUriPermission: null uri");
6102 return;
6103 }
6104
6105 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6106 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6107 if (modeFlags == 0) {
6108 return;
6109 }
6110
6111 final IPackageManager pm = ActivityThread.getPackageManager();
6112
6113 final String authority = uri.getAuthority();
6114 ProviderInfo pi = null;
6115 ContentProviderRecord cpr
6116 = (ContentProviderRecord)mProvidersByName.get(authority);
6117 if (cpr != null) {
6118 pi = cpr.info;
6119 } else {
6120 try {
6121 pi = pm.resolveContentProvider(authority,
6122 PackageManager.GET_URI_PERMISSION_PATTERNS);
6123 } catch (RemoteException ex) {
6124 }
6125 }
6126 if (pi == null) {
6127 Log.w(TAG, "No content provider found for: " + authority);
6128 return;
6129 }
6130
6131 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6132 }
6133 }
6134
6135 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6136 synchronized (this) {
6137 ProcessRecord app =
6138 who != null ? getRecordForAppLocked(who) : null;
6139 if (app == null) return;
6140
6141 Message msg = Message.obtain();
6142 msg.what = WAIT_FOR_DEBUGGER_MSG;
6143 msg.obj = app;
6144 msg.arg1 = waiting ? 1 : 0;
6145 mHandler.sendMessage(msg);
6146 }
6147 }
6148
6149 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6150 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006151 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006152 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006153 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006154 }
6155
6156 // =========================================================
6157 // TASK MANAGEMENT
6158 // =========================================================
6159
6160 public List getTasks(int maxNum, int flags,
6161 IThumbnailReceiver receiver) {
6162 ArrayList list = new ArrayList();
6163
6164 PendingThumbnailsRecord pending = null;
6165 IApplicationThread topThumbnail = null;
6166 HistoryRecord topRecord = null;
6167
6168 synchronized(this) {
6169 if (localLOGV) Log.v(
6170 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6171 + ", receiver=" + receiver);
6172
6173 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6174 != PackageManager.PERMISSION_GRANTED) {
6175 if (receiver != null) {
6176 // If the caller wants to wait for pending thumbnails,
6177 // it ain't gonna get them.
6178 try {
6179 receiver.finished();
6180 } catch (RemoteException ex) {
6181 }
6182 }
6183 String msg = "Permission Denial: getTasks() from pid="
6184 + Binder.getCallingPid()
6185 + ", uid=" + Binder.getCallingUid()
6186 + " requires " + android.Manifest.permission.GET_TASKS;
6187 Log.w(TAG, msg);
6188 throw new SecurityException(msg);
6189 }
6190
6191 int pos = mHistory.size()-1;
6192 HistoryRecord next =
6193 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6194 HistoryRecord top = null;
6195 CharSequence topDescription = null;
6196 TaskRecord curTask = null;
6197 int numActivities = 0;
6198 int numRunning = 0;
6199 while (pos >= 0 && maxNum > 0) {
6200 final HistoryRecord r = next;
6201 pos--;
6202 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6203
6204 // Initialize state for next task if needed.
6205 if (top == null ||
6206 (top.state == ActivityState.INITIALIZING
6207 && top.task == r.task)) {
6208 top = r;
6209 topDescription = r.description;
6210 curTask = r.task;
6211 numActivities = numRunning = 0;
6212 }
6213
6214 // Add 'r' into the current task.
6215 numActivities++;
6216 if (r.app != null && r.app.thread != null) {
6217 numRunning++;
6218 }
6219 if (topDescription == null) {
6220 topDescription = r.description;
6221 }
6222
6223 if (localLOGV) Log.v(
6224 TAG, r.intent.getComponent().flattenToShortString()
6225 + ": task=" + r.task);
6226
6227 // If the next one is a different task, generate a new
6228 // TaskInfo entry for what we have.
6229 if (next == null || next.task != curTask) {
6230 ActivityManager.RunningTaskInfo ci
6231 = new ActivityManager.RunningTaskInfo();
6232 ci.id = curTask.taskId;
6233 ci.baseActivity = r.intent.getComponent();
6234 ci.topActivity = top.intent.getComponent();
6235 ci.thumbnail = top.thumbnail;
6236 ci.description = topDescription;
6237 ci.numActivities = numActivities;
6238 ci.numRunning = numRunning;
6239 //System.out.println(
6240 // "#" + maxNum + ": " + " descr=" + ci.description);
6241 if (ci.thumbnail == null && receiver != null) {
6242 if (localLOGV) Log.v(
6243 TAG, "State=" + top.state + "Idle=" + top.idle
6244 + " app=" + top.app
6245 + " thr=" + (top.app != null ? top.app.thread : null));
6246 if (top.state == ActivityState.RESUMED
6247 || top.state == ActivityState.PAUSING) {
6248 if (top.idle && top.app != null
6249 && top.app.thread != null) {
6250 topRecord = top;
6251 topThumbnail = top.app.thread;
6252 } else {
6253 top.thumbnailNeeded = true;
6254 }
6255 }
6256 if (pending == null) {
6257 pending = new PendingThumbnailsRecord(receiver);
6258 }
6259 pending.pendingRecords.add(top);
6260 }
6261 list.add(ci);
6262 maxNum--;
6263 top = null;
6264 }
6265 }
6266
6267 if (pending != null) {
6268 mPendingThumbnails.add(pending);
6269 }
6270 }
6271
6272 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6273
6274 if (topThumbnail != null) {
6275 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6276 try {
6277 topThumbnail.requestThumbnail(topRecord);
6278 } catch (Exception e) {
6279 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6280 sendPendingThumbnail(null, topRecord, null, null, true);
6281 }
6282 }
6283
6284 if (pending == null && receiver != null) {
6285 // In this case all thumbnails were available and the client
6286 // is being asked to be told when the remaining ones come in...
6287 // which is unusually, since the top-most currently running
6288 // activity should never have a canned thumbnail! Oh well.
6289 try {
6290 receiver.finished();
6291 } catch (RemoteException ex) {
6292 }
6293 }
6294
6295 return list;
6296 }
6297
6298 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6299 int flags) {
6300 synchronized (this) {
6301 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6302 "getRecentTasks()");
6303
6304 final int N = mRecentTasks.size();
6305 ArrayList<ActivityManager.RecentTaskInfo> res
6306 = new ArrayList<ActivityManager.RecentTaskInfo>(
6307 maxNum < N ? maxNum : N);
6308 for (int i=0; i<N && maxNum > 0; i++) {
6309 TaskRecord tr = mRecentTasks.get(i);
6310 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6311 || (tr.intent == null)
6312 || ((tr.intent.getFlags()
6313 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6314 ActivityManager.RecentTaskInfo rti
6315 = new ActivityManager.RecentTaskInfo();
6316 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6317 rti.baseIntent = new Intent(
6318 tr.intent != null ? tr.intent : tr.affinityIntent);
6319 rti.origActivity = tr.origActivity;
6320 res.add(rti);
6321 maxNum--;
6322 }
6323 }
6324 return res;
6325 }
6326 }
6327
6328 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6329 int j;
6330 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6331 TaskRecord jt = startTask;
6332
6333 // First look backwards
6334 for (j=startIndex-1; j>=0; j--) {
6335 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6336 if (r.task != jt) {
6337 jt = r.task;
6338 if (affinity.equals(jt.affinity)) {
6339 return j;
6340 }
6341 }
6342 }
6343
6344 // Now look forwards
6345 final int N = mHistory.size();
6346 jt = startTask;
6347 for (j=startIndex+1; j<N; j++) {
6348 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6349 if (r.task != jt) {
6350 if (affinity.equals(jt.affinity)) {
6351 return j;
6352 }
6353 jt = r.task;
6354 }
6355 }
6356
6357 // Might it be at the top?
6358 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6359 return N-1;
6360 }
6361
6362 return -1;
6363 }
6364
6365 /**
6366 * Perform a reset of the given task, if needed as part of launching it.
6367 * Returns the new HistoryRecord at the top of the task.
6368 */
6369 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6370 HistoryRecord newActivity) {
6371 boolean forceReset = (newActivity.info.flags
6372 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6373 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6374 if ((newActivity.info.flags
6375 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6376 forceReset = true;
6377 }
6378 }
6379
6380 final TaskRecord task = taskTop.task;
6381
6382 // We are going to move through the history list so that we can look
6383 // at each activity 'target' with 'below' either the interesting
6384 // activity immediately below it in the stack or null.
6385 HistoryRecord target = null;
6386 int targetI = 0;
6387 int taskTopI = -1;
6388 int replyChainEnd = -1;
6389 int lastReparentPos = -1;
6390 for (int i=mHistory.size()-1; i>=-1; i--) {
6391 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6392
6393 if (below != null && below.finishing) {
6394 continue;
6395 }
6396 if (target == null) {
6397 target = below;
6398 targetI = i;
6399 // If we were in the middle of a reply chain before this
6400 // task, it doesn't appear like the root of the chain wants
6401 // anything interesting, so drop it.
6402 replyChainEnd = -1;
6403 continue;
6404 }
6405
6406 final int flags = target.info.flags;
6407
6408 final boolean finishOnTaskLaunch =
6409 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6410 final boolean allowTaskReparenting =
6411 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6412
6413 if (target.task == task) {
6414 // We are inside of the task being reset... we'll either
6415 // finish this activity, push it out for another task,
6416 // or leave it as-is. We only do this
6417 // for activities that are not the root of the task (since
6418 // if we finish the root, we may no longer have the task!).
6419 if (taskTopI < 0) {
6420 taskTopI = targetI;
6421 }
6422 if (below != null && below.task == task) {
6423 final boolean clearWhenTaskReset =
6424 (target.intent.getFlags()
6425 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006426 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006427 // If this activity is sending a reply to a previous
6428 // activity, we can't do anything with it now until
6429 // we reach the start of the reply chain.
6430 // XXX note that we are assuming the result is always
6431 // to the previous activity, which is almost always
6432 // the case but we really shouldn't count on.
6433 if (replyChainEnd < 0) {
6434 replyChainEnd = targetI;
6435 }
Ed Heyl73798232009-03-24 21:32:21 -07006436 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006437 && target.taskAffinity != null
6438 && !target.taskAffinity.equals(task.affinity)) {
6439 // If this activity has an affinity for another
6440 // task, then we need to move it out of here. We will
6441 // move it as far out of the way as possible, to the
6442 // bottom of the activity stack. This also keeps it
6443 // correctly ordered with any activities we previously
6444 // moved.
6445 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6446 if (target.taskAffinity != null
6447 && target.taskAffinity.equals(p.task.affinity)) {
6448 // If the activity currently at the bottom has the
6449 // same task affinity as the one we are moving,
6450 // then merge it into the same task.
6451 target.task = p.task;
6452 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6453 + " out to bottom task " + p.task);
6454 } else {
6455 mCurTask++;
6456 if (mCurTask <= 0) {
6457 mCurTask = 1;
6458 }
6459 target.task = new TaskRecord(mCurTask, target.info, null,
6460 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6461 target.task.affinityIntent = target.intent;
6462 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6463 + " out to new task " + target.task);
6464 }
6465 mWindowManager.setAppGroupId(target, task.taskId);
6466 if (replyChainEnd < 0) {
6467 replyChainEnd = targetI;
6468 }
6469 int dstPos = 0;
6470 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6471 p = (HistoryRecord)mHistory.get(srcPos);
6472 if (p.finishing) {
6473 continue;
6474 }
6475 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6476 + " out to target's task " + target.task);
6477 task.numActivities--;
6478 p.task = target.task;
6479 target.task.numActivities++;
6480 mHistory.remove(srcPos);
6481 mHistory.add(dstPos, p);
6482 mWindowManager.moveAppToken(dstPos, p);
6483 mWindowManager.setAppGroupId(p, p.task.taskId);
6484 dstPos++;
6485 if (VALIDATE_TOKENS) {
6486 mWindowManager.validateAppTokens(mHistory);
6487 }
6488 i++;
6489 }
6490 if (taskTop == p) {
6491 taskTop = below;
6492 }
6493 if (taskTopI == replyChainEnd) {
6494 taskTopI = -1;
6495 }
6496 replyChainEnd = -1;
6497 addRecentTask(target.task);
6498 } else if (forceReset || finishOnTaskLaunch
6499 || clearWhenTaskReset) {
6500 // If the activity should just be removed -- either
6501 // because it asks for it, or the task should be
6502 // cleared -- then finish it and anything that is
6503 // part of its reply chain.
6504 if (clearWhenTaskReset) {
6505 // In this case, we want to finish this activity
6506 // and everything above it, so be sneaky and pretend
6507 // like these are all in the reply chain.
6508 replyChainEnd = targetI+1;
6509 while (replyChainEnd < mHistory.size() &&
6510 ((HistoryRecord)mHistory.get(
6511 replyChainEnd)).task == task) {
6512 replyChainEnd++;
6513 }
6514 replyChainEnd--;
6515 } else if (replyChainEnd < 0) {
6516 replyChainEnd = targetI;
6517 }
6518 HistoryRecord p = null;
6519 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6520 p = (HistoryRecord)mHistory.get(srcPos);
6521 if (p.finishing) {
6522 continue;
6523 }
6524 if (finishActivityLocked(p, srcPos,
6525 Activity.RESULT_CANCELED, null, "reset")) {
6526 replyChainEnd--;
6527 srcPos--;
6528 }
6529 }
6530 if (taskTop == p) {
6531 taskTop = below;
6532 }
6533 if (taskTopI == replyChainEnd) {
6534 taskTopI = -1;
6535 }
6536 replyChainEnd = -1;
6537 } else {
6538 // If we were in the middle of a chain, well the
6539 // activity that started it all doesn't want anything
6540 // special, so leave it all as-is.
6541 replyChainEnd = -1;
6542 }
6543 } else {
6544 // Reached the bottom of the task -- any reply chain
6545 // should be left as-is.
6546 replyChainEnd = -1;
6547 }
6548
6549 } else if (target.resultTo != null) {
6550 // If this activity is sending a reply to a previous
6551 // activity, we can't do anything with it now until
6552 // we reach the start of the reply chain.
6553 // XXX note that we are assuming the result is always
6554 // to the previous activity, which is almost always
6555 // the case but we really shouldn't count on.
6556 if (replyChainEnd < 0) {
6557 replyChainEnd = targetI;
6558 }
6559
6560 } else if (taskTopI >= 0 && allowTaskReparenting
6561 && task.affinity != null
6562 && task.affinity.equals(target.taskAffinity)) {
6563 // We are inside of another task... if this activity has
6564 // an affinity for our task, then either remove it if we are
6565 // clearing or move it over to our task. Note that
6566 // we currently punt on the case where we are resetting a
6567 // task that is not at the top but who has activities above
6568 // with an affinity to it... this is really not a normal
6569 // case, and we will need to later pull that task to the front
6570 // and usually at that point we will do the reset and pick
6571 // up those remaining activities. (This only happens if
6572 // someone starts an activity in a new task from an activity
6573 // in a task that is not currently on top.)
6574 if (forceReset || finishOnTaskLaunch) {
6575 if (replyChainEnd < 0) {
6576 replyChainEnd = targetI;
6577 }
6578 HistoryRecord p = null;
6579 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6580 p = (HistoryRecord)mHistory.get(srcPos);
6581 if (p.finishing) {
6582 continue;
6583 }
6584 if (finishActivityLocked(p, srcPos,
6585 Activity.RESULT_CANCELED, null, "reset")) {
6586 taskTopI--;
6587 lastReparentPos--;
6588 replyChainEnd--;
6589 srcPos--;
6590 }
6591 }
6592 replyChainEnd = -1;
6593 } else {
6594 if (replyChainEnd < 0) {
6595 replyChainEnd = targetI;
6596 }
6597 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6598 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6599 if (p.finishing) {
6600 continue;
6601 }
6602 if (lastReparentPos < 0) {
6603 lastReparentPos = taskTopI;
6604 taskTop = p;
6605 } else {
6606 lastReparentPos--;
6607 }
6608 mHistory.remove(srcPos);
6609 p.task.numActivities--;
6610 p.task = task;
6611 mHistory.add(lastReparentPos, p);
6612 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6613 + " in to resetting task " + task);
6614 task.numActivities++;
6615 mWindowManager.moveAppToken(lastReparentPos, p);
6616 mWindowManager.setAppGroupId(p, p.task.taskId);
6617 if (VALIDATE_TOKENS) {
6618 mWindowManager.validateAppTokens(mHistory);
6619 }
6620 }
6621 replyChainEnd = -1;
6622
6623 // Now we've moved it in to place... but what if this is
6624 // a singleTop activity and we have put it on top of another
6625 // instance of the same activity? Then we drop the instance
6626 // below so it remains singleTop.
6627 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6628 for (int j=lastReparentPos-1; j>=0; j--) {
6629 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6630 if (p.finishing) {
6631 continue;
6632 }
6633 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6634 if (finishActivityLocked(p, j,
6635 Activity.RESULT_CANCELED, null, "replace")) {
6636 taskTopI--;
6637 lastReparentPos--;
6638 }
6639 }
6640 }
6641 }
6642 }
6643 }
6644
6645 target = below;
6646 targetI = i;
6647 }
6648
6649 return taskTop;
6650 }
6651
6652 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006653 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006654 */
6655 public void moveTaskToFront(int task) {
6656 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6657 "moveTaskToFront()");
6658
6659 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006660 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6661 Binder.getCallingUid(), "Task to front")) {
6662 return;
6663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006664 final long origId = Binder.clearCallingIdentity();
6665 try {
6666 int N = mRecentTasks.size();
6667 for (int i=0; i<N; i++) {
6668 TaskRecord tr = mRecentTasks.get(i);
6669 if (tr.taskId == task) {
6670 moveTaskToFrontLocked(tr);
6671 return;
6672 }
6673 }
6674 for (int i=mHistory.size()-1; i>=0; i--) {
6675 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6676 if (hr.task.taskId == task) {
6677 moveTaskToFrontLocked(hr.task);
6678 return;
6679 }
6680 }
6681 } finally {
6682 Binder.restoreCallingIdentity(origId);
6683 }
6684 }
6685 }
6686
6687 private final void moveTaskToFrontLocked(TaskRecord tr) {
6688 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6689
6690 final int task = tr.taskId;
6691 int top = mHistory.size()-1;
6692
6693 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6694 // nothing to do!
6695 return;
6696 }
6697
6698 if (DEBUG_TRANSITION) Log.v(TAG,
6699 "Prepare to front transition: task=" + tr);
6700 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6701
6702 ArrayList moved = new ArrayList();
6703
6704 // Applying the affinities may have removed entries from the history,
6705 // so get the size again.
6706 top = mHistory.size()-1;
6707 int pos = top;
6708
6709 // Shift all activities with this task up to the top
6710 // of the stack, keeping them in the same internal order.
6711 while (pos >= 0) {
6712 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6713 if (localLOGV) Log.v(
6714 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6715 boolean first = true;
6716 if (r.task.taskId == task) {
6717 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6718 mHistory.remove(pos);
6719 mHistory.add(top, r);
6720 moved.add(0, r);
6721 top--;
6722 if (first) {
6723 addRecentTask(r.task);
6724 first = false;
6725 }
6726 }
6727 pos--;
6728 }
6729
6730 mWindowManager.moveAppTokensToTop(moved);
6731 if (VALIDATE_TOKENS) {
6732 mWindowManager.validateAppTokens(mHistory);
6733 }
6734
6735 finishTaskMove(task);
6736 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6737 }
6738
6739 private final void finishTaskMove(int task) {
6740 resumeTopActivityLocked(null);
6741 }
6742
6743 public void moveTaskToBack(int task) {
6744 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6745 "moveTaskToBack()");
6746
6747 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006748 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6749 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6750 Binder.getCallingUid(), "Task to back")) {
6751 return;
6752 }
6753 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006754 final long origId = Binder.clearCallingIdentity();
6755 moveTaskToBackLocked(task);
6756 Binder.restoreCallingIdentity(origId);
6757 }
6758 }
6759
6760 /**
6761 * Moves an activity, and all of the other activities within the same task, to the bottom
6762 * of the history stack. The activity's order within the task is unchanged.
6763 *
6764 * @param token A reference to the activity we wish to move
6765 * @param nonRoot If false then this only works if the activity is the root
6766 * of a task; if true it will work for any activity in a task.
6767 * @return Returns true if the move completed, false if not.
6768 */
6769 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6770 synchronized(this) {
6771 final long origId = Binder.clearCallingIdentity();
6772 int taskId = getTaskForActivityLocked(token, !nonRoot);
6773 if (taskId >= 0) {
6774 return moveTaskToBackLocked(taskId);
6775 }
6776 Binder.restoreCallingIdentity(origId);
6777 }
6778 return false;
6779 }
6780
6781 /**
6782 * Worker method for rearranging history stack. Implements the function of moving all
6783 * activities for a specific task (gathering them if disjoint) into a single group at the
6784 * bottom of the stack.
6785 *
6786 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6787 * to premeptively cancel the move.
6788 *
6789 * @param task The taskId to collect and move to the bottom.
6790 * @return Returns true if the move completed, false if not.
6791 */
6792 private final boolean moveTaskToBackLocked(int task) {
6793 Log.i(TAG, "moveTaskToBack: " + task);
6794
6795 // If we have a watcher, preflight the move before committing to it. First check
6796 // for *other* available tasks, but if none are available, then try again allowing the
6797 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006798 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006799 HistoryRecord next = topRunningActivityLocked(null, task);
6800 if (next == null) {
6801 next = topRunningActivityLocked(null, 0);
6802 }
6803 if (next != null) {
6804 // ask watcher if this is allowed
6805 boolean moveOK = true;
6806 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006807 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006808 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006809 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006810 }
6811 if (!moveOK) {
6812 return false;
6813 }
6814 }
6815 }
6816
6817 ArrayList moved = new ArrayList();
6818
6819 if (DEBUG_TRANSITION) Log.v(TAG,
6820 "Prepare to back transition: task=" + task);
6821 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6822
6823 final int N = mHistory.size();
6824 int bottom = 0;
6825 int pos = 0;
6826
6827 // Shift all activities with this task down to the bottom
6828 // of the stack, keeping them in the same internal order.
6829 while (pos < N) {
6830 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6831 if (localLOGV) Log.v(
6832 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6833 if (r.task.taskId == task) {
6834 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6835 mHistory.remove(pos);
6836 mHistory.add(bottom, r);
6837 moved.add(r);
6838 bottom++;
6839 }
6840 pos++;
6841 }
6842
6843 mWindowManager.moveAppTokensToBottom(moved);
6844 if (VALIDATE_TOKENS) {
6845 mWindowManager.validateAppTokens(mHistory);
6846 }
6847
6848 finishTaskMove(task);
6849 return true;
6850 }
6851
6852 public void moveTaskBackwards(int task) {
6853 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6854 "moveTaskBackwards()");
6855
6856 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006857 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6858 Binder.getCallingUid(), "Task backwards")) {
6859 return;
6860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006861 final long origId = Binder.clearCallingIdentity();
6862 moveTaskBackwardsLocked(task);
6863 Binder.restoreCallingIdentity(origId);
6864 }
6865 }
6866
6867 private final void moveTaskBackwardsLocked(int task) {
6868 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6869 }
6870
6871 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6872 synchronized(this) {
6873 return getTaskForActivityLocked(token, onlyRoot);
6874 }
6875 }
6876
6877 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6878 final int N = mHistory.size();
6879 TaskRecord lastTask = null;
6880 for (int i=0; i<N; i++) {
6881 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6882 if (r == token) {
6883 if (!onlyRoot || lastTask != r.task) {
6884 return r.task.taskId;
6885 }
6886 return -1;
6887 }
6888 lastTask = r.task;
6889 }
6890
6891 return -1;
6892 }
6893
6894 /**
6895 * Returns the top activity in any existing task matching the given
6896 * Intent. Returns null if no such task is found.
6897 */
6898 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6899 ComponentName cls = intent.getComponent();
6900 if (info.targetActivity != null) {
6901 cls = new ComponentName(info.packageName, info.targetActivity);
6902 }
6903
6904 TaskRecord cp = null;
6905
6906 final int N = mHistory.size();
6907 for (int i=(N-1); i>=0; i--) {
6908 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6909 if (!r.finishing && r.task != cp
6910 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6911 cp = r.task;
6912 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6913 // + "/aff=" + r.task.affinity + " to new cls="
6914 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6915 if (r.task.affinity != null) {
6916 if (r.task.affinity.equals(info.taskAffinity)) {
6917 //Log.i(TAG, "Found matching affinity!");
6918 return r;
6919 }
6920 } else if (r.task.intent != null
6921 && r.task.intent.getComponent().equals(cls)) {
6922 //Log.i(TAG, "Found matching class!");
6923 //dump();
6924 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6925 return r;
6926 } else if (r.task.affinityIntent != null
6927 && r.task.affinityIntent.getComponent().equals(cls)) {
6928 //Log.i(TAG, "Found matching class!");
6929 //dump();
6930 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6931 return r;
6932 }
6933 }
6934 }
6935
6936 return null;
6937 }
6938
6939 /**
6940 * Returns the first activity (starting from the top of the stack) that
6941 * is the same as the given activity. Returns null if no such activity
6942 * is found.
6943 */
6944 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6945 ComponentName cls = intent.getComponent();
6946 if (info.targetActivity != null) {
6947 cls = new ComponentName(info.packageName, info.targetActivity);
6948 }
6949
6950 final int N = mHistory.size();
6951 for (int i=(N-1); i>=0; i--) {
6952 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6953 if (!r.finishing) {
6954 if (r.intent.getComponent().equals(cls)) {
6955 //Log.i(TAG, "Found matching class!");
6956 //dump();
6957 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6958 return r;
6959 }
6960 }
6961 }
6962
6963 return null;
6964 }
6965
6966 public void finishOtherInstances(IBinder token, ComponentName className) {
6967 synchronized(this) {
6968 final long origId = Binder.clearCallingIdentity();
6969
6970 int N = mHistory.size();
6971 TaskRecord lastTask = null;
6972 for (int i=0; i<N; i++) {
6973 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6974 if (r.realActivity.equals(className)
6975 && r != token && lastTask != r.task) {
6976 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6977 null, "others")) {
6978 i--;
6979 N--;
6980 }
6981 }
6982 lastTask = r.task;
6983 }
6984
6985 Binder.restoreCallingIdentity(origId);
6986 }
6987 }
6988
6989 // =========================================================
6990 // THUMBNAILS
6991 // =========================================================
6992
6993 public void reportThumbnail(IBinder token,
6994 Bitmap thumbnail, CharSequence description) {
6995 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6996 final long origId = Binder.clearCallingIdentity();
6997 sendPendingThumbnail(null, token, thumbnail, description, true);
6998 Binder.restoreCallingIdentity(origId);
6999 }
7000
7001 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7002 Bitmap thumbnail, CharSequence description, boolean always) {
7003 TaskRecord task = null;
7004 ArrayList receivers = null;
7005
7006 //System.out.println("Send pending thumbnail: " + r);
7007
7008 synchronized(this) {
7009 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007010 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007011 if (index < 0) {
7012 return;
7013 }
7014 r = (HistoryRecord)mHistory.get(index);
7015 }
7016 if (thumbnail == null) {
7017 thumbnail = r.thumbnail;
7018 description = r.description;
7019 }
7020 if (thumbnail == null && !always) {
7021 // If there is no thumbnail, and this entry is not actually
7022 // going away, then abort for now and pick up the next
7023 // thumbnail we get.
7024 return;
7025 }
7026 task = r.task;
7027
7028 int N = mPendingThumbnails.size();
7029 int i=0;
7030 while (i<N) {
7031 PendingThumbnailsRecord pr =
7032 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7033 //System.out.println("Looking in " + pr.pendingRecords);
7034 if (pr.pendingRecords.remove(r)) {
7035 if (receivers == null) {
7036 receivers = new ArrayList();
7037 }
7038 receivers.add(pr);
7039 if (pr.pendingRecords.size() == 0) {
7040 pr.finished = true;
7041 mPendingThumbnails.remove(i);
7042 N--;
7043 continue;
7044 }
7045 }
7046 i++;
7047 }
7048 }
7049
7050 if (receivers != null) {
7051 final int N = receivers.size();
7052 for (int i=0; i<N; i++) {
7053 try {
7054 PendingThumbnailsRecord pr =
7055 (PendingThumbnailsRecord)receivers.get(i);
7056 pr.receiver.newThumbnail(
7057 task != null ? task.taskId : -1, thumbnail, description);
7058 if (pr.finished) {
7059 pr.receiver.finished();
7060 }
7061 } catch (Exception e) {
7062 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7063 }
7064 }
7065 }
7066 }
7067
7068 // =========================================================
7069 // CONTENT PROVIDERS
7070 // =========================================================
7071
7072 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7073 List providers = null;
7074 try {
7075 providers = ActivityThread.getPackageManager().
7076 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007077 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007078 } catch (RemoteException ex) {
7079 }
7080 if (providers != null) {
7081 final int N = providers.size();
7082 for (int i=0; i<N; i++) {
7083 ProviderInfo cpi =
7084 (ProviderInfo)providers.get(i);
7085 ContentProviderRecord cpr =
7086 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7087 if (cpr == null) {
7088 cpr = new ContentProviderRecord(cpi, app.info);
7089 mProvidersByClass.put(cpi.name, cpr);
7090 }
7091 app.pubProviders.put(cpi.name, cpr);
7092 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007093 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007094 }
7095 }
7096 return providers;
7097 }
7098
7099 private final String checkContentProviderPermissionLocked(
7100 ProviderInfo cpi, ProcessRecord r, int mode) {
7101 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7102 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7103 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7104 cpi.exported ? -1 : cpi.applicationInfo.uid)
7105 == PackageManager.PERMISSION_GRANTED
7106 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7107 return null;
7108 }
7109 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7110 cpi.exported ? -1 : cpi.applicationInfo.uid)
7111 == PackageManager.PERMISSION_GRANTED) {
7112 return null;
7113 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007114
7115 PathPermission[] pps = cpi.pathPermissions;
7116 if (pps != null) {
7117 int i = pps.length;
7118 while (i > 0) {
7119 i--;
7120 PathPermission pp = pps[i];
7121 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7122 cpi.exported ? -1 : cpi.applicationInfo.uid)
7123 == PackageManager.PERMISSION_GRANTED
7124 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7125 return null;
7126 }
7127 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7128 cpi.exported ? -1 : cpi.applicationInfo.uid)
7129 == PackageManager.PERMISSION_GRANTED) {
7130 return null;
7131 }
7132 }
7133 }
7134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007135 String msg = "Permission Denial: opening provider " + cpi.name
7136 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7137 + ", uid=" + callingUid + ") requires "
7138 + cpi.readPermission + " or " + cpi.writePermission;
7139 Log.w(TAG, msg);
7140 return msg;
7141 }
7142
7143 private final ContentProviderHolder getContentProviderImpl(
7144 IApplicationThread caller, String name) {
7145 ContentProviderRecord cpr;
7146 ProviderInfo cpi = null;
7147
7148 synchronized(this) {
7149 ProcessRecord r = null;
7150 if (caller != null) {
7151 r = getRecordForAppLocked(caller);
7152 if (r == null) {
7153 throw new SecurityException(
7154 "Unable to find app for caller " + caller
7155 + " (pid=" + Binder.getCallingPid()
7156 + ") when getting content provider " + name);
7157 }
7158 }
7159
7160 // First check if this content provider has been published...
7161 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7162 if (cpr != null) {
7163 cpi = cpr.info;
7164 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7165 return new ContentProviderHolder(cpi,
7166 cpi.readPermission != null
7167 ? cpi.readPermission : cpi.writePermission);
7168 }
7169
7170 if (r != null && cpr.canRunHere(r)) {
7171 // This provider has been published or is in the process
7172 // of being published... but it is also allowed to run
7173 // in the caller's process, so don't make a connection
7174 // and just let the caller instantiate its own instance.
7175 if (cpr.provider != null) {
7176 // don't give caller the provider object, it needs
7177 // to make its own.
7178 cpr = new ContentProviderRecord(cpr);
7179 }
7180 return cpr;
7181 }
7182
7183 final long origId = Binder.clearCallingIdentity();
7184
7185 // In this case the provider is a single instance, so we can
7186 // return it right away.
7187 if (r != null) {
7188 r.conProviders.add(cpr);
7189 cpr.clients.add(r);
7190 } else {
7191 cpr.externals++;
7192 }
7193
7194 if (cpr.app != null) {
7195 updateOomAdjLocked(cpr.app);
7196 }
7197
7198 Binder.restoreCallingIdentity(origId);
7199
7200 } else {
7201 try {
7202 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007203 resolveContentProvider(name,
7204 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007205 } catch (RemoteException ex) {
7206 }
7207 if (cpi == null) {
7208 return null;
7209 }
7210
7211 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7212 return new ContentProviderHolder(cpi,
7213 cpi.readPermission != null
7214 ? cpi.readPermission : cpi.writePermission);
7215 }
7216
7217 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7218 final boolean firstClass = cpr == null;
7219 if (firstClass) {
7220 try {
7221 ApplicationInfo ai =
7222 ActivityThread.getPackageManager().
7223 getApplicationInfo(
7224 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007225 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007226 if (ai == null) {
7227 Log.w(TAG, "No package info for content provider "
7228 + cpi.name);
7229 return null;
7230 }
7231 cpr = new ContentProviderRecord(cpi, ai);
7232 } catch (RemoteException ex) {
7233 // pm is in same process, this will never happen.
7234 }
7235 }
7236
7237 if (r != null && cpr.canRunHere(r)) {
7238 // If this is a multiprocess provider, then just return its
7239 // info and allow the caller to instantiate it. Only do
7240 // this if the provider is the same user as the caller's
7241 // process, or can run as root (so can be in any process).
7242 return cpr;
7243 }
7244
7245 if (false) {
7246 RuntimeException e = new RuntimeException("foo");
7247 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7248 // + " pruid " + ai.uid + "): " + cpi.className, e);
7249 }
7250
7251 // This is single process, and our app is now connecting to it.
7252 // See if we are already in the process of launching this
7253 // provider.
7254 final int N = mLaunchingProviders.size();
7255 int i;
7256 for (i=0; i<N; i++) {
7257 if (mLaunchingProviders.get(i) == cpr) {
7258 break;
7259 }
7260 if (false) {
7261 final ContentProviderRecord rec =
7262 (ContentProviderRecord)mLaunchingProviders.get(i);
7263 if (rec.info.name.equals(cpr.info.name)) {
7264 cpr = rec;
7265 break;
7266 }
7267 }
7268 }
7269
7270 // If the provider is not already being launched, then get it
7271 // started.
7272 if (i >= N) {
7273 final long origId = Binder.clearCallingIdentity();
7274 ProcessRecord proc = startProcessLocked(cpi.processName,
7275 cpr.appInfo, false, 0, "content provider",
7276 new ComponentName(cpi.applicationInfo.packageName,
7277 cpi.name));
7278 if (proc == null) {
7279 Log.w(TAG, "Unable to launch app "
7280 + cpi.applicationInfo.packageName + "/"
7281 + cpi.applicationInfo.uid + " for provider "
7282 + name + ": process is bad");
7283 return null;
7284 }
7285 cpr.launchingApp = proc;
7286 mLaunchingProviders.add(cpr);
7287 Binder.restoreCallingIdentity(origId);
7288 }
7289
7290 // Make sure the provider is published (the same provider class
7291 // may be published under multiple names).
7292 if (firstClass) {
7293 mProvidersByClass.put(cpi.name, cpr);
7294 }
7295 mProvidersByName.put(name, cpr);
7296
7297 if (r != null) {
7298 r.conProviders.add(cpr);
7299 cpr.clients.add(r);
7300 } else {
7301 cpr.externals++;
7302 }
7303 }
7304 }
7305
7306 // Wait for the provider to be published...
7307 synchronized (cpr) {
7308 while (cpr.provider == null) {
7309 if (cpr.launchingApp == null) {
7310 Log.w(TAG, "Unable to launch app "
7311 + cpi.applicationInfo.packageName + "/"
7312 + cpi.applicationInfo.uid + " for provider "
7313 + name + ": launching app became null");
7314 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7315 cpi.applicationInfo.packageName,
7316 cpi.applicationInfo.uid, name);
7317 return null;
7318 }
7319 try {
7320 cpr.wait();
7321 } catch (InterruptedException ex) {
7322 }
7323 }
7324 }
7325 return cpr;
7326 }
7327
7328 public final ContentProviderHolder getContentProvider(
7329 IApplicationThread caller, String name) {
7330 if (caller == null) {
7331 String msg = "null IApplicationThread when getting content provider "
7332 + name;
7333 Log.w(TAG, msg);
7334 throw new SecurityException(msg);
7335 }
7336
7337 return getContentProviderImpl(caller, name);
7338 }
7339
7340 private ContentProviderHolder getContentProviderExternal(String name) {
7341 return getContentProviderImpl(null, name);
7342 }
7343
7344 /**
7345 * Drop a content provider from a ProcessRecord's bookkeeping
7346 * @param cpr
7347 */
7348 public void removeContentProvider(IApplicationThread caller, String name) {
7349 synchronized (this) {
7350 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7351 if(cpr == null) {
7352 //remove from mProvidersByClass
7353 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7354 return;
7355 }
7356 final ProcessRecord r = getRecordForAppLocked(caller);
7357 if (r == null) {
7358 throw new SecurityException(
7359 "Unable to find app for caller " + caller +
7360 " when removing content provider " + name);
7361 }
7362 //update content provider record entry info
7363 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7364 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7365 r.info.processName+" from process "+localCpr.appInfo.processName);
7366 if(localCpr.appInfo.processName == r.info.processName) {
7367 //should not happen. taken care of as a local provider
7368 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7369 return;
7370 } else {
7371 localCpr.clients.remove(r);
7372 r.conProviders.remove(localCpr);
7373 }
7374 updateOomAdjLocked();
7375 }
7376 }
7377
7378 private void removeContentProviderExternal(String name) {
7379 synchronized (this) {
7380 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7381 if(cpr == null) {
7382 //remove from mProvidersByClass
7383 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7384 return;
7385 }
7386
7387 //update content provider record entry info
7388 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7389 localCpr.externals--;
7390 if (localCpr.externals < 0) {
7391 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7392 }
7393 updateOomAdjLocked();
7394 }
7395 }
7396
7397 public final void publishContentProviders(IApplicationThread caller,
7398 List<ContentProviderHolder> providers) {
7399 if (providers == null) {
7400 return;
7401 }
7402
7403 synchronized(this) {
7404 final ProcessRecord r = getRecordForAppLocked(caller);
7405 if (r == null) {
7406 throw new SecurityException(
7407 "Unable to find app for caller " + caller
7408 + " (pid=" + Binder.getCallingPid()
7409 + ") when publishing content providers");
7410 }
7411
7412 final long origId = Binder.clearCallingIdentity();
7413
7414 final int N = providers.size();
7415 for (int i=0; i<N; i++) {
7416 ContentProviderHolder src = providers.get(i);
7417 if (src == null || src.info == null || src.provider == null) {
7418 continue;
7419 }
7420 ContentProviderRecord dst =
7421 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7422 if (dst != null) {
7423 mProvidersByClass.put(dst.info.name, dst);
7424 String names[] = dst.info.authority.split(";");
7425 for (int j = 0; j < names.length; j++) {
7426 mProvidersByName.put(names[j], dst);
7427 }
7428
7429 int NL = mLaunchingProviders.size();
7430 int j;
7431 for (j=0; j<NL; j++) {
7432 if (mLaunchingProviders.get(j) == dst) {
7433 mLaunchingProviders.remove(j);
7434 j--;
7435 NL--;
7436 }
7437 }
7438 synchronized (dst) {
7439 dst.provider = src.provider;
7440 dst.app = r;
7441 dst.notifyAll();
7442 }
7443 updateOomAdjLocked(r);
7444 }
7445 }
7446
7447 Binder.restoreCallingIdentity(origId);
7448 }
7449 }
7450
7451 public static final void installSystemProviders() {
7452 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7453 List providers = mSelf.generateApplicationProvidersLocked(app);
7454 mSystemThread.installSystemProviders(providers);
7455 }
7456
7457 // =========================================================
7458 // GLOBAL MANAGEMENT
7459 // =========================================================
7460
7461 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7462 ApplicationInfo info, String customProcess) {
7463 String proc = customProcess != null ? customProcess : info.processName;
7464 BatteryStatsImpl.Uid.Proc ps = null;
7465 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7466 synchronized (stats) {
7467 ps = stats.getProcessStatsLocked(info.uid, proc);
7468 }
7469 return new ProcessRecord(ps, thread, info, proc);
7470 }
7471
7472 final ProcessRecord addAppLocked(ApplicationInfo info) {
7473 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7474
7475 if (app == null) {
7476 app = newProcessRecordLocked(null, info, null);
7477 mProcessNames.put(info.processName, info.uid, app);
7478 updateLRUListLocked(app, true);
7479 }
7480
7481 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7482 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7483 app.persistent = true;
7484 app.maxAdj = CORE_SERVER_ADJ;
7485 }
7486 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7487 mPersistentStartingProcesses.add(app);
7488 startProcessLocked(app, "added application", app.processName);
7489 }
7490
7491 return app;
7492 }
7493
7494 public void unhandledBack() {
7495 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7496 "unhandledBack()");
7497
7498 synchronized(this) {
7499 int count = mHistory.size();
7500 if (Config.LOGD) Log.d(
7501 TAG, "Performing unhandledBack(): stack size = " + count);
7502 if (count > 1) {
7503 final long origId = Binder.clearCallingIdentity();
7504 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7505 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7506 Binder.restoreCallingIdentity(origId);
7507 }
7508 }
7509 }
7510
7511 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7512 String name = uri.getAuthority();
7513 ContentProviderHolder cph = getContentProviderExternal(name);
7514 ParcelFileDescriptor pfd = null;
7515 if (cph != null) {
7516 // We record the binder invoker's uid in thread-local storage before
7517 // going to the content provider to open the file. Later, in the code
7518 // that handles all permissions checks, we look for this uid and use
7519 // that rather than the Activity Manager's own uid. The effect is that
7520 // we do the check against the caller's permissions even though it looks
7521 // to the content provider like the Activity Manager itself is making
7522 // the request.
7523 sCallerIdentity.set(new Identity(
7524 Binder.getCallingPid(), Binder.getCallingUid()));
7525 try {
7526 pfd = cph.provider.openFile(uri, "r");
7527 } catch (FileNotFoundException e) {
7528 // do nothing; pfd will be returned null
7529 } finally {
7530 // Ensure that whatever happens, we clean up the identity state
7531 sCallerIdentity.remove();
7532 }
7533
7534 // We've got the fd now, so we're done with the provider.
7535 removeContentProviderExternal(name);
7536 } else {
7537 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7538 }
7539 return pfd;
7540 }
7541
7542 public void goingToSleep() {
7543 synchronized(this) {
7544 mSleeping = true;
7545 mWindowManager.setEventDispatching(false);
7546
7547 if (mResumedActivity != null) {
7548 pauseIfSleepingLocked();
7549 } else {
7550 Log.w(TAG, "goingToSleep with no resumed activity!");
7551 }
7552 }
7553 }
7554
Dianne Hackborn55280a92009-05-07 15:53:46 -07007555 public boolean shutdown(int timeout) {
7556 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7557 != PackageManager.PERMISSION_GRANTED) {
7558 throw new SecurityException("Requires permission "
7559 + android.Manifest.permission.SHUTDOWN);
7560 }
7561
7562 boolean timedout = false;
7563
7564 synchronized(this) {
7565 mShuttingDown = true;
7566 mWindowManager.setEventDispatching(false);
7567
7568 if (mResumedActivity != null) {
7569 pauseIfSleepingLocked();
7570 final long endTime = System.currentTimeMillis() + timeout;
7571 while (mResumedActivity != null || mPausingActivity != null) {
7572 long delay = endTime - System.currentTimeMillis();
7573 if (delay <= 0) {
7574 Log.w(TAG, "Activity manager shutdown timed out");
7575 timedout = true;
7576 break;
7577 }
7578 try {
7579 this.wait();
7580 } catch (InterruptedException e) {
7581 }
7582 }
7583 }
7584 }
7585
7586 mUsageStatsService.shutdown();
7587 mBatteryStatsService.shutdown();
7588
7589 return timedout;
7590 }
7591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007592 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007593 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 if (!mGoingToSleep.isHeld()) {
7595 mGoingToSleep.acquire();
7596 if (mLaunchingActivity.isHeld()) {
7597 mLaunchingActivity.release();
7598 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7599 }
7600 }
7601
7602 // If we are not currently pausing an activity, get the current
7603 // one to pause. If we are pausing one, we will just let that stuff
7604 // run and release the wake lock when all done.
7605 if (mPausingActivity == null) {
7606 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7607 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7608 startPausingLocked(false, true);
7609 }
7610 }
7611 }
7612
7613 public void wakingUp() {
7614 synchronized(this) {
7615 if (mGoingToSleep.isHeld()) {
7616 mGoingToSleep.release();
7617 }
7618 mWindowManager.setEventDispatching(true);
7619 mSleeping = false;
7620 resumeTopActivityLocked(null);
7621 }
7622 }
7623
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007624 public void stopAppSwitches() {
7625 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7626 != PackageManager.PERMISSION_GRANTED) {
7627 throw new SecurityException("Requires permission "
7628 + android.Manifest.permission.STOP_APP_SWITCHES);
7629 }
7630
7631 synchronized(this) {
7632 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7633 + APP_SWITCH_DELAY_TIME;
7634 mDidAppSwitch = false;
7635 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7636 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7637 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7638 }
7639 }
7640
7641 public void resumeAppSwitches() {
7642 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7643 != PackageManager.PERMISSION_GRANTED) {
7644 throw new SecurityException("Requires permission "
7645 + android.Manifest.permission.STOP_APP_SWITCHES);
7646 }
7647
7648 synchronized(this) {
7649 // Note that we don't execute any pending app switches... we will
7650 // let those wait until either the timeout, or the next start
7651 // activity request.
7652 mAppSwitchesAllowedTime = 0;
7653 }
7654 }
7655
7656 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7657 String name) {
7658 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7659 return true;
7660 }
7661
7662 final int perm = checkComponentPermission(
7663 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7664 callingUid, -1);
7665 if (perm == PackageManager.PERMISSION_GRANTED) {
7666 return true;
7667 }
7668
7669 Log.w(TAG, name + " request from " + callingUid + " stopped");
7670 return false;
7671 }
7672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007673 public void setDebugApp(String packageName, boolean waitForDebugger,
7674 boolean persistent) {
7675 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7676 "setDebugApp()");
7677
7678 // Note that this is not really thread safe if there are multiple
7679 // callers into it at the same time, but that's not a situation we
7680 // care about.
7681 if (persistent) {
7682 final ContentResolver resolver = mContext.getContentResolver();
7683 Settings.System.putString(
7684 resolver, Settings.System.DEBUG_APP,
7685 packageName);
7686 Settings.System.putInt(
7687 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7688 waitForDebugger ? 1 : 0);
7689 }
7690
7691 synchronized (this) {
7692 if (!persistent) {
7693 mOrigDebugApp = mDebugApp;
7694 mOrigWaitForDebugger = mWaitForDebugger;
7695 }
7696 mDebugApp = packageName;
7697 mWaitForDebugger = waitForDebugger;
7698 mDebugTransient = !persistent;
7699 if (packageName != null) {
7700 final long origId = Binder.clearCallingIdentity();
7701 uninstallPackageLocked(packageName, -1, false);
7702 Binder.restoreCallingIdentity(origId);
7703 }
7704 }
7705 }
7706
7707 public void setAlwaysFinish(boolean enabled) {
7708 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7709 "setAlwaysFinish()");
7710
7711 Settings.System.putInt(
7712 mContext.getContentResolver(),
7713 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7714
7715 synchronized (this) {
7716 mAlwaysFinishActivities = enabled;
7717 }
7718 }
7719
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007720 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007721 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007722 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007723 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007724 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007725 }
7726 }
7727
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007728 public void registerActivityWatcher(IActivityWatcher watcher) {
7729 mWatchers.register(watcher);
7730 }
7731
7732 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7733 mWatchers.unregister(watcher);
7734 }
7735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007736 public final void enterSafeMode() {
7737 synchronized(this) {
7738 // It only makes sense to do this before the system is ready
7739 // and started launching other packages.
7740 if (!mSystemReady) {
7741 try {
7742 ActivityThread.getPackageManager().enterSafeMode();
7743 } catch (RemoteException e) {
7744 }
7745
7746 View v = LayoutInflater.from(mContext).inflate(
7747 com.android.internal.R.layout.safe_mode, null);
7748 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7749 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7750 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7751 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7752 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7753 lp.format = v.getBackground().getOpacity();
7754 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7755 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7756 ((WindowManager)mContext.getSystemService(
7757 Context.WINDOW_SERVICE)).addView(v, lp);
7758 }
7759 }
7760 }
7761
7762 public void noteWakeupAlarm(IIntentSender sender) {
7763 if (!(sender instanceof PendingIntentRecord)) {
7764 return;
7765 }
7766 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7767 synchronized (stats) {
7768 if (mBatteryStatsService.isOnBattery()) {
7769 mBatteryStatsService.enforceCallingPermission();
7770 PendingIntentRecord rec = (PendingIntentRecord)sender;
7771 int MY_UID = Binder.getCallingUid();
7772 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7773 BatteryStatsImpl.Uid.Pkg pkg =
7774 stats.getPackageStatsLocked(uid, rec.key.packageName);
7775 pkg.incWakeupsLocked();
7776 }
7777 }
7778 }
7779
7780 public boolean killPidsForMemory(int[] pids) {
7781 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7782 throw new SecurityException("killPidsForMemory only available to the system");
7783 }
7784
7785 // XXX Note: don't acquire main activity lock here, because the window
7786 // manager calls in with its locks held.
7787
7788 boolean killed = false;
7789 synchronized (mPidsSelfLocked) {
7790 int[] types = new int[pids.length];
7791 int worstType = 0;
7792 for (int i=0; i<pids.length; i++) {
7793 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7794 if (proc != null) {
7795 int type = proc.setAdj;
7796 types[i] = type;
7797 if (type > worstType) {
7798 worstType = type;
7799 }
7800 }
7801 }
7802
7803 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7804 // then constrain it so we will kill all hidden procs.
7805 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7806 worstType = HIDDEN_APP_MIN_ADJ;
7807 }
7808 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7809 for (int i=0; i<pids.length; i++) {
7810 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7811 if (proc == null) {
7812 continue;
7813 }
7814 int adj = proc.setAdj;
7815 if (adj >= worstType) {
7816 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7817 + adj + ")");
7818 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7819 proc.processName, adj);
7820 killed = true;
7821 Process.killProcess(pids[i]);
7822 }
7823 }
7824 }
7825 return killed;
7826 }
7827
7828 public void reportPss(IApplicationThread caller, int pss) {
7829 Watchdog.PssRequestor req;
7830 String name;
7831 ProcessRecord callerApp;
7832 synchronized (this) {
7833 if (caller == null) {
7834 return;
7835 }
7836 callerApp = getRecordForAppLocked(caller);
7837 if (callerApp == null) {
7838 return;
7839 }
7840 callerApp.lastPss = pss;
7841 req = callerApp;
7842 name = callerApp.processName;
7843 }
7844 Watchdog.getInstance().reportPss(req, name, pss);
7845 if (!callerApp.persistent) {
7846 removeRequestedPss(callerApp);
7847 }
7848 }
7849
7850 public void requestPss(Runnable completeCallback) {
7851 ArrayList<ProcessRecord> procs;
7852 synchronized (this) {
7853 mRequestPssCallback = completeCallback;
7854 mRequestPssList.clear();
7855 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7856 ProcessRecord proc = mLRUProcesses.get(i);
7857 if (!proc.persistent) {
7858 mRequestPssList.add(proc);
7859 }
7860 }
7861 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7862 }
7863
7864 int oldPri = Process.getThreadPriority(Process.myTid());
7865 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7866 for (int i=procs.size()-1; i>=0; i--) {
7867 ProcessRecord proc = procs.get(i);
7868 proc.lastPss = 0;
7869 proc.requestPss();
7870 }
7871 Process.setThreadPriority(oldPri);
7872 }
7873
7874 void removeRequestedPss(ProcessRecord proc) {
7875 Runnable callback = null;
7876 synchronized (this) {
7877 if (mRequestPssList.remove(proc)) {
7878 if (mRequestPssList.size() == 0) {
7879 callback = mRequestPssCallback;
7880 mRequestPssCallback = null;
7881 }
7882 }
7883 }
7884
7885 if (callback != null) {
7886 callback.run();
7887 }
7888 }
7889
7890 public void collectPss(Watchdog.PssStats stats) {
7891 stats.mEmptyPss = 0;
7892 stats.mEmptyCount = 0;
7893 stats.mBackgroundPss = 0;
7894 stats.mBackgroundCount = 0;
7895 stats.mServicePss = 0;
7896 stats.mServiceCount = 0;
7897 stats.mVisiblePss = 0;
7898 stats.mVisibleCount = 0;
7899 stats.mForegroundPss = 0;
7900 stats.mForegroundCount = 0;
7901 stats.mNoPssCount = 0;
7902 synchronized (this) {
7903 int i;
7904 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7905 ? mProcDeaths.length : stats.mProcDeaths.length;
7906 int aggr = 0;
7907 for (i=0; i<NPD; i++) {
7908 aggr += mProcDeaths[i];
7909 stats.mProcDeaths[i] = aggr;
7910 }
7911 while (i<stats.mProcDeaths.length) {
7912 stats.mProcDeaths[i] = 0;
7913 i++;
7914 }
7915
7916 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7917 ProcessRecord proc = mLRUProcesses.get(i);
7918 if (proc.persistent) {
7919 continue;
7920 }
7921 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7922 if (proc.lastPss == 0) {
7923 stats.mNoPssCount++;
7924 continue;
7925 }
7926 if (proc.setAdj == EMPTY_APP_ADJ) {
7927 stats.mEmptyPss += proc.lastPss;
7928 stats.mEmptyCount++;
7929 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7930 stats.mEmptyPss += proc.lastPss;
7931 stats.mEmptyCount++;
7932 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7933 stats.mBackgroundPss += proc.lastPss;
7934 stats.mBackgroundCount++;
7935 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7936 stats.mVisiblePss += proc.lastPss;
7937 stats.mVisibleCount++;
7938 } else {
7939 stats.mForegroundPss += proc.lastPss;
7940 stats.mForegroundCount++;
7941 }
7942 }
7943 }
7944 }
7945
7946 public final void startRunning(String pkg, String cls, String action,
7947 String data) {
7948 synchronized(this) {
7949 if (mStartRunning) {
7950 return;
7951 }
7952 mStartRunning = true;
7953 mTopComponent = pkg != null && cls != null
7954 ? new ComponentName(pkg, cls) : null;
7955 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7956 mTopData = data;
7957 if (!mSystemReady) {
7958 return;
7959 }
7960 }
7961
7962 systemReady();
7963 }
7964
7965 private void retrieveSettings() {
7966 final ContentResolver resolver = mContext.getContentResolver();
7967 String debugApp = Settings.System.getString(
7968 resolver, Settings.System.DEBUG_APP);
7969 boolean waitForDebugger = Settings.System.getInt(
7970 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7971 boolean alwaysFinishActivities = Settings.System.getInt(
7972 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7973
7974 Configuration configuration = new Configuration();
7975 Settings.System.getConfiguration(resolver, configuration);
7976
7977 synchronized (this) {
7978 mDebugApp = mOrigDebugApp = debugApp;
7979 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7980 mAlwaysFinishActivities = alwaysFinishActivities;
7981 // This happens before any activities are started, so we can
7982 // change mConfiguration in-place.
7983 mConfiguration.updateFrom(configuration);
7984 }
7985 }
7986
7987 public boolean testIsSystemReady() {
7988 // no need to synchronize(this) just to read & return the value
7989 return mSystemReady;
7990 }
7991
7992 public void systemReady() {
7993 // In the simulator, startRunning will never have been called, which
7994 // normally sets a few crucial variables. Do it here instead.
7995 if (!Process.supportsProcesses()) {
7996 mStartRunning = true;
7997 mTopAction = Intent.ACTION_MAIN;
7998 }
7999
8000 synchronized(this) {
8001 if (mSystemReady) {
8002 return;
8003 }
8004 mSystemReady = true;
8005 if (!mStartRunning) {
8006 return;
8007 }
8008 }
8009
8010 if (Config.LOGD) Log.d(TAG, "Start running!");
8011 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8012 SystemClock.uptimeMillis());
8013
8014 synchronized(this) {
8015 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8016 ResolveInfo ri = mContext.getPackageManager()
8017 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008018 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008019 CharSequence errorMsg = null;
8020 if (ri != null) {
8021 ActivityInfo ai = ri.activityInfo;
8022 ApplicationInfo app = ai.applicationInfo;
8023 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8024 mTopAction = Intent.ACTION_FACTORY_TEST;
8025 mTopData = null;
8026 mTopComponent = new ComponentName(app.packageName,
8027 ai.name);
8028 } else {
8029 errorMsg = mContext.getResources().getText(
8030 com.android.internal.R.string.factorytest_not_system);
8031 }
8032 } else {
8033 errorMsg = mContext.getResources().getText(
8034 com.android.internal.R.string.factorytest_no_action);
8035 }
8036 if (errorMsg != null) {
8037 mTopAction = null;
8038 mTopData = null;
8039 mTopComponent = null;
8040 Message msg = Message.obtain();
8041 msg.what = SHOW_FACTORY_ERROR_MSG;
8042 msg.getData().putCharSequence("msg", errorMsg);
8043 mHandler.sendMessage(msg);
8044 }
8045 }
8046 }
8047
8048 retrieveSettings();
8049
8050 synchronized (this) {
8051 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8052 try {
8053 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008054 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008055 if (apps != null) {
8056 int N = apps.size();
8057 int i;
8058 for (i=0; i<N; i++) {
8059 ApplicationInfo info
8060 = (ApplicationInfo)apps.get(i);
8061 if (info != null &&
8062 !info.packageName.equals("android")) {
8063 addAppLocked(info);
8064 }
8065 }
8066 }
8067 } catch (RemoteException ex) {
8068 // pm is in same process, this will never happen.
8069 }
8070 }
8071
8072 try {
8073 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8074 Message msg = Message.obtain();
8075 msg.what = SHOW_UID_ERROR_MSG;
8076 mHandler.sendMessage(msg);
8077 }
8078 } catch (RemoteException e) {
8079 }
8080
8081 // Start up initial activity.
8082 mBooting = true;
8083 resumeTopActivityLocked(null);
8084 }
8085 }
8086
8087 boolean makeAppCrashingLocked(ProcessRecord app,
8088 String tag, String shortMsg, String longMsg, byte[] crashData) {
8089 app.crashing = true;
8090 app.crashingReport = generateProcessError(app,
8091 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8092 startAppProblemLocked(app);
8093 app.stopFreezingAllLocked();
8094 return handleAppCrashLocked(app);
8095 }
8096
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008097 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8098 IPackageManager pm = ActivityThread.getPackageManager();
8099 try {
8100 // was an installer package name specified when this app was
8101 // installed?
8102 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8103 if (installerPackageName == null) {
8104 return null;
8105 }
8106
8107 // is there an Activity in this package that handles ACTION_APP_ERROR?
8108 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008109 intent.setPackage(installerPackageName);
8110 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008111 if (info == null || info.activityInfo == null) {
8112 return null;
8113 }
8114
8115 return new ComponentName(installerPackageName, info.activityInfo.name);
8116 } catch (RemoteException e) {
8117 // will return null and no error report will be delivered
8118 }
8119 return null;
8120 }
8121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008122 void makeAppNotRespondingLocked(ProcessRecord app,
8123 String tag, String shortMsg, String longMsg, byte[] crashData) {
8124 app.notResponding = true;
8125 app.notRespondingReport = generateProcessError(app,
8126 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8127 crashData);
8128 startAppProblemLocked(app);
8129 app.stopFreezingAllLocked();
8130 }
8131
8132 /**
8133 * Generate a process error record, suitable for attachment to a ProcessRecord.
8134 *
8135 * @param app The ProcessRecord in which the error occurred.
8136 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8137 * ActivityManager.AppErrorStateInfo
8138 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8139 * @param shortMsg Short message describing the crash.
8140 * @param longMsg Long message describing the crash.
8141 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8142 *
8143 * @return Returns a fully-formed AppErrorStateInfo record.
8144 */
8145 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8146 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8147 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8148
8149 report.condition = condition;
8150 report.processName = app.processName;
8151 report.pid = app.pid;
8152 report.uid = app.info.uid;
8153 report.tag = tag;
8154 report.shortMsg = shortMsg;
8155 report.longMsg = longMsg;
8156 report.crashData = crashData;
8157
8158 return report;
8159 }
8160
8161 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8162 boolean crashed) {
8163 synchronized (this) {
8164 app.crashing = false;
8165 app.crashingReport = null;
8166 app.notResponding = false;
8167 app.notRespondingReport = null;
8168 if (app.anrDialog == fromDialog) {
8169 app.anrDialog = null;
8170 }
8171 if (app.waitDialog == fromDialog) {
8172 app.waitDialog = null;
8173 }
8174 if (app.pid > 0 && app.pid != MY_PID) {
8175 if (crashed) {
8176 handleAppCrashLocked(app);
8177 }
8178 Log.i(ActivityManagerService.TAG, "Killing process "
8179 + app.processName
8180 + " (pid=" + app.pid + ") at user's request");
8181 Process.killProcess(app.pid);
8182 }
8183
8184 }
8185 }
8186
8187 boolean handleAppCrashLocked(ProcessRecord app) {
8188 long now = SystemClock.uptimeMillis();
8189
8190 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8191 app.info.uid);
8192 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8193 // This process loses!
8194 Log.w(TAG, "Process " + app.info.processName
8195 + " has crashed too many times: killing!");
8196 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8197 app.info.processName, app.info.uid);
8198 killServicesLocked(app, false);
8199 for (int i=mHistory.size()-1; i>=0; i--) {
8200 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8201 if (r.app == app) {
8202 if (Config.LOGD) Log.d(
8203 TAG, " Force finishing activity "
8204 + r.intent.getComponent().flattenToShortString());
8205 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8206 }
8207 }
8208 if (!app.persistent) {
8209 // We don't want to start this process again until the user
8210 // explicitly does so... but for persistent process, we really
8211 // need to keep it running. If a persistent process is actually
8212 // repeatedly crashing, then badness for everyone.
8213 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8214 app.info.processName);
8215 mBadProcesses.put(app.info.processName, app.info.uid, now);
8216 app.bad = true;
8217 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8218 app.removed = true;
8219 removeProcessLocked(app, false);
8220 return false;
8221 }
8222 }
8223
8224 // Bump up the crash count of any services currently running in the proc.
8225 if (app.services.size() != 0) {
8226 // Any services running in the application need to be placed
8227 // back in the pending list.
8228 Iterator it = app.services.iterator();
8229 while (it.hasNext()) {
8230 ServiceRecord sr = (ServiceRecord)it.next();
8231 sr.crashCount++;
8232 }
8233 }
8234
8235 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8236 return true;
8237 }
8238
8239 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008240 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008241 skipCurrentReceiverLocked(app);
8242 }
8243
8244 void skipCurrentReceiverLocked(ProcessRecord app) {
8245 boolean reschedule = false;
8246 BroadcastRecord r = app.curReceiver;
8247 if (r != null) {
8248 // The current broadcast is waiting for this app's receiver
8249 // to be finished. Looks like that's not going to happen, so
8250 // let the broadcast continue.
8251 logBroadcastReceiverDiscard(r);
8252 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8253 r.resultExtras, r.resultAbort, true);
8254 reschedule = true;
8255 }
8256 r = mPendingBroadcast;
8257 if (r != null && r.curApp == app) {
8258 if (DEBUG_BROADCAST) Log.v(TAG,
8259 "skip & discard pending app " + r);
8260 logBroadcastReceiverDiscard(r);
8261 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8262 r.resultExtras, r.resultAbort, true);
8263 reschedule = true;
8264 }
8265 if (reschedule) {
8266 scheduleBroadcastsLocked();
8267 }
8268 }
8269
8270 public int handleApplicationError(IBinder app, int flags,
8271 String tag, String shortMsg, String longMsg, byte[] crashData) {
8272 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008273 ProcessRecord r = null;
8274 synchronized (this) {
8275 if (app != null) {
8276 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8277 final int NA = apps.size();
8278 for (int ia=0; ia<NA; ia++) {
8279 ProcessRecord p = apps.valueAt(ia);
8280 if (p.thread != null && p.thread.asBinder() == app) {
8281 r = p;
8282 break;
8283 }
8284 }
8285 }
8286 }
8287
8288 if (r != null) {
8289 // The application has crashed. Send the SIGQUIT to the process so
8290 // that it can dump its state.
8291 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8292 //Log.i(TAG, "Current system threads:");
8293 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8294 }
8295
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008296 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008297 try {
8298 String name = r != null ? r.processName : null;
8299 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008300 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008301 shortMsg, longMsg, crashData)) {
8302 Log.w(TAG, "Force-killing crashed app " + name
8303 + " at watcher's request");
8304 Process.killProcess(pid);
8305 return 0;
8306 }
8307 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008308 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008309 }
8310 }
8311
8312 final long origId = Binder.clearCallingIdentity();
8313
8314 // If this process is running instrumentation, finish it.
8315 if (r != null && r.instrumentationClass != null) {
8316 Log.w(TAG, "Error in app " + r.processName
8317 + " running instrumentation " + r.instrumentationClass + ":");
8318 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8319 if (longMsg != null) Log.w(TAG, " " + longMsg);
8320 Bundle info = new Bundle();
8321 info.putString("shortMsg", shortMsg);
8322 info.putString("longMsg", longMsg);
8323 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8324 Binder.restoreCallingIdentity(origId);
8325 return 0;
8326 }
8327
8328 if (r != null) {
8329 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8330 return 0;
8331 }
8332 } else {
8333 Log.w(TAG, "Some application object " + app + " tag " + tag
8334 + " has crashed, but I don't know who it is.");
8335 Log.w(TAG, "ShortMsg:" + shortMsg);
8336 Log.w(TAG, "LongMsg:" + longMsg);
8337 Binder.restoreCallingIdentity(origId);
8338 return 0;
8339 }
8340
8341 Message msg = Message.obtain();
8342 msg.what = SHOW_ERROR_MSG;
8343 HashMap data = new HashMap();
8344 data.put("result", result);
8345 data.put("app", r);
8346 data.put("flags", flags);
8347 data.put("shortMsg", shortMsg);
8348 data.put("longMsg", longMsg);
8349 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8350 // For system processes, submit crash data to the server.
8351 data.put("crashData", crashData);
8352 }
8353 msg.obj = data;
8354 mHandler.sendMessage(msg);
8355
8356 Binder.restoreCallingIdentity(origId);
8357 }
8358
8359 int res = result.get();
8360
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008361 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008362 synchronized (this) {
8363 if (r != null) {
8364 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8365 SystemClock.uptimeMillis());
8366 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008367 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8368 appErrorIntent = createAppErrorIntentLocked(r);
8369 res = AppErrorDialog.FORCE_QUIT;
8370 }
8371 }
8372
8373 if (appErrorIntent != null) {
8374 try {
8375 mContext.startActivity(appErrorIntent);
8376 } catch (ActivityNotFoundException e) {
8377 Log.w(TAG, "bug report receiver dissappeared", e);
8378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008379 }
8380
8381 return res;
8382 }
8383
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008384 Intent createAppErrorIntentLocked(ProcessRecord r) {
8385 ApplicationErrorReport report = createAppErrorReportLocked(r);
8386 if (report == null) {
8387 return null;
8388 }
8389 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8390 result.setComponent(r.errorReportReceiver);
8391 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8392 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8393 return result;
8394 }
8395
8396 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8397 if (r.errorReportReceiver == null) {
8398 return null;
8399 }
8400
8401 if (!r.crashing && !r.notResponding) {
8402 return null;
8403 }
8404
8405 try {
8406 ApplicationErrorReport report = new ApplicationErrorReport();
8407 report.packageName = r.info.packageName;
8408 report.installerPackageName = r.errorReportReceiver.getPackageName();
8409 report.processName = r.processName;
8410
8411 if (r.crashing) {
8412 report.type = ApplicationErrorReport.TYPE_CRASH;
8413 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8414
8415 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8416 r.crashingReport.crashData);
8417 DataInputStream dataStream = new DataInputStream(byteStream);
8418 CrashData crashData = new CrashData(dataStream);
8419 ThrowableData throwData = crashData.getThrowableData();
8420
8421 report.time = crashData.getTime();
8422 report.crashInfo.stackTrace = throwData.toString();
8423
Jacek Surazskif829a782009-06-11 22:47:02 +02008424 // Extract the source of the exception, useful for report
8425 // clustering. Also extract the "deepest" non-null exception
8426 // message.
8427 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008428 while (throwData.getCause() != null) {
8429 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008430 String msg = throwData.getMessage();
8431 if (msg != null && msg.length() > 0) {
8432 exceptionMessage = msg;
8433 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008434 }
8435 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008436 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008437 report.crashInfo.exceptionClassName = throwData.getType();
8438 report.crashInfo.throwFileName = trace.getFileName();
8439 report.crashInfo.throwClassName = trace.getClassName();
8440 report.crashInfo.throwMethodName = trace.getMethodName();
8441 } else if (r.notResponding) {
8442 report.type = ApplicationErrorReport.TYPE_ANR;
8443 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8444
8445 report.anrInfo.activity = r.notRespondingReport.tag;
8446 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8447 report.anrInfo.info = r.notRespondingReport.longMsg;
8448 }
8449
8450 return report;
8451 } catch (IOException e) {
8452 // we don't send it
8453 }
8454
8455 return null;
8456 }
8457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008458 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8459 // assume our apps are happy - lazy create the list
8460 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8461
8462 synchronized (this) {
8463
8464 // iterate across all processes
8465 final int N = mLRUProcesses.size();
8466 for (int i = 0; i < N; i++) {
8467 ProcessRecord app = mLRUProcesses.get(i);
8468 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8469 // This one's in trouble, so we'll generate a report for it
8470 // crashes are higher priority (in case there's a crash *and* an anr)
8471 ActivityManager.ProcessErrorStateInfo report = null;
8472 if (app.crashing) {
8473 report = app.crashingReport;
8474 } else if (app.notResponding) {
8475 report = app.notRespondingReport;
8476 }
8477
8478 if (report != null) {
8479 if (errList == null) {
8480 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8481 }
8482 errList.add(report);
8483 } else {
8484 Log.w(TAG, "Missing app error report, app = " + app.processName +
8485 " crashing = " + app.crashing +
8486 " notResponding = " + app.notResponding);
8487 }
8488 }
8489 }
8490 }
8491
8492 return errList;
8493 }
8494
8495 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8496 // Lazy instantiation of list
8497 List<ActivityManager.RunningAppProcessInfo> runList = null;
8498 synchronized (this) {
8499 // Iterate across all processes
8500 final int N = mLRUProcesses.size();
8501 for (int i = 0; i < N; i++) {
8502 ProcessRecord app = mLRUProcesses.get(i);
8503 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8504 // Generate process state info for running application
8505 ActivityManager.RunningAppProcessInfo currApp =
8506 new ActivityManager.RunningAppProcessInfo(app.processName,
8507 app.pid, app.getPackageList());
8508 int adj = app.curAdj;
8509 if (adj >= CONTENT_PROVIDER_ADJ) {
8510 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8511 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8512 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008513 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8514 } else if (adj >= HOME_APP_ADJ) {
8515 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8516 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008517 } else if (adj >= SECONDARY_SERVER_ADJ) {
8518 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8519 } else if (adj >= VISIBLE_APP_ADJ) {
8520 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8521 } else {
8522 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8523 }
8524 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8525 // + " lru=" + currApp.lru);
8526 if (runList == null) {
8527 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8528 }
8529 runList.add(currApp);
8530 }
8531 }
8532 }
8533 return runList;
8534 }
8535
8536 @Override
8537 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8538 synchronized (this) {
8539 if (checkCallingPermission(android.Manifest.permission.DUMP)
8540 != PackageManager.PERMISSION_GRANTED) {
8541 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8542 + Binder.getCallingPid()
8543 + ", uid=" + Binder.getCallingUid()
8544 + " without permission "
8545 + android.Manifest.permission.DUMP);
8546 return;
8547 }
8548 if (args.length != 0 && "service".equals(args[0])) {
8549 dumpService(fd, pw, args);
8550 return;
8551 }
8552 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008553 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008554 pw.println(" ");
8555 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008556 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008557 if (mWaitingVisibleActivities.size() > 0) {
8558 pw.println(" ");
8559 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008560 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008561 }
8562 if (mStoppingActivities.size() > 0) {
8563 pw.println(" ");
8564 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008565 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 }
8567 if (mFinishingActivities.size() > 0) {
8568 pw.println(" ");
8569 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008570 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008571 }
8572
8573 pw.println(" ");
8574 pw.println(" mPausingActivity: " + mPausingActivity);
8575 pw.println(" mResumedActivity: " + mResumedActivity);
8576 pw.println(" mFocusedActivity: " + mFocusedActivity);
8577 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8578
8579 if (mRecentTasks.size() > 0) {
8580 pw.println(" ");
8581 pw.println("Recent tasks in Current Activity Manager State:");
8582
8583 final int N = mRecentTasks.size();
8584 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008585 TaskRecord tr = mRecentTasks.get(i);
8586 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8587 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008588 mRecentTasks.get(i).dump(pw, " ");
8589 }
8590 }
8591
8592 pw.println(" ");
8593 pw.println(" mCurTask: " + mCurTask);
8594
8595 pw.println(" ");
8596 pw.println("Processes in Current Activity Manager State:");
8597
8598 boolean needSep = false;
8599 int numPers = 0;
8600
8601 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8602 final int NA = procs.size();
8603 for (int ia=0; ia<NA; ia++) {
8604 if (!needSep) {
8605 pw.println(" All known processes:");
8606 needSep = true;
8607 }
8608 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008609 pw.print(r.persistent ? " *PERS*" : " *APP*");
8610 pw.print(" UID "); pw.print(procs.keyAt(ia));
8611 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008612 r.dump(pw, " ");
8613 if (r.persistent) {
8614 numPers++;
8615 }
8616 }
8617 }
8618
8619 if (mLRUProcesses.size() > 0) {
8620 if (needSep) pw.println(" ");
8621 needSep = true;
8622 pw.println(" Running processes (most recent first):");
8623 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008624 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008625 needSep = true;
8626 }
8627
8628 synchronized (mPidsSelfLocked) {
8629 if (mPidsSelfLocked.size() > 0) {
8630 if (needSep) pw.println(" ");
8631 needSep = true;
8632 pw.println(" PID mappings:");
8633 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008634 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8635 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008636 }
8637 }
8638 }
8639
8640 if (mForegroundProcesses.size() > 0) {
8641 if (needSep) pw.println(" ");
8642 needSep = true;
8643 pw.println(" Foreground Processes:");
8644 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008645 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8646 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008647 }
8648 }
8649
8650 if (mPersistentStartingProcesses.size() > 0) {
8651 if (needSep) pw.println(" ");
8652 needSep = true;
8653 pw.println(" Persisent processes that are starting:");
8654 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008655 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008656 }
8657
8658 if (mStartingProcesses.size() > 0) {
8659 if (needSep) pw.println(" ");
8660 needSep = true;
8661 pw.println(" Processes that are starting:");
8662 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008663 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008664 }
8665
8666 if (mRemovedProcesses.size() > 0) {
8667 if (needSep) pw.println(" ");
8668 needSep = true;
8669 pw.println(" Processes that are being removed:");
8670 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008671 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008672 }
8673
8674 if (mProcessesOnHold.size() > 0) {
8675 if (needSep) pw.println(" ");
8676 needSep = true;
8677 pw.println(" Processes that are on old until the system is ready:");
8678 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008679 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008680 }
8681
8682 if (mProcessCrashTimes.getMap().size() > 0) {
8683 if (needSep) pw.println(" ");
8684 needSep = true;
8685 pw.println(" Time since processes crashed:");
8686 long now = SystemClock.uptimeMillis();
8687 for (Map.Entry<String, SparseArray<Long>> procs
8688 : mProcessCrashTimes.getMap().entrySet()) {
8689 SparseArray<Long> uids = procs.getValue();
8690 final int N = uids.size();
8691 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008692 pw.print(" Process "); pw.print(procs.getKey());
8693 pw.print(" uid "); pw.print(uids.keyAt(i));
8694 pw.print(": last crashed ");
8695 pw.print((now-uids.valueAt(i)));
8696 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008697 }
8698 }
8699 }
8700
8701 if (mBadProcesses.getMap().size() > 0) {
8702 if (needSep) pw.println(" ");
8703 needSep = true;
8704 pw.println(" Bad processes:");
8705 for (Map.Entry<String, SparseArray<Long>> procs
8706 : mBadProcesses.getMap().entrySet()) {
8707 SparseArray<Long> uids = procs.getValue();
8708 final int N = uids.size();
8709 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008710 pw.print(" Bad process "); pw.print(procs.getKey());
8711 pw.print(" uid "); pw.print(uids.keyAt(i));
8712 pw.print(": crashed at time ");
8713 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 }
8715 }
8716 }
8717
8718 pw.println(" ");
8719 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008720 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008721 pw.println(" mConfiguration: " + mConfiguration);
8722 pw.println(" mStartRunning=" + mStartRunning
8723 + " mSystemReady=" + mSystemReady
8724 + " mBooting=" + mBooting
8725 + " mBooted=" + mBooted
8726 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008727 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 pw.println(" mGoingToSleep=" + mGoingToSleep);
8729 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8730 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8731 + " mDebugTransient=" + mDebugTransient
8732 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8733 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008734 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008735 }
8736 }
8737
8738 /**
8739 * There are three ways to call this:
8740 * - no service specified: dump all the services
8741 * - a flattened component name that matched an existing service was specified as the
8742 * first arg: dump that one service
8743 * - the first arg isn't the flattened component name of an existing service:
8744 * dump all services whose component contains the first arg as a substring
8745 */
8746 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8747 String[] newArgs;
8748 String componentNameString;
8749 ServiceRecord r;
8750 if (args.length == 1) {
8751 componentNameString = null;
8752 newArgs = EMPTY_STRING_ARRAY;
8753 r = null;
8754 } else {
8755 componentNameString = args[1];
8756 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8757 r = componentName != null ? mServices.get(componentName) : null;
8758 newArgs = new String[args.length - 2];
8759 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8760 }
8761
8762 if (r != null) {
8763 dumpService(fd, pw, r, newArgs);
8764 } else {
8765 for (ServiceRecord r1 : mServices.values()) {
8766 if (componentNameString == null
8767 || r1.name.flattenToString().contains(componentNameString)) {
8768 dumpService(fd, pw, r1, newArgs);
8769 }
8770 }
8771 }
8772 }
8773
8774 /**
8775 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8776 * there is a thread associated with the service.
8777 */
8778 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8779 pw.println(" Service " + r.name.flattenToString());
8780 if (r.app != null && r.app.thread != null) {
8781 try {
8782 // flush anything that is already in the PrintWriter since the thread is going
8783 // to write to the file descriptor directly
8784 pw.flush();
8785 r.app.thread.dumpService(fd, r, args);
8786 pw.print("\n");
8787 } catch (RemoteException e) {
8788 pw.println("got a RemoteException while dumping the service");
8789 }
8790 }
8791 }
8792
8793 void dumpBroadcasts(PrintWriter pw) {
8794 synchronized (this) {
8795 if (checkCallingPermission(android.Manifest.permission.DUMP)
8796 != PackageManager.PERMISSION_GRANTED) {
8797 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8798 + Binder.getCallingPid()
8799 + ", uid=" + Binder.getCallingUid()
8800 + " without permission "
8801 + android.Manifest.permission.DUMP);
8802 return;
8803 }
8804 pw.println("Broadcasts in Current Activity Manager State:");
8805
8806 if (mRegisteredReceivers.size() > 0) {
8807 pw.println(" ");
8808 pw.println(" Registered Receivers:");
8809 Iterator it = mRegisteredReceivers.values().iterator();
8810 while (it.hasNext()) {
8811 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008812 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008813 r.dump(pw, " ");
8814 }
8815 }
8816
8817 pw.println(" ");
8818 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008819 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008820
8821 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8822 || mPendingBroadcast != null) {
8823 if (mParallelBroadcasts.size() > 0) {
8824 pw.println(" ");
8825 pw.println(" Active broadcasts:");
8826 }
8827 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8828 pw.println(" Broadcast #" + i + ":");
8829 mParallelBroadcasts.get(i).dump(pw, " ");
8830 }
8831 if (mOrderedBroadcasts.size() > 0) {
8832 pw.println(" ");
8833 pw.println(" Active serialized broadcasts:");
8834 }
8835 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8836 pw.println(" Serialized Broadcast #" + i + ":");
8837 mOrderedBroadcasts.get(i).dump(pw, " ");
8838 }
8839 pw.println(" ");
8840 pw.println(" Pending broadcast:");
8841 if (mPendingBroadcast != null) {
8842 mPendingBroadcast.dump(pw, " ");
8843 } else {
8844 pw.println(" (null)");
8845 }
8846 }
8847
8848 pw.println(" ");
8849 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8850 if (mStickyBroadcasts != null) {
8851 pw.println(" ");
8852 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008853 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008854 for (Map.Entry<String, ArrayList<Intent>> ent
8855 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008856 pw.print(" * Sticky action "); pw.print(ent.getKey());
8857 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008858 ArrayList<Intent> intents = ent.getValue();
8859 final int N = intents.size();
8860 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008861 sb.setLength(0);
8862 sb.append(" Intent: ");
8863 intents.get(i).toShortString(sb, true, false);
8864 pw.println(sb.toString());
8865 Bundle bundle = intents.get(i).getExtras();
8866 if (bundle != null) {
8867 pw.print(" ");
8868 pw.println(bundle.toString());
8869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008870 }
8871 }
8872 }
8873
8874 pw.println(" ");
8875 pw.println(" mHandler:");
8876 mHandler.dump(new PrintWriterPrinter(pw), " ");
8877 }
8878 }
8879
8880 void dumpServices(PrintWriter pw) {
8881 synchronized (this) {
8882 if (checkCallingPermission(android.Manifest.permission.DUMP)
8883 != PackageManager.PERMISSION_GRANTED) {
8884 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8885 + Binder.getCallingPid()
8886 + ", uid=" + Binder.getCallingUid()
8887 + " without permission "
8888 + android.Manifest.permission.DUMP);
8889 return;
8890 }
8891 pw.println("Services in Current Activity Manager State:");
8892
8893 boolean needSep = false;
8894
8895 if (mServices.size() > 0) {
8896 pw.println(" Active services:");
8897 Iterator<ServiceRecord> it = mServices.values().iterator();
8898 while (it.hasNext()) {
8899 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008900 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008901 r.dump(pw, " ");
8902 }
8903 needSep = true;
8904 }
8905
8906 if (mPendingServices.size() > 0) {
8907 if (needSep) pw.println(" ");
8908 pw.println(" Pending services:");
8909 for (int i=0; i<mPendingServices.size(); i++) {
8910 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008911 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008912 r.dump(pw, " ");
8913 }
8914 needSep = true;
8915 }
8916
8917 if (mRestartingServices.size() > 0) {
8918 if (needSep) pw.println(" ");
8919 pw.println(" Restarting services:");
8920 for (int i=0; i<mRestartingServices.size(); i++) {
8921 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008922 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008923 r.dump(pw, " ");
8924 }
8925 needSep = true;
8926 }
8927
8928 if (mStoppingServices.size() > 0) {
8929 if (needSep) pw.println(" ");
8930 pw.println(" Stopping services:");
8931 for (int i=0; i<mStoppingServices.size(); i++) {
8932 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008933 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 r.dump(pw, " ");
8935 }
8936 needSep = true;
8937 }
8938
8939 if (mServiceConnections.size() > 0) {
8940 if (needSep) pw.println(" ");
8941 pw.println(" Connection bindings to services:");
8942 Iterator<ConnectionRecord> it
8943 = mServiceConnections.values().iterator();
8944 while (it.hasNext()) {
8945 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008946 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008947 r.dump(pw, " ");
8948 }
8949 }
8950 }
8951 }
8952
8953 void dumpProviders(PrintWriter pw) {
8954 synchronized (this) {
8955 if (checkCallingPermission(android.Manifest.permission.DUMP)
8956 != PackageManager.PERMISSION_GRANTED) {
8957 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8958 + Binder.getCallingPid()
8959 + ", uid=" + Binder.getCallingUid()
8960 + " without permission "
8961 + android.Manifest.permission.DUMP);
8962 return;
8963 }
8964
8965 pw.println("Content Providers in Current Activity Manager State:");
8966
8967 boolean needSep = false;
8968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008969 if (mProvidersByClass.size() > 0) {
8970 if (needSep) pw.println(" ");
8971 pw.println(" Published content providers (by class):");
8972 Iterator it = mProvidersByClass.entrySet().iterator();
8973 while (it.hasNext()) {
8974 Map.Entry e = (Map.Entry)it.next();
8975 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008976 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008977 r.dump(pw, " ");
8978 }
8979 needSep = true;
8980 }
8981
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008982 if (mProvidersByName.size() > 0) {
8983 pw.println(" ");
8984 pw.println(" Authority to provider mappings:");
8985 Iterator it = mProvidersByName.entrySet().iterator();
8986 while (it.hasNext()) {
8987 Map.Entry e = (Map.Entry)it.next();
8988 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8989 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8990 pw.println(r);
8991 }
8992 needSep = true;
8993 }
8994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008995 if (mLaunchingProviders.size() > 0) {
8996 if (needSep) pw.println(" ");
8997 pw.println(" Launching content providers:");
8998 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008999 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9000 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009001 }
9002 needSep = true;
9003 }
9004
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009005 if (mGrantedUriPermissions.size() > 0) {
9006 pw.println();
9007 pw.println("Granted Uri Permissions:");
9008 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9009 int uid = mGrantedUriPermissions.keyAt(i);
9010 HashMap<Uri, UriPermission> perms
9011 = mGrantedUriPermissions.valueAt(i);
9012 pw.print(" * UID "); pw.print(uid);
9013 pw.println(" holds:");
9014 for (UriPermission perm : perms.values()) {
9015 pw.print(" "); pw.println(perm);
9016 perm.dump(pw, " ");
9017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 }
9019 }
9020 }
9021 }
9022
9023 void dumpSenders(PrintWriter pw) {
9024 synchronized (this) {
9025 if (checkCallingPermission(android.Manifest.permission.DUMP)
9026 != PackageManager.PERMISSION_GRANTED) {
9027 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9028 + Binder.getCallingPid()
9029 + ", uid=" + Binder.getCallingUid()
9030 + " without permission "
9031 + android.Manifest.permission.DUMP);
9032 return;
9033 }
9034
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009035 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036
9037 if (this.mIntentSenderRecords.size() > 0) {
9038 Iterator<WeakReference<PendingIntentRecord>> it
9039 = mIntentSenderRecords.values().iterator();
9040 while (it.hasNext()) {
9041 WeakReference<PendingIntentRecord> ref = it.next();
9042 PendingIntentRecord rec = ref != null ? ref.get(): null;
9043 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009044 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009045 rec.dump(pw, " ");
9046 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009047 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009048 }
9049 }
9050 }
9051 }
9052 }
9053
9054 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009055 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 TaskRecord lastTask = null;
9057 for (int i=list.size()-1; i>=0; i--) {
9058 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009059 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009060 if (lastTask != r.task) {
9061 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 pw.print(prefix);
9063 pw.print(full ? "* " : " ");
9064 pw.println(lastTask);
9065 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009066 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009069 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9070 pw.print(" #"); pw.print(i); pw.print(": ");
9071 pw.println(r);
9072 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009073 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009075 }
9076 }
9077
9078 private static final int dumpProcessList(PrintWriter pw, List list,
9079 String prefix, String normalLabel, String persistentLabel,
9080 boolean inclOomAdj) {
9081 int numPers = 0;
9082 for (int i=list.size()-1; i>=0; i--) {
9083 ProcessRecord r = (ProcessRecord)list.get(i);
9084 if (false) {
9085 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9086 + " #" + i + ":");
9087 r.dump(pw, prefix + " ");
9088 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009089 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009090 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009091 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009092 } else {
9093 pw.println(String.format("%s%s #%2d: %s",
9094 prefix, (r.persistent ? persistentLabel : normalLabel),
9095 i, r.toString()));
9096 }
9097 if (r.persistent) {
9098 numPers++;
9099 }
9100 }
9101 return numPers;
9102 }
9103
9104 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9105 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009106 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009107 long uptime = SystemClock.uptimeMillis();
9108 long realtime = SystemClock.elapsedRealtime();
9109
9110 if (isCheckinRequest) {
9111 // short checkin version
9112 pw.println(uptime + "," + realtime);
9113 pw.flush();
9114 } else {
9115 pw.println("Applications Memory Usage (kB):");
9116 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9117 }
9118 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9119 ProcessRecord r = (ProcessRecord)list.get(i);
9120 if (r.thread != null) {
9121 if (!isCheckinRequest) {
9122 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9123 pw.flush();
9124 }
9125 try {
9126 r.thread.asBinder().dump(fd, args);
9127 } catch (RemoteException e) {
9128 if (!isCheckinRequest) {
9129 pw.println("Got RemoteException!");
9130 pw.flush();
9131 }
9132 }
9133 }
9134 }
9135 }
9136
9137 /**
9138 * Searches array of arguments for the specified string
9139 * @param args array of argument strings
9140 * @param value value to search for
9141 * @return true if the value is contained in the array
9142 */
9143 private static boolean scanArgs(String[] args, String value) {
9144 if (args != null) {
9145 for (String arg : args) {
9146 if (value.equals(arg)) {
9147 return true;
9148 }
9149 }
9150 }
9151 return false;
9152 }
9153
Dianne Hackborn75b03852009-06-12 15:43:26 -07009154 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009155 int count = mHistory.size();
9156
9157 // convert the token to an entry in the history.
9158 HistoryRecord r = null;
9159 int index = -1;
9160 for (int i=count-1; i>=0; i--) {
9161 Object o = mHistory.get(i);
9162 if (o == token) {
9163 r = (HistoryRecord)o;
9164 index = i;
9165 break;
9166 }
9167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009168
9169 return index;
9170 }
9171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009172 private final void killServicesLocked(ProcessRecord app,
9173 boolean allowRestart) {
9174 // Report disconnected services.
9175 if (false) {
9176 // XXX we are letting the client link to the service for
9177 // death notifications.
9178 if (app.services.size() > 0) {
9179 Iterator it = app.services.iterator();
9180 while (it.hasNext()) {
9181 ServiceRecord r = (ServiceRecord)it.next();
9182 if (r.connections.size() > 0) {
9183 Iterator<ConnectionRecord> jt
9184 = r.connections.values().iterator();
9185 while (jt.hasNext()) {
9186 ConnectionRecord c = jt.next();
9187 if (c.binding.client != app) {
9188 try {
9189 //c.conn.connected(r.className, null);
9190 } catch (Exception e) {
9191 // todo: this should be asynchronous!
9192 Log.w(TAG, "Exception thrown disconnected servce "
9193 + r.shortName
9194 + " from app " + app.processName, e);
9195 }
9196 }
9197 }
9198 }
9199 }
9200 }
9201 }
9202
9203 // Clean up any connections this application has to other services.
9204 if (app.connections.size() > 0) {
9205 Iterator<ConnectionRecord> it = app.connections.iterator();
9206 while (it.hasNext()) {
9207 ConnectionRecord r = it.next();
9208 removeConnectionLocked(r, app, null);
9209 }
9210 }
9211 app.connections.clear();
9212
9213 if (app.services.size() != 0) {
9214 // Any services running in the application need to be placed
9215 // back in the pending list.
9216 Iterator it = app.services.iterator();
9217 while (it.hasNext()) {
9218 ServiceRecord sr = (ServiceRecord)it.next();
9219 synchronized (sr.stats.getBatteryStats()) {
9220 sr.stats.stopLaunchedLocked();
9221 }
9222 sr.app = null;
9223 sr.executeNesting = 0;
9224 mStoppingServices.remove(sr);
9225 if (sr.bindings.size() > 0) {
9226 Iterator<IntentBindRecord> bindings
9227 = sr.bindings.values().iterator();
9228 while (bindings.hasNext()) {
9229 IntentBindRecord b = bindings.next();
9230 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9231 + ": shouldUnbind=" + b.hasBound);
9232 b.binder = null;
9233 b.requested = b.received = b.hasBound = false;
9234 }
9235 }
9236
9237 if (sr.crashCount >= 2) {
9238 Log.w(TAG, "Service crashed " + sr.crashCount
9239 + " times, stopping: " + sr);
9240 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9241 sr.crashCount, sr.shortName, app.pid);
9242 bringDownServiceLocked(sr, true);
9243 } else if (!allowRestart) {
9244 bringDownServiceLocked(sr, true);
9245 } else {
9246 scheduleServiceRestartLocked(sr);
9247 }
9248 }
9249
9250 if (!allowRestart) {
9251 app.services.clear();
9252 }
9253 }
9254
9255 app.executingServices.clear();
9256 }
9257
9258 private final void removeDyingProviderLocked(ProcessRecord proc,
9259 ContentProviderRecord cpr) {
9260 synchronized (cpr) {
9261 cpr.launchingApp = null;
9262 cpr.notifyAll();
9263 }
9264
9265 mProvidersByClass.remove(cpr.info.name);
9266 String names[] = cpr.info.authority.split(";");
9267 for (int j = 0; j < names.length; j++) {
9268 mProvidersByName.remove(names[j]);
9269 }
9270
9271 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9272 while (cit.hasNext()) {
9273 ProcessRecord capp = cit.next();
9274 if (!capp.persistent && capp.thread != null
9275 && capp.pid != 0
9276 && capp.pid != MY_PID) {
9277 Log.i(TAG, "Killing app " + capp.processName
9278 + " (pid " + capp.pid
9279 + ") because provider " + cpr.info.name
9280 + " is in dying process " + proc.processName);
9281 Process.killProcess(capp.pid);
9282 }
9283 }
9284
9285 mLaunchingProviders.remove(cpr);
9286 }
9287
9288 /**
9289 * Main code for cleaning up a process when it has gone away. This is
9290 * called both as a result of the process dying, or directly when stopping
9291 * a process when running in single process mode.
9292 */
9293 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9294 boolean restarting, int index) {
9295 if (index >= 0) {
9296 mLRUProcesses.remove(index);
9297 }
9298
9299 // Dismiss any open dialogs.
9300 if (app.crashDialog != null) {
9301 app.crashDialog.dismiss();
9302 app.crashDialog = null;
9303 }
9304 if (app.anrDialog != null) {
9305 app.anrDialog.dismiss();
9306 app.anrDialog = null;
9307 }
9308 if (app.waitDialog != null) {
9309 app.waitDialog.dismiss();
9310 app.waitDialog = null;
9311 }
9312
9313 app.crashing = false;
9314 app.notResponding = false;
9315
9316 app.resetPackageList();
9317 app.thread = null;
9318 app.forcingToForeground = null;
9319 app.foregroundServices = false;
9320
9321 killServicesLocked(app, true);
9322
9323 boolean restart = false;
9324
9325 int NL = mLaunchingProviders.size();
9326
9327 // Remove published content providers.
9328 if (!app.pubProviders.isEmpty()) {
9329 Iterator it = app.pubProviders.values().iterator();
9330 while (it.hasNext()) {
9331 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9332 cpr.provider = null;
9333 cpr.app = null;
9334
9335 // See if someone is waiting for this provider... in which
9336 // case we don't remove it, but just let it restart.
9337 int i = 0;
9338 if (!app.bad) {
9339 for (; i<NL; i++) {
9340 if (mLaunchingProviders.get(i) == cpr) {
9341 restart = true;
9342 break;
9343 }
9344 }
9345 } else {
9346 i = NL;
9347 }
9348
9349 if (i >= NL) {
9350 removeDyingProviderLocked(app, cpr);
9351 NL = mLaunchingProviders.size();
9352 }
9353 }
9354 app.pubProviders.clear();
9355 }
9356
9357 // Look through the content providers we are waiting to have launched,
9358 // and if any run in this process then either schedule a restart of
9359 // the process or kill the client waiting for it if this process has
9360 // gone bad.
9361 for (int i=0; i<NL; i++) {
9362 ContentProviderRecord cpr = (ContentProviderRecord)
9363 mLaunchingProviders.get(i);
9364 if (cpr.launchingApp == app) {
9365 if (!app.bad) {
9366 restart = true;
9367 } else {
9368 removeDyingProviderLocked(app, cpr);
9369 NL = mLaunchingProviders.size();
9370 }
9371 }
9372 }
9373
9374 // Unregister from connected content providers.
9375 if (!app.conProviders.isEmpty()) {
9376 Iterator it = app.conProviders.iterator();
9377 while (it.hasNext()) {
9378 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9379 cpr.clients.remove(app);
9380 }
9381 app.conProviders.clear();
9382 }
9383
9384 skipCurrentReceiverLocked(app);
9385
9386 // Unregister any receivers.
9387 if (app.receivers.size() > 0) {
9388 Iterator<ReceiverList> it = app.receivers.iterator();
9389 while (it.hasNext()) {
9390 removeReceiverLocked(it.next());
9391 }
9392 app.receivers.clear();
9393 }
9394
Christopher Tate181fafa2009-05-14 11:12:14 -07009395 // If the app is undergoing backup, tell the backup manager about it
9396 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9397 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9398 try {
9399 IBackupManager bm = IBackupManager.Stub.asInterface(
9400 ServiceManager.getService(Context.BACKUP_SERVICE));
9401 bm.agentDisconnected(app.info.packageName);
9402 } catch (RemoteException e) {
9403 // can't happen; backup manager is local
9404 }
9405 }
9406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009407 // If the caller is restarting this app, then leave it in its
9408 // current lists and let the caller take care of it.
9409 if (restarting) {
9410 return;
9411 }
9412
9413 if (!app.persistent) {
9414 if (DEBUG_PROCESSES) Log.v(TAG,
9415 "Removing non-persistent process during cleanup: " + app);
9416 mProcessNames.remove(app.processName, app.info.uid);
9417 } else if (!app.removed) {
9418 // This app is persistent, so we need to keep its record around.
9419 // If it is not already on the pending app list, add it there
9420 // and start a new process for it.
9421 app.thread = null;
9422 app.forcingToForeground = null;
9423 app.foregroundServices = false;
9424 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9425 mPersistentStartingProcesses.add(app);
9426 restart = true;
9427 }
9428 }
9429 mProcessesOnHold.remove(app);
9430
The Android Open Source Project4df24232009-03-05 14:34:35 -08009431 if (app == mHomeProcess) {
9432 mHomeProcess = null;
9433 }
9434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009435 if (restart) {
9436 // We have components that still need to be running in the
9437 // process, so re-launch it.
9438 mProcessNames.put(app.processName, app.info.uid, app);
9439 startProcessLocked(app, "restart", app.processName);
9440 } else if (app.pid > 0 && app.pid != MY_PID) {
9441 // Goodbye!
9442 synchronized (mPidsSelfLocked) {
9443 mPidsSelfLocked.remove(app.pid);
9444 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9445 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009446 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009447 }
9448 }
9449
9450 // =========================================================
9451 // SERVICES
9452 // =========================================================
9453
9454 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9455 ActivityManager.RunningServiceInfo info =
9456 new ActivityManager.RunningServiceInfo();
9457 info.service = r.name;
9458 if (r.app != null) {
9459 info.pid = r.app.pid;
9460 }
9461 info.process = r.processName;
9462 info.foreground = r.isForeground;
9463 info.activeSince = r.createTime;
9464 info.started = r.startRequested;
9465 info.clientCount = r.connections.size();
9466 info.crashCount = r.crashCount;
9467 info.lastActivityTime = r.lastActivity;
9468 return info;
9469 }
9470
9471 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9472 int flags) {
9473 synchronized (this) {
9474 ArrayList<ActivityManager.RunningServiceInfo> res
9475 = new ArrayList<ActivityManager.RunningServiceInfo>();
9476
9477 if (mServices.size() > 0) {
9478 Iterator<ServiceRecord> it = mServices.values().iterator();
9479 while (it.hasNext() && res.size() < maxNum) {
9480 res.add(makeRunningServiceInfoLocked(it.next()));
9481 }
9482 }
9483
9484 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9485 ServiceRecord r = mRestartingServices.get(i);
9486 ActivityManager.RunningServiceInfo info =
9487 makeRunningServiceInfoLocked(r);
9488 info.restarting = r.nextRestartTime;
9489 res.add(info);
9490 }
9491
9492 return res;
9493 }
9494 }
9495
9496 private final ServiceRecord findServiceLocked(ComponentName name,
9497 IBinder token) {
9498 ServiceRecord r = mServices.get(name);
9499 return r == token ? r : null;
9500 }
9501
9502 private final class ServiceLookupResult {
9503 final ServiceRecord record;
9504 final String permission;
9505
9506 ServiceLookupResult(ServiceRecord _record, String _permission) {
9507 record = _record;
9508 permission = _permission;
9509 }
9510 };
9511
9512 private ServiceLookupResult findServiceLocked(Intent service,
9513 String resolvedType) {
9514 ServiceRecord r = null;
9515 if (service.getComponent() != null) {
9516 r = mServices.get(service.getComponent());
9517 }
9518 if (r == null) {
9519 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9520 r = mServicesByIntent.get(filter);
9521 }
9522
9523 if (r == null) {
9524 try {
9525 ResolveInfo rInfo =
9526 ActivityThread.getPackageManager().resolveService(
9527 service, resolvedType, 0);
9528 ServiceInfo sInfo =
9529 rInfo != null ? rInfo.serviceInfo : null;
9530 if (sInfo == null) {
9531 return null;
9532 }
9533
9534 ComponentName name = new ComponentName(
9535 sInfo.applicationInfo.packageName, sInfo.name);
9536 r = mServices.get(name);
9537 } catch (RemoteException ex) {
9538 // pm is in same process, this will never happen.
9539 }
9540 }
9541 if (r != null) {
9542 int callingPid = Binder.getCallingPid();
9543 int callingUid = Binder.getCallingUid();
9544 if (checkComponentPermission(r.permission,
9545 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9546 != PackageManager.PERMISSION_GRANTED) {
9547 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9548 + " from pid=" + callingPid
9549 + ", uid=" + callingUid
9550 + " requires " + r.permission);
9551 return new ServiceLookupResult(null, r.permission);
9552 }
9553 return new ServiceLookupResult(r, null);
9554 }
9555 return null;
9556 }
9557
9558 private class ServiceRestarter implements Runnable {
9559 private ServiceRecord mService;
9560
9561 void setService(ServiceRecord service) {
9562 mService = service;
9563 }
9564
9565 public void run() {
9566 synchronized(ActivityManagerService.this) {
9567 performServiceRestartLocked(mService);
9568 }
9569 }
9570 }
9571
9572 private ServiceLookupResult retrieveServiceLocked(Intent service,
9573 String resolvedType, int callingPid, int callingUid) {
9574 ServiceRecord r = null;
9575 if (service.getComponent() != null) {
9576 r = mServices.get(service.getComponent());
9577 }
9578 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9579 r = mServicesByIntent.get(filter);
9580 if (r == null) {
9581 try {
9582 ResolveInfo rInfo =
9583 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009584 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009585 ServiceInfo sInfo =
9586 rInfo != null ? rInfo.serviceInfo : null;
9587 if (sInfo == null) {
9588 Log.w(TAG, "Unable to start service " + service +
9589 ": not found");
9590 return null;
9591 }
9592
9593 ComponentName name = new ComponentName(
9594 sInfo.applicationInfo.packageName, sInfo.name);
9595 r = mServices.get(name);
9596 if (r == null) {
9597 filter = new Intent.FilterComparison(service.cloneFilter());
9598 ServiceRestarter res = new ServiceRestarter();
9599 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9600 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9601 synchronized (stats) {
9602 ss = stats.getServiceStatsLocked(
9603 sInfo.applicationInfo.uid, sInfo.packageName,
9604 sInfo.name);
9605 }
9606 r = new ServiceRecord(ss, name, filter, sInfo, res);
9607 res.setService(r);
9608 mServices.put(name, r);
9609 mServicesByIntent.put(filter, r);
9610
9611 // Make sure this component isn't in the pending list.
9612 int N = mPendingServices.size();
9613 for (int i=0; i<N; i++) {
9614 ServiceRecord pr = mPendingServices.get(i);
9615 if (pr.name.equals(name)) {
9616 mPendingServices.remove(i);
9617 i--;
9618 N--;
9619 }
9620 }
9621 }
9622 } catch (RemoteException ex) {
9623 // pm is in same process, this will never happen.
9624 }
9625 }
9626 if (r != null) {
9627 if (checkComponentPermission(r.permission,
9628 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9629 != PackageManager.PERMISSION_GRANTED) {
9630 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9631 + " from pid=" + Binder.getCallingPid()
9632 + ", uid=" + Binder.getCallingUid()
9633 + " requires " + r.permission);
9634 return new ServiceLookupResult(null, r.permission);
9635 }
9636 return new ServiceLookupResult(r, null);
9637 }
9638 return null;
9639 }
9640
9641 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9642 long now = SystemClock.uptimeMillis();
9643 if (r.executeNesting == 0 && r.app != null) {
9644 if (r.app.executingServices.size() == 0) {
9645 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9646 msg.obj = r.app;
9647 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9648 }
9649 r.app.executingServices.add(r);
9650 }
9651 r.executeNesting++;
9652 r.executingStart = now;
9653 }
9654
9655 private final void sendServiceArgsLocked(ServiceRecord r,
9656 boolean oomAdjusted) {
9657 final int N = r.startArgs.size();
9658 if (N == 0) {
9659 return;
9660 }
9661
9662 final int BASEID = r.lastStartId - N + 1;
9663 int i = 0;
9664 while (i < N) {
9665 try {
9666 Intent args = r.startArgs.get(i);
9667 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9668 + r.name + " " + r.intent + " args=" + args);
9669 bumpServiceExecutingLocked(r);
9670 if (!oomAdjusted) {
9671 oomAdjusted = true;
9672 updateOomAdjLocked(r.app);
9673 }
9674 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9675 i++;
9676 } catch (Exception e) {
9677 break;
9678 }
9679 }
9680 if (i == N) {
9681 r.startArgs.clear();
9682 } else {
9683 while (i > 0) {
9684 r.startArgs.remove(0);
9685 i--;
9686 }
9687 }
9688 }
9689
9690 private final boolean requestServiceBindingLocked(ServiceRecord r,
9691 IntentBindRecord i, boolean rebind) {
9692 if (r.app == null || r.app.thread == null) {
9693 // If service is not currently running, can't yet bind.
9694 return false;
9695 }
9696 if ((!i.requested || rebind) && i.apps.size() > 0) {
9697 try {
9698 bumpServiceExecutingLocked(r);
9699 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9700 + ": shouldUnbind=" + i.hasBound);
9701 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9702 if (!rebind) {
9703 i.requested = true;
9704 }
9705 i.hasBound = true;
9706 i.doRebind = false;
9707 } catch (RemoteException e) {
9708 return false;
9709 }
9710 }
9711 return true;
9712 }
9713
9714 private final void requestServiceBindingsLocked(ServiceRecord r) {
9715 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9716 while (bindings.hasNext()) {
9717 IntentBindRecord i = bindings.next();
9718 if (!requestServiceBindingLocked(r, i, false)) {
9719 break;
9720 }
9721 }
9722 }
9723
9724 private final void realStartServiceLocked(ServiceRecord r,
9725 ProcessRecord app) throws RemoteException {
9726 if (app.thread == null) {
9727 throw new RemoteException();
9728 }
9729
9730 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009731 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009732
9733 app.services.add(r);
9734 bumpServiceExecutingLocked(r);
9735 updateLRUListLocked(app, true);
9736
9737 boolean created = false;
9738 try {
9739 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9740 + r.name + " " + r.intent);
9741 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9742 System.identityHashCode(r), r.shortName,
9743 r.intent.getIntent().toString(), r.app.pid);
9744 synchronized (r.stats.getBatteryStats()) {
9745 r.stats.startLaunchedLocked();
9746 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009747 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009748 app.thread.scheduleCreateService(r, r.serviceInfo);
9749 created = true;
9750 } finally {
9751 if (!created) {
9752 app.services.remove(r);
9753 scheduleServiceRestartLocked(r);
9754 }
9755 }
9756
9757 requestServiceBindingsLocked(r);
9758 sendServiceArgsLocked(r, true);
9759 }
9760
9761 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9762 r.totalRestartCount++;
9763 if (r.restartDelay == 0) {
9764 r.restartCount++;
9765 r.restartDelay = SERVICE_RESTART_DURATION;
9766 } else {
9767 // If it has been a "reasonably long time" since the service
9768 // was started, then reset our restart duration back to
9769 // the beginning, so we don't infinitely increase the duration
9770 // on a service that just occasionally gets killed (which is
9771 // a normal case, due to process being killed to reclaim memory).
9772 long now = SystemClock.uptimeMillis();
9773 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9774 r.restartCount = 1;
9775 r.restartDelay = SERVICE_RESTART_DURATION;
9776 } else {
9777 r.restartDelay *= 2;
9778 }
9779 }
9780 if (!mRestartingServices.contains(r)) {
9781 mRestartingServices.add(r);
9782 }
9783 mHandler.removeCallbacks(r.restarter);
9784 mHandler.postDelayed(r.restarter, r.restartDelay);
9785 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9786 Log.w(TAG, "Scheduling restart of crashed service "
9787 + r.shortName + " in " + r.restartDelay + "ms");
9788 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9789 r.shortName, r.restartDelay);
9790
9791 Message msg = Message.obtain();
9792 msg.what = SERVICE_ERROR_MSG;
9793 msg.obj = r;
9794 mHandler.sendMessage(msg);
9795 }
9796
9797 final void performServiceRestartLocked(ServiceRecord r) {
9798 if (!mRestartingServices.contains(r)) {
9799 return;
9800 }
9801 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9802 }
9803
9804 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9805 if (r.restartDelay == 0) {
9806 return false;
9807 }
9808 r.resetRestartCounter();
9809 mRestartingServices.remove(r);
9810 mHandler.removeCallbacks(r.restarter);
9811 return true;
9812 }
9813
9814 private final boolean bringUpServiceLocked(ServiceRecord r,
9815 int intentFlags, boolean whileRestarting) {
9816 //Log.i(TAG, "Bring up service:");
9817 //r.dump(" ");
9818
9819 if (r.app != null) {
9820 sendServiceArgsLocked(r, false);
9821 return true;
9822 }
9823
9824 if (!whileRestarting && r.restartDelay > 0) {
9825 // If waiting for a restart, then do nothing.
9826 return true;
9827 }
9828
9829 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9830 + " " + r.intent);
9831
9832 final String appName = r.processName;
9833 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9834 if (app != null && app.thread != null) {
9835 try {
9836 realStartServiceLocked(r, app);
9837 return true;
9838 } catch (RemoteException e) {
9839 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9840 }
9841
9842 // If a dead object exception was thrown -- fall through to
9843 // restart the application.
9844 }
9845
9846 if (!mPendingServices.contains(r)) {
9847 // Not running -- get it started, and enqueue this service record
9848 // to be executed when the app comes up.
9849 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9850 "service", r.name) == null) {
9851 Log.w(TAG, "Unable to launch app "
9852 + r.appInfo.packageName + "/"
9853 + r.appInfo.uid + " for service "
9854 + r.intent.getIntent() + ": process is bad");
9855 bringDownServiceLocked(r, true);
9856 return false;
9857 }
9858 mPendingServices.add(r);
9859 }
9860 return true;
9861 }
9862
9863 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9864 //Log.i(TAG, "Bring down service:");
9865 //r.dump(" ");
9866
9867 // Does it still need to run?
9868 if (!force && r.startRequested) {
9869 return;
9870 }
9871 if (r.connections.size() > 0) {
9872 if (!force) {
9873 // XXX should probably keep a count of the number of auto-create
9874 // connections directly in the service.
9875 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9876 while (it.hasNext()) {
9877 ConnectionRecord cr = it.next();
9878 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9879 return;
9880 }
9881 }
9882 }
9883
9884 // Report to all of the connections that the service is no longer
9885 // available.
9886 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9887 while (it.hasNext()) {
9888 ConnectionRecord c = it.next();
9889 try {
9890 // todo: shouldn't be a synchronous call!
9891 c.conn.connected(r.name, null);
9892 } catch (Exception e) {
9893 Log.w(TAG, "Failure disconnecting service " + r.name +
9894 " to connection " + c.conn.asBinder() +
9895 " (in " + c.binding.client.processName + ")", e);
9896 }
9897 }
9898 }
9899
9900 // Tell the service that it has been unbound.
9901 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9902 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9903 while (it.hasNext()) {
9904 IntentBindRecord ibr = it.next();
9905 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9906 + ": hasBound=" + ibr.hasBound);
9907 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9908 try {
9909 bumpServiceExecutingLocked(r);
9910 updateOomAdjLocked(r.app);
9911 ibr.hasBound = false;
9912 r.app.thread.scheduleUnbindService(r,
9913 ibr.intent.getIntent());
9914 } catch (Exception e) {
9915 Log.w(TAG, "Exception when unbinding service "
9916 + r.shortName, e);
9917 serviceDoneExecutingLocked(r, true);
9918 }
9919 }
9920 }
9921 }
9922
9923 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9924 + " " + r.intent);
9925 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9926 System.identityHashCode(r), r.shortName,
9927 (r.app != null) ? r.app.pid : -1);
9928
9929 mServices.remove(r.name);
9930 mServicesByIntent.remove(r.intent);
9931 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9932 r.totalRestartCount = 0;
9933 unscheduleServiceRestartLocked(r);
9934
9935 // Also make sure it is not on the pending list.
9936 int N = mPendingServices.size();
9937 for (int i=0; i<N; i++) {
9938 if (mPendingServices.get(i) == r) {
9939 mPendingServices.remove(i);
9940 if (DEBUG_SERVICE) Log.v(
9941 TAG, "Removed pending service: " + r.shortName);
9942 i--;
9943 N--;
9944 }
9945 }
9946
9947 if (r.app != null) {
9948 synchronized (r.stats.getBatteryStats()) {
9949 r.stats.stopLaunchedLocked();
9950 }
9951 r.app.services.remove(r);
9952 if (r.app.thread != null) {
9953 updateServiceForegroundLocked(r.app, false);
9954 try {
9955 Log.i(TAG, "Stopping service: " + r.shortName);
9956 bumpServiceExecutingLocked(r);
9957 mStoppingServices.add(r);
9958 updateOomAdjLocked(r.app);
9959 r.app.thread.scheduleStopService(r);
9960 } catch (Exception e) {
9961 Log.w(TAG, "Exception when stopping service "
9962 + r.shortName, e);
9963 serviceDoneExecutingLocked(r, true);
9964 }
9965 } else {
9966 if (DEBUG_SERVICE) Log.v(
9967 TAG, "Removed service that has no process: " + r.shortName);
9968 }
9969 } else {
9970 if (DEBUG_SERVICE) Log.v(
9971 TAG, "Removed service that is not running: " + r.shortName);
9972 }
9973 }
9974
9975 ComponentName startServiceLocked(IApplicationThread caller,
9976 Intent service, String resolvedType,
9977 int callingPid, int callingUid) {
9978 synchronized(this) {
9979 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9980 + " type=" + resolvedType + " args=" + service.getExtras());
9981
9982 if (caller != null) {
9983 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9984 if (callerApp == null) {
9985 throw new SecurityException(
9986 "Unable to find app for caller " + caller
9987 + " (pid=" + Binder.getCallingPid()
9988 + ") when starting service " + service);
9989 }
9990 }
9991
9992 ServiceLookupResult res =
9993 retrieveServiceLocked(service, resolvedType,
9994 callingPid, callingUid);
9995 if (res == null) {
9996 return null;
9997 }
9998 if (res.record == null) {
9999 return new ComponentName("!", res.permission != null
10000 ? res.permission : "private to package");
10001 }
10002 ServiceRecord r = res.record;
10003 if (unscheduleServiceRestartLocked(r)) {
10004 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10005 + r.shortName);
10006 }
10007 r.startRequested = true;
10008 r.startArgs.add(service);
10009 r.lastStartId++;
10010 if (r.lastStartId < 1) {
10011 r.lastStartId = 1;
10012 }
10013 r.lastActivity = SystemClock.uptimeMillis();
10014 synchronized (r.stats.getBatteryStats()) {
10015 r.stats.startRunningLocked();
10016 }
10017 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10018 return new ComponentName("!", "Service process is bad");
10019 }
10020 return r.name;
10021 }
10022 }
10023
10024 public ComponentName startService(IApplicationThread caller, Intent service,
10025 String resolvedType) {
10026 // Refuse possible leaked file descriptors
10027 if (service != null && service.hasFileDescriptors() == true) {
10028 throw new IllegalArgumentException("File descriptors passed in Intent");
10029 }
10030
10031 synchronized(this) {
10032 final int callingPid = Binder.getCallingPid();
10033 final int callingUid = Binder.getCallingUid();
10034 final long origId = Binder.clearCallingIdentity();
10035 ComponentName res = startServiceLocked(caller, service,
10036 resolvedType, callingPid, callingUid);
10037 Binder.restoreCallingIdentity(origId);
10038 return res;
10039 }
10040 }
10041
10042 ComponentName startServiceInPackage(int uid,
10043 Intent service, String resolvedType) {
10044 synchronized(this) {
10045 final long origId = Binder.clearCallingIdentity();
10046 ComponentName res = startServiceLocked(null, service,
10047 resolvedType, -1, uid);
10048 Binder.restoreCallingIdentity(origId);
10049 return res;
10050 }
10051 }
10052
10053 public int stopService(IApplicationThread caller, Intent service,
10054 String resolvedType) {
10055 // Refuse possible leaked file descriptors
10056 if (service != null && service.hasFileDescriptors() == true) {
10057 throw new IllegalArgumentException("File descriptors passed in Intent");
10058 }
10059
10060 synchronized(this) {
10061 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10062 + " type=" + resolvedType);
10063
10064 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10065 if (caller != null && callerApp == null) {
10066 throw new SecurityException(
10067 "Unable to find app for caller " + caller
10068 + " (pid=" + Binder.getCallingPid()
10069 + ") when stopping service " + service);
10070 }
10071
10072 // If this service is active, make sure it is stopped.
10073 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10074 if (r != null) {
10075 if (r.record != null) {
10076 synchronized (r.record.stats.getBatteryStats()) {
10077 r.record.stats.stopRunningLocked();
10078 }
10079 r.record.startRequested = false;
10080 final long origId = Binder.clearCallingIdentity();
10081 bringDownServiceLocked(r.record, false);
10082 Binder.restoreCallingIdentity(origId);
10083 return 1;
10084 }
10085 return -1;
10086 }
10087 }
10088
10089 return 0;
10090 }
10091
10092 public IBinder peekService(Intent service, String resolvedType) {
10093 // Refuse possible leaked file descriptors
10094 if (service != null && service.hasFileDescriptors() == true) {
10095 throw new IllegalArgumentException("File descriptors passed in Intent");
10096 }
10097
10098 IBinder ret = null;
10099
10100 synchronized(this) {
10101 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10102
10103 if (r != null) {
10104 // r.record is null if findServiceLocked() failed the caller permission check
10105 if (r.record == null) {
10106 throw new SecurityException(
10107 "Permission Denial: Accessing service " + r.record.name
10108 + " from pid=" + Binder.getCallingPid()
10109 + ", uid=" + Binder.getCallingUid()
10110 + " requires " + r.permission);
10111 }
10112 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10113 if (ib != null) {
10114 ret = ib.binder;
10115 }
10116 }
10117 }
10118
10119 return ret;
10120 }
10121
10122 public boolean stopServiceToken(ComponentName className, IBinder token,
10123 int startId) {
10124 synchronized(this) {
10125 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10126 + " " + token + " startId=" + startId);
10127 ServiceRecord r = findServiceLocked(className, token);
10128 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10129 synchronized (r.stats.getBatteryStats()) {
10130 r.stats.stopRunningLocked();
10131 r.startRequested = false;
10132 }
10133 final long origId = Binder.clearCallingIdentity();
10134 bringDownServiceLocked(r, false);
10135 Binder.restoreCallingIdentity(origId);
10136 return true;
10137 }
10138 }
10139 return false;
10140 }
10141
10142 public void setServiceForeground(ComponentName className, IBinder token,
10143 boolean isForeground) {
10144 synchronized(this) {
10145 ServiceRecord r = findServiceLocked(className, token);
10146 if (r != null) {
10147 if (r.isForeground != isForeground) {
10148 final long origId = Binder.clearCallingIdentity();
10149 r.isForeground = isForeground;
10150 if (r.app != null) {
10151 updateServiceForegroundLocked(r.app, true);
10152 }
10153 Binder.restoreCallingIdentity(origId);
10154 }
10155 }
10156 }
10157 }
10158
10159 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10160 boolean anyForeground = false;
10161 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10162 if (sr.isForeground) {
10163 anyForeground = true;
10164 break;
10165 }
10166 }
10167 if (anyForeground != proc.foregroundServices) {
10168 proc.foregroundServices = anyForeground;
10169 if (oomAdj) {
10170 updateOomAdjLocked();
10171 }
10172 }
10173 }
10174
10175 public int bindService(IApplicationThread caller, IBinder token,
10176 Intent service, String resolvedType,
10177 IServiceConnection connection, int flags) {
10178 // Refuse possible leaked file descriptors
10179 if (service != null && service.hasFileDescriptors() == true) {
10180 throw new IllegalArgumentException("File descriptors passed in Intent");
10181 }
10182
10183 synchronized(this) {
10184 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10185 + " type=" + resolvedType + " conn=" + connection.asBinder()
10186 + " flags=0x" + Integer.toHexString(flags));
10187 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10188 if (callerApp == null) {
10189 throw new SecurityException(
10190 "Unable to find app for caller " + caller
10191 + " (pid=" + Binder.getCallingPid()
10192 + ") when binding service " + service);
10193 }
10194
10195 HistoryRecord activity = null;
10196 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010197 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010198 if (aindex < 0) {
10199 Log.w(TAG, "Binding with unknown activity: " + token);
10200 return 0;
10201 }
10202 activity = (HistoryRecord)mHistory.get(aindex);
10203 }
10204
10205 ServiceLookupResult res =
10206 retrieveServiceLocked(service, resolvedType,
10207 Binder.getCallingPid(), Binder.getCallingUid());
10208 if (res == null) {
10209 return 0;
10210 }
10211 if (res.record == null) {
10212 return -1;
10213 }
10214 ServiceRecord s = res.record;
10215
10216 final long origId = Binder.clearCallingIdentity();
10217
10218 if (unscheduleServiceRestartLocked(s)) {
10219 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10220 + s.shortName);
10221 }
10222
10223 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10224 ConnectionRecord c = new ConnectionRecord(b, activity,
10225 connection, flags);
10226
10227 IBinder binder = connection.asBinder();
10228 s.connections.put(binder, c);
10229 b.connections.add(c);
10230 if (activity != null) {
10231 if (activity.connections == null) {
10232 activity.connections = new HashSet<ConnectionRecord>();
10233 }
10234 activity.connections.add(c);
10235 }
10236 b.client.connections.add(c);
10237 mServiceConnections.put(binder, c);
10238
10239 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10240 s.lastActivity = SystemClock.uptimeMillis();
10241 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10242 return 0;
10243 }
10244 }
10245
10246 if (s.app != null) {
10247 // This could have made the service more important.
10248 updateOomAdjLocked(s.app);
10249 }
10250
10251 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10252 + ": received=" + b.intent.received
10253 + " apps=" + b.intent.apps.size()
10254 + " doRebind=" + b.intent.doRebind);
10255
10256 if (s.app != null && b.intent.received) {
10257 // Service is already running, so we can immediately
10258 // publish the connection.
10259 try {
10260 c.conn.connected(s.name, b.intent.binder);
10261 } catch (Exception e) {
10262 Log.w(TAG, "Failure sending service " + s.shortName
10263 + " to connection " + c.conn.asBinder()
10264 + " (in " + c.binding.client.processName + ")", e);
10265 }
10266
10267 // If this is the first app connected back to this binding,
10268 // and the service had previously asked to be told when
10269 // rebound, then do so.
10270 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10271 requestServiceBindingLocked(s, b.intent, true);
10272 }
10273 } else if (!b.intent.requested) {
10274 requestServiceBindingLocked(s, b.intent, false);
10275 }
10276
10277 Binder.restoreCallingIdentity(origId);
10278 }
10279
10280 return 1;
10281 }
10282
10283 private void removeConnectionLocked(
10284 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10285 IBinder binder = c.conn.asBinder();
10286 AppBindRecord b = c.binding;
10287 ServiceRecord s = b.service;
10288 s.connections.remove(binder);
10289 b.connections.remove(c);
10290 if (c.activity != null && c.activity != skipAct) {
10291 if (c.activity.connections != null) {
10292 c.activity.connections.remove(c);
10293 }
10294 }
10295 if (b.client != skipApp) {
10296 b.client.connections.remove(c);
10297 }
10298 mServiceConnections.remove(binder);
10299
10300 if (b.connections.size() == 0) {
10301 b.intent.apps.remove(b.client);
10302 }
10303
10304 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10305 + ": shouldUnbind=" + b.intent.hasBound);
10306 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10307 && b.intent.hasBound) {
10308 try {
10309 bumpServiceExecutingLocked(s);
10310 updateOomAdjLocked(s.app);
10311 b.intent.hasBound = false;
10312 // Assume the client doesn't want to know about a rebind;
10313 // we will deal with that later if it asks for one.
10314 b.intent.doRebind = false;
10315 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10316 } catch (Exception e) {
10317 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10318 serviceDoneExecutingLocked(s, true);
10319 }
10320 }
10321
10322 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10323 bringDownServiceLocked(s, false);
10324 }
10325 }
10326
10327 public boolean unbindService(IServiceConnection connection) {
10328 synchronized (this) {
10329 IBinder binder = connection.asBinder();
10330 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10331 ConnectionRecord r = mServiceConnections.get(binder);
10332 if (r == null) {
10333 Log.w(TAG, "Unbind failed: could not find connection for "
10334 + connection.asBinder());
10335 return false;
10336 }
10337
10338 final long origId = Binder.clearCallingIdentity();
10339
10340 removeConnectionLocked(r, null, null);
10341
10342 if (r.binding.service.app != null) {
10343 // This could have made the service less important.
10344 updateOomAdjLocked(r.binding.service.app);
10345 }
10346
10347 Binder.restoreCallingIdentity(origId);
10348 }
10349
10350 return true;
10351 }
10352
10353 public void publishService(IBinder token, Intent intent, IBinder service) {
10354 // Refuse possible leaked file descriptors
10355 if (intent != null && intent.hasFileDescriptors() == true) {
10356 throw new IllegalArgumentException("File descriptors passed in Intent");
10357 }
10358
10359 synchronized(this) {
10360 if (!(token instanceof ServiceRecord)) {
10361 throw new IllegalArgumentException("Invalid service token");
10362 }
10363 ServiceRecord r = (ServiceRecord)token;
10364
10365 final long origId = Binder.clearCallingIdentity();
10366
10367 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10368 + " " + intent + ": " + service);
10369 if (r != null) {
10370 Intent.FilterComparison filter
10371 = new Intent.FilterComparison(intent);
10372 IntentBindRecord b = r.bindings.get(filter);
10373 if (b != null && !b.received) {
10374 b.binder = service;
10375 b.requested = true;
10376 b.received = true;
10377 if (r.connections.size() > 0) {
10378 Iterator<ConnectionRecord> it
10379 = r.connections.values().iterator();
10380 while (it.hasNext()) {
10381 ConnectionRecord c = it.next();
10382 if (!filter.equals(c.binding.intent.intent)) {
10383 if (DEBUG_SERVICE) Log.v(
10384 TAG, "Not publishing to: " + c);
10385 if (DEBUG_SERVICE) Log.v(
10386 TAG, "Bound intent: " + c.binding.intent.intent);
10387 if (DEBUG_SERVICE) Log.v(
10388 TAG, "Published intent: " + intent);
10389 continue;
10390 }
10391 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10392 try {
10393 c.conn.connected(r.name, service);
10394 } catch (Exception e) {
10395 Log.w(TAG, "Failure sending service " + r.name +
10396 " to connection " + c.conn.asBinder() +
10397 " (in " + c.binding.client.processName + ")", e);
10398 }
10399 }
10400 }
10401 }
10402
10403 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10404
10405 Binder.restoreCallingIdentity(origId);
10406 }
10407 }
10408 }
10409
10410 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10411 // Refuse possible leaked file descriptors
10412 if (intent != null && intent.hasFileDescriptors() == true) {
10413 throw new IllegalArgumentException("File descriptors passed in Intent");
10414 }
10415
10416 synchronized(this) {
10417 if (!(token instanceof ServiceRecord)) {
10418 throw new IllegalArgumentException("Invalid service token");
10419 }
10420 ServiceRecord r = (ServiceRecord)token;
10421
10422 final long origId = Binder.clearCallingIdentity();
10423
10424 if (r != null) {
10425 Intent.FilterComparison filter
10426 = new Intent.FilterComparison(intent);
10427 IntentBindRecord b = r.bindings.get(filter);
10428 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10429 + " at " + b + ": apps="
10430 + (b != null ? b.apps.size() : 0));
10431 if (b != null) {
10432 if (b.apps.size() > 0) {
10433 // Applications have already bound since the last
10434 // unbind, so just rebind right here.
10435 requestServiceBindingLocked(r, b, true);
10436 } else {
10437 // Note to tell the service the next time there is
10438 // a new client.
10439 b.doRebind = true;
10440 }
10441 }
10442
10443 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10444
10445 Binder.restoreCallingIdentity(origId);
10446 }
10447 }
10448 }
10449
10450 public void serviceDoneExecuting(IBinder token) {
10451 synchronized(this) {
10452 if (!(token instanceof ServiceRecord)) {
10453 throw new IllegalArgumentException("Invalid service token");
10454 }
10455 ServiceRecord r = (ServiceRecord)token;
10456 boolean inStopping = mStoppingServices.contains(token);
10457 if (r != null) {
10458 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10459 + ": nesting=" + r.executeNesting
10460 + ", inStopping=" + inStopping);
10461 if (r != token) {
10462 Log.w(TAG, "Done executing service " + r.name
10463 + " with incorrect token: given " + token
10464 + ", expected " + r);
10465 return;
10466 }
10467
10468 final long origId = Binder.clearCallingIdentity();
10469 serviceDoneExecutingLocked(r, inStopping);
10470 Binder.restoreCallingIdentity(origId);
10471 } else {
10472 Log.w(TAG, "Done executing unknown service " + r.name
10473 + " with token " + token);
10474 }
10475 }
10476 }
10477
10478 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10479 r.executeNesting--;
10480 if (r.executeNesting <= 0 && r.app != null) {
10481 r.app.executingServices.remove(r);
10482 if (r.app.executingServices.size() == 0) {
10483 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10484 }
10485 if (inStopping) {
10486 mStoppingServices.remove(r);
10487 }
10488 updateOomAdjLocked(r.app);
10489 }
10490 }
10491
10492 void serviceTimeout(ProcessRecord proc) {
10493 synchronized(this) {
10494 if (proc.executingServices.size() == 0 || proc.thread == null) {
10495 return;
10496 }
10497 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10498 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10499 ServiceRecord timeout = null;
10500 long nextTime = 0;
10501 while (it.hasNext()) {
10502 ServiceRecord sr = it.next();
10503 if (sr.executingStart < maxTime) {
10504 timeout = sr;
10505 break;
10506 }
10507 if (sr.executingStart > nextTime) {
10508 nextTime = sr.executingStart;
10509 }
10510 }
10511 if (timeout != null && mLRUProcesses.contains(proc)) {
10512 Log.w(TAG, "Timeout executing service: " + timeout);
10513 appNotRespondingLocked(proc, null, "Executing service "
10514 + timeout.name);
10515 } else {
10516 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10517 msg.obj = proc;
10518 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10519 }
10520 }
10521 }
10522
10523 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010524 // BACKUP AND RESTORE
10525 // =========================================================
10526
10527 // Cause the target app to be launched if necessary and its backup agent
10528 // instantiated. The backup agent will invoke backupAgentCreated() on the
10529 // activity manager to announce its creation.
10530 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10531 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10532 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10533
10534 synchronized(this) {
10535 // !!! TODO: currently no check here that we're already bound
10536 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10537 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10538 synchronized (stats) {
10539 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10540 }
10541
10542 BackupRecord r = new BackupRecord(ss, app, backupMode);
10543 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10544 // startProcessLocked() returns existing proc's record if it's already running
10545 ProcessRecord proc = startProcessLocked(app.processName, app,
10546 false, 0, "backup", hostingName);
10547 if (proc == null) {
10548 Log.e(TAG, "Unable to start backup agent process " + r);
10549 return false;
10550 }
10551
10552 r.app = proc;
10553 mBackupTarget = r;
10554 mBackupAppName = app.packageName;
10555
Christopher Tate6fa95972009-06-05 18:43:55 -070010556 // Try not to kill the process during backup
10557 updateOomAdjLocked(proc);
10558
Christopher Tate181fafa2009-05-14 11:12:14 -070010559 // If the process is already attached, schedule the creation of the backup agent now.
10560 // If it is not yet live, this will be done when it attaches to the framework.
10561 if (proc.thread != null) {
10562 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10563 try {
10564 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10565 } catch (RemoteException e) {
10566 // !!! TODO: notify the backup manager that we crashed, or rely on
10567 // death notices, or...?
10568 }
10569 } else {
10570 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10571 }
10572 // Invariants: at this point, the target app process exists and the application
10573 // is either already running or in the process of coming up. mBackupTarget and
10574 // mBackupAppName describe the app, so that when it binds back to the AM we
10575 // know that it's scheduled for a backup-agent operation.
10576 }
10577
10578 return true;
10579 }
10580
10581 // A backup agent has just come up
10582 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10583 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10584 + " = " + agent);
10585
10586 synchronized(this) {
10587 if (!agentPackageName.equals(mBackupAppName)) {
10588 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10589 return;
10590 }
10591
Christopher Tate043dadc2009-06-02 16:11:00 -070010592 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010593 try {
10594 IBackupManager bm = IBackupManager.Stub.asInterface(
10595 ServiceManager.getService(Context.BACKUP_SERVICE));
10596 bm.agentConnected(agentPackageName, agent);
10597 } catch (RemoteException e) {
10598 // can't happen; the backup manager service is local
10599 } catch (Exception e) {
10600 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10601 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010602 } finally {
10603 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010604 }
10605 }
10606 }
10607
10608 // done with this agent
10609 public void unbindBackupAgent(ApplicationInfo appInfo) {
10610 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010611 if (appInfo == null) {
10612 Log.w(TAG, "unbind backup agent for null app");
10613 return;
10614 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010615
10616 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010617 if (mBackupAppName == null) {
10618 Log.w(TAG, "Unbinding backup agent with no active backup");
10619 return;
10620 }
10621
Christopher Tate181fafa2009-05-14 11:12:14 -070010622 if (!mBackupAppName.equals(appInfo.packageName)) {
10623 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10624 return;
10625 }
10626
Christopher Tate6fa95972009-06-05 18:43:55 -070010627 ProcessRecord proc = mBackupTarget.app;
10628 mBackupTarget = null;
10629 mBackupAppName = null;
10630
10631 // Not backing this app up any more; reset its OOM adjustment
10632 updateOomAdjLocked(proc);
10633
Christopher Tatec7b31e32009-06-10 15:49:30 -070010634 // If the app crashed during backup, 'thread' will be null here
10635 if (proc.thread != null) {
10636 try {
10637 proc.thread.scheduleDestroyBackupAgent(appInfo);
10638 } catch (Exception e) {
10639 Log.e(TAG, "Exception when unbinding backup agent:");
10640 e.printStackTrace();
10641 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010642 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010643 }
10644 }
10645 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010646 // BROADCASTS
10647 // =========================================================
10648
10649 private final List getStickies(String action, IntentFilter filter,
10650 List cur) {
10651 final ContentResolver resolver = mContext.getContentResolver();
10652 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10653 if (list == null) {
10654 return cur;
10655 }
10656 int N = list.size();
10657 for (int i=0; i<N; i++) {
10658 Intent intent = list.get(i);
10659 if (filter.match(resolver, intent, true, TAG) >= 0) {
10660 if (cur == null) {
10661 cur = new ArrayList<Intent>();
10662 }
10663 cur.add(intent);
10664 }
10665 }
10666 return cur;
10667 }
10668
10669 private final void scheduleBroadcastsLocked() {
10670 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10671 + mBroadcastsScheduled);
10672
10673 if (mBroadcastsScheduled) {
10674 return;
10675 }
10676 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10677 mBroadcastsScheduled = true;
10678 }
10679
10680 public Intent registerReceiver(IApplicationThread caller,
10681 IIntentReceiver receiver, IntentFilter filter, String permission) {
10682 synchronized(this) {
10683 ProcessRecord callerApp = null;
10684 if (caller != null) {
10685 callerApp = getRecordForAppLocked(caller);
10686 if (callerApp == null) {
10687 throw new SecurityException(
10688 "Unable to find app for caller " + caller
10689 + " (pid=" + Binder.getCallingPid()
10690 + ") when registering receiver " + receiver);
10691 }
10692 }
10693
10694 List allSticky = null;
10695
10696 // Look for any matching sticky broadcasts...
10697 Iterator actions = filter.actionsIterator();
10698 if (actions != null) {
10699 while (actions.hasNext()) {
10700 String action = (String)actions.next();
10701 allSticky = getStickies(action, filter, allSticky);
10702 }
10703 } else {
10704 allSticky = getStickies(null, filter, allSticky);
10705 }
10706
10707 // The first sticky in the list is returned directly back to
10708 // the client.
10709 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10710
10711 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10712 + ": " + sticky);
10713
10714 if (receiver == null) {
10715 return sticky;
10716 }
10717
10718 ReceiverList rl
10719 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10720 if (rl == null) {
10721 rl = new ReceiverList(this, callerApp,
10722 Binder.getCallingPid(),
10723 Binder.getCallingUid(), receiver);
10724 if (rl.app != null) {
10725 rl.app.receivers.add(rl);
10726 } else {
10727 try {
10728 receiver.asBinder().linkToDeath(rl, 0);
10729 } catch (RemoteException e) {
10730 return sticky;
10731 }
10732 rl.linkedToDeath = true;
10733 }
10734 mRegisteredReceivers.put(receiver.asBinder(), rl);
10735 }
10736 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10737 rl.add(bf);
10738 if (!bf.debugCheck()) {
10739 Log.w(TAG, "==> For Dynamic broadast");
10740 }
10741 mReceiverResolver.addFilter(bf);
10742
10743 // Enqueue broadcasts for all existing stickies that match
10744 // this filter.
10745 if (allSticky != null) {
10746 ArrayList receivers = new ArrayList();
10747 receivers.add(bf);
10748
10749 int N = allSticky.size();
10750 for (int i=0; i<N; i++) {
10751 Intent intent = (Intent)allSticky.get(i);
10752 BroadcastRecord r = new BroadcastRecord(intent, null,
10753 null, -1, -1, null, receivers, null, 0, null, null,
10754 false);
10755 if (mParallelBroadcasts.size() == 0) {
10756 scheduleBroadcastsLocked();
10757 }
10758 mParallelBroadcasts.add(r);
10759 }
10760 }
10761
10762 return sticky;
10763 }
10764 }
10765
10766 public void unregisterReceiver(IIntentReceiver receiver) {
10767 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10768
10769 boolean doNext = false;
10770
10771 synchronized(this) {
10772 ReceiverList rl
10773 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10774 if (rl != null) {
10775 if (rl.curBroadcast != null) {
10776 BroadcastRecord r = rl.curBroadcast;
10777 doNext = finishReceiverLocked(
10778 receiver.asBinder(), r.resultCode, r.resultData,
10779 r.resultExtras, r.resultAbort, true);
10780 }
10781
10782 if (rl.app != null) {
10783 rl.app.receivers.remove(rl);
10784 }
10785 removeReceiverLocked(rl);
10786 if (rl.linkedToDeath) {
10787 rl.linkedToDeath = false;
10788 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10789 }
10790 }
10791 }
10792
10793 if (!doNext) {
10794 return;
10795 }
10796
10797 final long origId = Binder.clearCallingIdentity();
10798 processNextBroadcast(false);
10799 trimApplications();
10800 Binder.restoreCallingIdentity(origId);
10801 }
10802
10803 void removeReceiverLocked(ReceiverList rl) {
10804 mRegisteredReceivers.remove(rl.receiver.asBinder());
10805 int N = rl.size();
10806 for (int i=0; i<N; i++) {
10807 mReceiverResolver.removeFilter(rl.get(i));
10808 }
10809 }
10810
10811 private final int broadcastIntentLocked(ProcessRecord callerApp,
10812 String callerPackage, Intent intent, String resolvedType,
10813 IIntentReceiver resultTo, int resultCode, String resultData,
10814 Bundle map, String requiredPermission,
10815 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10816 intent = new Intent(intent);
10817
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010818 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010819 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10820 + " ordered=" + ordered);
10821 if ((resultTo != null) && !ordered) {
10822 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10823 }
10824
10825 // Handle special intents: if this broadcast is from the package
10826 // manager about a package being removed, we need to remove all of
10827 // its activities from the history stack.
10828 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10829 intent.getAction());
10830 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10831 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10832 || uidRemoved) {
10833 if (checkComponentPermission(
10834 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10835 callingPid, callingUid, -1)
10836 == PackageManager.PERMISSION_GRANTED) {
10837 if (uidRemoved) {
10838 final Bundle intentExtras = intent.getExtras();
10839 final int uid = intentExtras != null
10840 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10841 if (uid >= 0) {
10842 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10843 synchronized (bs) {
10844 bs.removeUidStatsLocked(uid);
10845 }
10846 }
10847 } else {
10848 Uri data = intent.getData();
10849 String ssp;
10850 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10851 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10852 uninstallPackageLocked(ssp,
10853 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010854 AttributeCache ac = AttributeCache.instance();
10855 if (ac != null) {
10856 ac.removePackage(ssp);
10857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010858 }
10859 }
10860 }
10861 } else {
10862 String msg = "Permission Denial: " + intent.getAction()
10863 + " broadcast from " + callerPackage + " (pid=" + callingPid
10864 + ", uid=" + callingUid + ")"
10865 + " requires "
10866 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10867 Log.w(TAG, msg);
10868 throw new SecurityException(msg);
10869 }
10870 }
10871
10872 /*
10873 * If this is the time zone changed action, queue up a message that will reset the timezone
10874 * of all currently running processes. This message will get queued up before the broadcast
10875 * happens.
10876 */
10877 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10878 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10879 }
10880
Dianne Hackborn854060af2009-07-09 18:14:31 -070010881 /*
10882 * Prevent non-system code (defined here to be non-persistent
10883 * processes) from sending protected broadcasts.
10884 */
10885 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10886 || callingUid == Process.SHELL_UID || callingUid == 0) {
10887 // Always okay.
10888 } else if (callerApp == null || !callerApp.persistent) {
10889 try {
10890 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10891 intent.getAction())) {
10892 String msg = "Permission Denial: not allowed to send broadcast "
10893 + intent.getAction() + " from pid="
10894 + callingPid + ", uid=" + callingUid;
10895 Log.w(TAG, msg);
10896 throw new SecurityException(msg);
10897 }
10898 } catch (RemoteException e) {
10899 Log.w(TAG, "Remote exception", e);
10900 return BROADCAST_SUCCESS;
10901 }
10902 }
10903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010904 // Add to the sticky list if requested.
10905 if (sticky) {
10906 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10907 callingPid, callingUid)
10908 != PackageManager.PERMISSION_GRANTED) {
10909 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10910 + callingPid + ", uid=" + callingUid
10911 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10912 Log.w(TAG, msg);
10913 throw new SecurityException(msg);
10914 }
10915 if (requiredPermission != null) {
10916 Log.w(TAG, "Can't broadcast sticky intent " + intent
10917 + " and enforce permission " + requiredPermission);
10918 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10919 }
10920 if (intent.getComponent() != null) {
10921 throw new SecurityException(
10922 "Sticky broadcasts can't target a specific component");
10923 }
10924 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10925 if (list == null) {
10926 list = new ArrayList<Intent>();
10927 mStickyBroadcasts.put(intent.getAction(), list);
10928 }
10929 int N = list.size();
10930 int i;
10931 for (i=0; i<N; i++) {
10932 if (intent.filterEquals(list.get(i))) {
10933 // This sticky already exists, replace it.
10934 list.set(i, new Intent(intent));
10935 break;
10936 }
10937 }
10938 if (i >= N) {
10939 list.add(new Intent(intent));
10940 }
10941 }
10942
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010943 // Figure out who all will receive this broadcast.
10944 List receivers = null;
10945 List<BroadcastFilter> registeredReceivers = null;
10946 try {
10947 if (intent.getComponent() != null) {
10948 // Broadcast is going to one specific receiver class...
10949 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010950 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010951 if (ai != null) {
10952 receivers = new ArrayList();
10953 ResolveInfo ri = new ResolveInfo();
10954 ri.activityInfo = ai;
10955 receivers.add(ri);
10956 }
10957 } else {
10958 // Need to resolve the intent to interested receivers...
10959 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10960 == 0) {
10961 receivers =
10962 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010963 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010964 }
Mihai Preda074edef2009-05-18 17:13:31 +020010965 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010966 }
10967 } catch (RemoteException ex) {
10968 // pm is in same process, this will never happen.
10969 }
10970
10971 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10972 if (!ordered && NR > 0) {
10973 // If we are not serializing this broadcast, then send the
10974 // registered receivers separately so they don't wait for the
10975 // components to be launched.
10976 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10977 callerPackage, callingPid, callingUid, requiredPermission,
10978 registeredReceivers, resultTo, resultCode, resultData, map,
10979 ordered);
10980 if (DEBUG_BROADCAST) Log.v(
10981 TAG, "Enqueueing parallel broadcast " + r
10982 + ": prev had " + mParallelBroadcasts.size());
10983 mParallelBroadcasts.add(r);
10984 scheduleBroadcastsLocked();
10985 registeredReceivers = null;
10986 NR = 0;
10987 }
10988
10989 // Merge into one list.
10990 int ir = 0;
10991 if (receivers != null) {
10992 // A special case for PACKAGE_ADDED: do not allow the package
10993 // being added to see this broadcast. This prevents them from
10994 // using this as a back door to get run as soon as they are
10995 // installed. Maybe in the future we want to have a special install
10996 // broadcast or such for apps, but we'd like to deliberately make
10997 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010998 boolean skip = false;
10999 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011000 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011001 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11002 skip = true;
11003 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11004 skip = true;
11005 }
11006 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011007 ? intent.getData().getSchemeSpecificPart()
11008 : null;
11009 if (skipPackage != null && receivers != null) {
11010 int NT = receivers.size();
11011 for (int it=0; it<NT; it++) {
11012 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11013 if (curt.activityInfo.packageName.equals(skipPackage)) {
11014 receivers.remove(it);
11015 it--;
11016 NT--;
11017 }
11018 }
11019 }
11020
11021 int NT = receivers != null ? receivers.size() : 0;
11022 int it = 0;
11023 ResolveInfo curt = null;
11024 BroadcastFilter curr = null;
11025 while (it < NT && ir < NR) {
11026 if (curt == null) {
11027 curt = (ResolveInfo)receivers.get(it);
11028 }
11029 if (curr == null) {
11030 curr = registeredReceivers.get(ir);
11031 }
11032 if (curr.getPriority() >= curt.priority) {
11033 // Insert this broadcast record into the final list.
11034 receivers.add(it, curr);
11035 ir++;
11036 curr = null;
11037 it++;
11038 NT++;
11039 } else {
11040 // Skip to the next ResolveInfo in the final list.
11041 it++;
11042 curt = null;
11043 }
11044 }
11045 }
11046 while (ir < NR) {
11047 if (receivers == null) {
11048 receivers = new ArrayList();
11049 }
11050 receivers.add(registeredReceivers.get(ir));
11051 ir++;
11052 }
11053
11054 if ((receivers != null && receivers.size() > 0)
11055 || resultTo != null) {
11056 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11057 callerPackage, callingPid, callingUid, requiredPermission,
11058 receivers, resultTo, resultCode, resultData, map, ordered);
11059 if (DEBUG_BROADCAST) Log.v(
11060 TAG, "Enqueueing ordered broadcast " + r
11061 + ": prev had " + mOrderedBroadcasts.size());
11062 if (DEBUG_BROADCAST) {
11063 int seq = r.intent.getIntExtra("seq", -1);
11064 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11065 }
11066 mOrderedBroadcasts.add(r);
11067 scheduleBroadcastsLocked();
11068 }
11069
11070 return BROADCAST_SUCCESS;
11071 }
11072
11073 public final int broadcastIntent(IApplicationThread caller,
11074 Intent intent, String resolvedType, IIntentReceiver resultTo,
11075 int resultCode, String resultData, Bundle map,
11076 String requiredPermission, boolean serialized, boolean sticky) {
11077 // Refuse possible leaked file descriptors
11078 if (intent != null && intent.hasFileDescriptors() == true) {
11079 throw new IllegalArgumentException("File descriptors passed in Intent");
11080 }
11081
11082 synchronized(this) {
11083 if (!mSystemReady) {
11084 // if the caller really truly claims to know what they're doing, go
11085 // ahead and allow the broadcast without launching any receivers
11086 int flags = intent.getFlags();
11087 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11088 intent = new Intent(intent);
11089 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11090 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11091 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11092 + " before boot completion");
11093 throw new IllegalStateException("Cannot broadcast before boot completed");
11094 }
11095 }
11096
11097 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11098 final int callingPid = Binder.getCallingPid();
11099 final int callingUid = Binder.getCallingUid();
11100 final long origId = Binder.clearCallingIdentity();
11101 int res = broadcastIntentLocked(callerApp,
11102 callerApp != null ? callerApp.info.packageName : null,
11103 intent, resolvedType, resultTo,
11104 resultCode, resultData, map, requiredPermission, serialized,
11105 sticky, callingPid, callingUid);
11106 Binder.restoreCallingIdentity(origId);
11107 return res;
11108 }
11109 }
11110
11111 int broadcastIntentInPackage(String packageName, int uid,
11112 Intent intent, String resolvedType, IIntentReceiver resultTo,
11113 int resultCode, String resultData, Bundle map,
11114 String requiredPermission, boolean serialized, boolean sticky) {
11115 synchronized(this) {
11116 final long origId = Binder.clearCallingIdentity();
11117 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11118 resultTo, resultCode, resultData, map, requiredPermission,
11119 serialized, sticky, -1, uid);
11120 Binder.restoreCallingIdentity(origId);
11121 return res;
11122 }
11123 }
11124
11125 public final void unbroadcastIntent(IApplicationThread caller,
11126 Intent intent) {
11127 // Refuse possible leaked file descriptors
11128 if (intent != null && intent.hasFileDescriptors() == true) {
11129 throw new IllegalArgumentException("File descriptors passed in Intent");
11130 }
11131
11132 synchronized(this) {
11133 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11134 != PackageManager.PERMISSION_GRANTED) {
11135 String msg = "Permission Denial: unbroadcastIntent() from pid="
11136 + Binder.getCallingPid()
11137 + ", uid=" + Binder.getCallingUid()
11138 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11139 Log.w(TAG, msg);
11140 throw new SecurityException(msg);
11141 }
11142 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11143 if (list != null) {
11144 int N = list.size();
11145 int i;
11146 for (i=0; i<N; i++) {
11147 if (intent.filterEquals(list.get(i))) {
11148 list.remove(i);
11149 break;
11150 }
11151 }
11152 }
11153 }
11154 }
11155
11156 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11157 String resultData, Bundle resultExtras, boolean resultAbort,
11158 boolean explicit) {
11159 if (mOrderedBroadcasts.size() == 0) {
11160 if (explicit) {
11161 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11162 }
11163 return false;
11164 }
11165 BroadcastRecord r = mOrderedBroadcasts.get(0);
11166 if (r.receiver == null) {
11167 if (explicit) {
11168 Log.w(TAG, "finishReceiver called but none active");
11169 }
11170 return false;
11171 }
11172 if (r.receiver != receiver) {
11173 Log.w(TAG, "finishReceiver called but active receiver is different");
11174 return false;
11175 }
11176 int state = r.state;
11177 r.state = r.IDLE;
11178 if (state == r.IDLE) {
11179 if (explicit) {
11180 Log.w(TAG, "finishReceiver called but state is IDLE");
11181 }
11182 }
11183 r.receiver = null;
11184 r.intent.setComponent(null);
11185 if (r.curApp != null) {
11186 r.curApp.curReceiver = null;
11187 }
11188 if (r.curFilter != null) {
11189 r.curFilter.receiverList.curBroadcast = null;
11190 }
11191 r.curFilter = null;
11192 r.curApp = null;
11193 r.curComponent = null;
11194 r.curReceiver = null;
11195 mPendingBroadcast = null;
11196
11197 r.resultCode = resultCode;
11198 r.resultData = resultData;
11199 r.resultExtras = resultExtras;
11200 r.resultAbort = resultAbort;
11201
11202 // We will process the next receiver right now if this is finishing
11203 // an app receiver (which is always asynchronous) or after we have
11204 // come back from calling a receiver.
11205 return state == BroadcastRecord.APP_RECEIVE
11206 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11207 }
11208
11209 public void finishReceiver(IBinder who, int resultCode, String resultData,
11210 Bundle resultExtras, boolean resultAbort) {
11211 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11212
11213 // Refuse possible leaked file descriptors
11214 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11215 throw new IllegalArgumentException("File descriptors passed in Bundle");
11216 }
11217
11218 boolean doNext;
11219
11220 final long origId = Binder.clearCallingIdentity();
11221
11222 synchronized(this) {
11223 doNext = finishReceiverLocked(
11224 who, resultCode, resultData, resultExtras, resultAbort, true);
11225 }
11226
11227 if (doNext) {
11228 processNextBroadcast(false);
11229 }
11230 trimApplications();
11231
11232 Binder.restoreCallingIdentity(origId);
11233 }
11234
11235 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11236 if (r.nextReceiver > 0) {
11237 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11238 if (curReceiver instanceof BroadcastFilter) {
11239 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11240 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11241 System.identityHashCode(r),
11242 r.intent.getAction(),
11243 r.nextReceiver - 1,
11244 System.identityHashCode(bf));
11245 } else {
11246 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11247 System.identityHashCode(r),
11248 r.intent.getAction(),
11249 r.nextReceiver - 1,
11250 ((ResolveInfo)curReceiver).toString());
11251 }
11252 } else {
11253 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11254 + r);
11255 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11256 System.identityHashCode(r),
11257 r.intent.getAction(),
11258 r.nextReceiver,
11259 "NONE");
11260 }
11261 }
11262
11263 private final void broadcastTimeout() {
11264 synchronized (this) {
11265 if (mOrderedBroadcasts.size() == 0) {
11266 return;
11267 }
11268 long now = SystemClock.uptimeMillis();
11269 BroadcastRecord r = mOrderedBroadcasts.get(0);
11270 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11271 if (DEBUG_BROADCAST) Log.v(TAG,
11272 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11273 + (r.startTime + BROADCAST_TIMEOUT));
11274 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11275 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11276 return;
11277 }
11278
11279 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11280 r.startTime = now;
11281 r.anrCount++;
11282
11283 // Current receiver has passed its expiration date.
11284 if (r.nextReceiver <= 0) {
11285 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11286 return;
11287 }
11288
11289 ProcessRecord app = null;
11290
11291 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11292 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11293 logBroadcastReceiverDiscard(r);
11294 if (curReceiver instanceof BroadcastFilter) {
11295 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11296 if (bf.receiverList.pid != 0
11297 && bf.receiverList.pid != MY_PID) {
11298 synchronized (this.mPidsSelfLocked) {
11299 app = this.mPidsSelfLocked.get(
11300 bf.receiverList.pid);
11301 }
11302 }
11303 } else {
11304 app = r.curApp;
11305 }
11306
11307 if (app != null) {
11308 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11309 }
11310
11311 if (mPendingBroadcast == r) {
11312 mPendingBroadcast = null;
11313 }
11314
11315 // Move on to the next receiver.
11316 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11317 r.resultExtras, r.resultAbort, true);
11318 scheduleBroadcastsLocked();
11319 }
11320 }
11321
11322 private final void processCurBroadcastLocked(BroadcastRecord r,
11323 ProcessRecord app) throws RemoteException {
11324 if (app.thread == null) {
11325 throw new RemoteException();
11326 }
11327 r.receiver = app.thread.asBinder();
11328 r.curApp = app;
11329 app.curReceiver = r;
11330 updateLRUListLocked(app, true);
11331
11332 // Tell the application to launch this receiver.
11333 r.intent.setComponent(r.curComponent);
11334
11335 boolean started = false;
11336 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011337 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011338 "Delivering to component " + r.curComponent
11339 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011340 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011341 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11342 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11343 started = true;
11344 } finally {
11345 if (!started) {
11346 r.receiver = null;
11347 r.curApp = null;
11348 app.curReceiver = null;
11349 }
11350 }
11351
11352 }
11353
11354 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11355 Intent intent, int resultCode, String data,
11356 Bundle extras, boolean ordered) throws RemoteException {
11357 if (app != null && app.thread != null) {
11358 // If we have an app thread, do the call through that so it is
11359 // correctly ordered with other one-way calls.
11360 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11361 data, extras, ordered);
11362 } else {
11363 receiver.performReceive(intent, resultCode, data, extras, ordered);
11364 }
11365 }
11366
11367 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11368 BroadcastFilter filter, boolean ordered) {
11369 boolean skip = false;
11370 if (filter.requiredPermission != null) {
11371 int perm = checkComponentPermission(filter.requiredPermission,
11372 r.callingPid, r.callingUid, -1);
11373 if (perm != PackageManager.PERMISSION_GRANTED) {
11374 Log.w(TAG, "Permission Denial: broadcasting "
11375 + r.intent.toString()
11376 + " from " + r.callerPackage + " (pid="
11377 + r.callingPid + ", uid=" + r.callingUid + ")"
11378 + " requires " + filter.requiredPermission
11379 + " due to registered receiver " + filter);
11380 skip = true;
11381 }
11382 }
11383 if (r.requiredPermission != null) {
11384 int perm = checkComponentPermission(r.requiredPermission,
11385 filter.receiverList.pid, filter.receiverList.uid, -1);
11386 if (perm != PackageManager.PERMISSION_GRANTED) {
11387 Log.w(TAG, "Permission Denial: receiving "
11388 + r.intent.toString()
11389 + " to " + filter.receiverList.app
11390 + " (pid=" + filter.receiverList.pid
11391 + ", uid=" + filter.receiverList.uid + ")"
11392 + " requires " + r.requiredPermission
11393 + " due to sender " + r.callerPackage
11394 + " (uid " + r.callingUid + ")");
11395 skip = true;
11396 }
11397 }
11398
11399 if (!skip) {
11400 // If this is not being sent as an ordered broadcast, then we
11401 // don't want to touch the fields that keep track of the current
11402 // state of ordered broadcasts.
11403 if (ordered) {
11404 r.receiver = filter.receiverList.receiver.asBinder();
11405 r.curFilter = filter;
11406 filter.receiverList.curBroadcast = r;
11407 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011408 if (filter.receiverList.app != null) {
11409 // Bump hosting application to no longer be in background
11410 // scheduling class. Note that we can't do that if there
11411 // isn't an app... but we can only be in that case for
11412 // things that directly call the IActivityManager API, which
11413 // are already core system stuff so don't matter for this.
11414 r.curApp = filter.receiverList.app;
11415 filter.receiverList.app.curReceiver = r;
11416 updateOomAdjLocked();
11417 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011418 }
11419 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011420 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011421 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011422 Log.i(TAG, "Delivering to " + filter.receiverList.app
11423 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011424 }
11425 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11426 new Intent(r.intent), r.resultCode,
11427 r.resultData, r.resultExtras, r.ordered);
11428 if (ordered) {
11429 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11430 }
11431 } catch (RemoteException e) {
11432 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11433 if (ordered) {
11434 r.receiver = null;
11435 r.curFilter = null;
11436 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011437 if (filter.receiverList.app != null) {
11438 filter.receiverList.app.curReceiver = null;
11439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011440 }
11441 }
11442 }
11443 }
11444
11445 private final void processNextBroadcast(boolean fromMsg) {
11446 synchronized(this) {
11447 BroadcastRecord r;
11448
11449 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11450 + mParallelBroadcasts.size() + " broadcasts, "
11451 + mOrderedBroadcasts.size() + " serialized broadcasts");
11452
11453 updateCpuStats();
11454
11455 if (fromMsg) {
11456 mBroadcastsScheduled = false;
11457 }
11458
11459 // First, deliver any non-serialized broadcasts right away.
11460 while (mParallelBroadcasts.size() > 0) {
11461 r = mParallelBroadcasts.remove(0);
11462 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011463 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11464 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011465 for (int i=0; i<N; i++) {
11466 Object target = r.receivers.get(i);
11467 if (DEBUG_BROADCAST) Log.v(TAG,
11468 "Delivering non-serialized to registered "
11469 + target + ": " + r);
11470 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11471 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011472 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11473 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011474 }
11475
11476 // Now take care of the next serialized one...
11477
11478 // If we are waiting for a process to come up to handle the next
11479 // broadcast, then do nothing at this point. Just in case, we
11480 // check that the process we're waiting for still exists.
11481 if (mPendingBroadcast != null) {
11482 Log.i(TAG, "processNextBroadcast: waiting for "
11483 + mPendingBroadcast.curApp);
11484
11485 boolean isDead;
11486 synchronized (mPidsSelfLocked) {
11487 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11488 }
11489 if (!isDead) {
11490 // It's still alive, so keep waiting
11491 return;
11492 } else {
11493 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11494 + " died before responding to broadcast");
11495 mPendingBroadcast = null;
11496 }
11497 }
11498
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011499 boolean looped = false;
11500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011501 do {
11502 if (mOrderedBroadcasts.size() == 0) {
11503 // No more broadcasts pending, so all done!
11504 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011505 if (looped) {
11506 // If we had finished the last ordered broadcast, then
11507 // make sure all processes have correct oom and sched
11508 // adjustments.
11509 updateOomAdjLocked();
11510 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011511 return;
11512 }
11513 r = mOrderedBroadcasts.get(0);
11514 boolean forceReceive = false;
11515
11516 // Ensure that even if something goes awry with the timeout
11517 // detection, we catch "hung" broadcasts here, discard them,
11518 // and continue to make progress.
11519 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11520 long now = SystemClock.uptimeMillis();
11521 if (r.dispatchTime > 0) {
11522 if ((numReceivers > 0) &&
11523 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11524 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11525 + " now=" + now
11526 + " dispatchTime=" + r.dispatchTime
11527 + " startTime=" + r.startTime
11528 + " intent=" + r.intent
11529 + " numReceivers=" + numReceivers
11530 + " nextReceiver=" + r.nextReceiver
11531 + " state=" + r.state);
11532 broadcastTimeout(); // forcibly finish this broadcast
11533 forceReceive = true;
11534 r.state = BroadcastRecord.IDLE;
11535 }
11536 }
11537
11538 if (r.state != BroadcastRecord.IDLE) {
11539 if (DEBUG_BROADCAST) Log.d(TAG,
11540 "processNextBroadcast() called when not idle (state="
11541 + r.state + ")");
11542 return;
11543 }
11544
11545 if (r.receivers == null || r.nextReceiver >= numReceivers
11546 || r.resultAbort || forceReceive) {
11547 // No more receivers for this broadcast! Send the final
11548 // result if requested...
11549 if (r.resultTo != null) {
11550 try {
11551 if (DEBUG_BROADCAST) {
11552 int seq = r.intent.getIntExtra("seq", -1);
11553 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11554 + " seq=" + seq + " app=" + r.callerApp);
11555 }
11556 performReceive(r.callerApp, r.resultTo,
11557 new Intent(r.intent), r.resultCode,
11558 r.resultData, r.resultExtras, false);
11559 } catch (RemoteException e) {
11560 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11561 }
11562 }
11563
11564 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11565 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11566
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011567 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11568 + r);
11569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011570 // ... and on to the next...
11571 mOrderedBroadcasts.remove(0);
11572 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011573 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011574 continue;
11575 }
11576 } while (r == null);
11577
11578 // Get the next receiver...
11579 int recIdx = r.nextReceiver++;
11580
11581 // Keep track of when this receiver started, and make sure there
11582 // is a timeout message pending to kill it if need be.
11583 r.startTime = SystemClock.uptimeMillis();
11584 if (recIdx == 0) {
11585 r.dispatchTime = r.startTime;
11586
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011587 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11588 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011589 if (DEBUG_BROADCAST) Log.v(TAG,
11590 "Submitting BROADCAST_TIMEOUT_MSG for "
11591 + (r.startTime + BROADCAST_TIMEOUT));
11592 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11593 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11594 }
11595
11596 Object nextReceiver = r.receivers.get(recIdx);
11597 if (nextReceiver instanceof BroadcastFilter) {
11598 // Simple case: this is a registered receiver who gets
11599 // a direct call.
11600 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11601 if (DEBUG_BROADCAST) Log.v(TAG,
11602 "Delivering serialized to registered "
11603 + filter + ": " + r);
11604 deliverToRegisteredReceiver(r, filter, r.ordered);
11605 if (r.receiver == null || !r.ordered) {
11606 // The receiver has already finished, so schedule to
11607 // process the next one.
11608 r.state = BroadcastRecord.IDLE;
11609 scheduleBroadcastsLocked();
11610 }
11611 return;
11612 }
11613
11614 // Hard case: need to instantiate the receiver, possibly
11615 // starting its application process to host it.
11616
11617 ResolveInfo info =
11618 (ResolveInfo)nextReceiver;
11619
11620 boolean skip = false;
11621 int perm = checkComponentPermission(info.activityInfo.permission,
11622 r.callingPid, r.callingUid,
11623 info.activityInfo.exported
11624 ? -1 : info.activityInfo.applicationInfo.uid);
11625 if (perm != PackageManager.PERMISSION_GRANTED) {
11626 Log.w(TAG, "Permission Denial: broadcasting "
11627 + r.intent.toString()
11628 + " from " + r.callerPackage + " (pid=" + r.callingPid
11629 + ", uid=" + r.callingUid + ")"
11630 + " requires " + info.activityInfo.permission
11631 + " due to receiver " + info.activityInfo.packageName
11632 + "/" + info.activityInfo.name);
11633 skip = true;
11634 }
11635 if (r.callingUid != Process.SYSTEM_UID &&
11636 r.requiredPermission != null) {
11637 try {
11638 perm = ActivityThread.getPackageManager().
11639 checkPermission(r.requiredPermission,
11640 info.activityInfo.applicationInfo.packageName);
11641 } catch (RemoteException e) {
11642 perm = PackageManager.PERMISSION_DENIED;
11643 }
11644 if (perm != PackageManager.PERMISSION_GRANTED) {
11645 Log.w(TAG, "Permission Denial: receiving "
11646 + r.intent + " to "
11647 + info.activityInfo.applicationInfo.packageName
11648 + " requires " + r.requiredPermission
11649 + " due to sender " + r.callerPackage
11650 + " (uid " + r.callingUid + ")");
11651 skip = true;
11652 }
11653 }
11654 if (r.curApp != null && r.curApp.crashing) {
11655 // If the target process is crashing, just skip it.
11656 skip = true;
11657 }
11658
11659 if (skip) {
11660 r.receiver = null;
11661 r.curFilter = null;
11662 r.state = BroadcastRecord.IDLE;
11663 scheduleBroadcastsLocked();
11664 return;
11665 }
11666
11667 r.state = BroadcastRecord.APP_RECEIVE;
11668 String targetProcess = info.activityInfo.processName;
11669 r.curComponent = new ComponentName(
11670 info.activityInfo.applicationInfo.packageName,
11671 info.activityInfo.name);
11672 r.curReceiver = info.activityInfo;
11673
11674 // Is this receiver's application already running?
11675 ProcessRecord app = getProcessRecordLocked(targetProcess,
11676 info.activityInfo.applicationInfo.uid);
11677 if (app != null && app.thread != null) {
11678 try {
11679 processCurBroadcastLocked(r, app);
11680 return;
11681 } catch (RemoteException e) {
11682 Log.w(TAG, "Exception when sending broadcast to "
11683 + r.curComponent, e);
11684 }
11685
11686 // If a dead object exception was thrown -- fall through to
11687 // restart the application.
11688 }
11689
11690 // Not running -- get it started, and enqueue this history record
11691 // to be executed when the app comes up.
11692 if ((r.curApp=startProcessLocked(targetProcess,
11693 info.activityInfo.applicationInfo, true,
11694 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11695 "broadcast", r.curComponent)) == null) {
11696 // Ah, this recipient is unavailable. Finish it if necessary,
11697 // and mark the broadcast record as ready for the next.
11698 Log.w(TAG, "Unable to launch app "
11699 + info.activityInfo.applicationInfo.packageName + "/"
11700 + info.activityInfo.applicationInfo.uid + " for broadcast "
11701 + r.intent + ": process is bad");
11702 logBroadcastReceiverDiscard(r);
11703 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11704 r.resultExtras, r.resultAbort, true);
11705 scheduleBroadcastsLocked();
11706 r.state = BroadcastRecord.IDLE;
11707 return;
11708 }
11709
11710 mPendingBroadcast = r;
11711 }
11712 }
11713
11714 // =========================================================
11715 // INSTRUMENTATION
11716 // =========================================================
11717
11718 public boolean startInstrumentation(ComponentName className,
11719 String profileFile, int flags, Bundle arguments,
11720 IInstrumentationWatcher watcher) {
11721 // Refuse possible leaked file descriptors
11722 if (arguments != null && arguments.hasFileDescriptors()) {
11723 throw new IllegalArgumentException("File descriptors passed in Bundle");
11724 }
11725
11726 synchronized(this) {
11727 InstrumentationInfo ii = null;
11728 ApplicationInfo ai = null;
11729 try {
11730 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011731 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011732 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011733 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011734 } catch (PackageManager.NameNotFoundException e) {
11735 }
11736 if (ii == null) {
11737 reportStartInstrumentationFailure(watcher, className,
11738 "Unable to find instrumentation info for: " + className);
11739 return false;
11740 }
11741 if (ai == null) {
11742 reportStartInstrumentationFailure(watcher, className,
11743 "Unable to find instrumentation target package: " + ii.targetPackage);
11744 return false;
11745 }
11746
11747 int match = mContext.getPackageManager().checkSignatures(
11748 ii.targetPackage, ii.packageName);
11749 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11750 String msg = "Permission Denial: starting instrumentation "
11751 + className + " from pid="
11752 + Binder.getCallingPid()
11753 + ", uid=" + Binder.getCallingPid()
11754 + " not allowed because package " + ii.packageName
11755 + " does not have a signature matching the target "
11756 + ii.targetPackage;
11757 reportStartInstrumentationFailure(watcher, className, msg);
11758 throw new SecurityException(msg);
11759 }
11760
11761 final long origId = Binder.clearCallingIdentity();
11762 uninstallPackageLocked(ii.targetPackage, -1, true);
11763 ProcessRecord app = addAppLocked(ai);
11764 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011765 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011766 app.instrumentationProfileFile = profileFile;
11767 app.instrumentationArguments = arguments;
11768 app.instrumentationWatcher = watcher;
11769 app.instrumentationResultClass = className;
11770 Binder.restoreCallingIdentity(origId);
11771 }
11772
11773 return true;
11774 }
11775
11776 /**
11777 * Report errors that occur while attempting to start Instrumentation. Always writes the
11778 * error to the logs, but if somebody is watching, send the report there too. This enables
11779 * the "am" command to report errors with more information.
11780 *
11781 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11782 * @param cn The component name of the instrumentation.
11783 * @param report The error report.
11784 */
11785 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11786 ComponentName cn, String report) {
11787 Log.w(TAG, report);
11788 try {
11789 if (watcher != null) {
11790 Bundle results = new Bundle();
11791 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11792 results.putString("Error", report);
11793 watcher.instrumentationStatus(cn, -1, results);
11794 }
11795 } catch (RemoteException e) {
11796 Log.w(TAG, e);
11797 }
11798 }
11799
11800 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11801 if (app.instrumentationWatcher != null) {
11802 try {
11803 // NOTE: IInstrumentationWatcher *must* be oneway here
11804 app.instrumentationWatcher.instrumentationFinished(
11805 app.instrumentationClass,
11806 resultCode,
11807 results);
11808 } catch (RemoteException e) {
11809 }
11810 }
11811 app.instrumentationWatcher = null;
11812 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011813 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011814 app.instrumentationProfileFile = null;
11815 app.instrumentationArguments = null;
11816
11817 uninstallPackageLocked(app.processName, -1, false);
11818 }
11819
11820 public void finishInstrumentation(IApplicationThread target,
11821 int resultCode, Bundle results) {
11822 // Refuse possible leaked file descriptors
11823 if (results != null && results.hasFileDescriptors()) {
11824 throw new IllegalArgumentException("File descriptors passed in Intent");
11825 }
11826
11827 synchronized(this) {
11828 ProcessRecord app = getRecordForAppLocked(target);
11829 if (app == null) {
11830 Log.w(TAG, "finishInstrumentation: no app for " + target);
11831 return;
11832 }
11833 final long origId = Binder.clearCallingIdentity();
11834 finishInstrumentationLocked(app, resultCode, results);
11835 Binder.restoreCallingIdentity(origId);
11836 }
11837 }
11838
11839 // =========================================================
11840 // CONFIGURATION
11841 // =========================================================
11842
11843 public ConfigurationInfo getDeviceConfigurationInfo() {
11844 ConfigurationInfo config = new ConfigurationInfo();
11845 synchronized (this) {
11846 config.reqTouchScreen = mConfiguration.touchscreen;
11847 config.reqKeyboardType = mConfiguration.keyboard;
11848 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011849 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11850 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011851 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11852 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011853 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11854 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011855 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11856 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070011857 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011858 }
11859 return config;
11860 }
11861
11862 public Configuration getConfiguration() {
11863 Configuration ci;
11864 synchronized(this) {
11865 ci = new Configuration(mConfiguration);
11866 }
11867 return ci;
11868 }
11869
11870 public void updateConfiguration(Configuration values) {
11871 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11872 "updateConfiguration()");
11873
11874 synchronized(this) {
11875 if (values == null && mWindowManager != null) {
11876 // sentinel: fetch the current configuration from the window manager
11877 values = mWindowManager.computeNewConfiguration();
11878 }
11879
11880 final long origId = Binder.clearCallingIdentity();
11881 updateConfigurationLocked(values, null);
11882 Binder.restoreCallingIdentity(origId);
11883 }
11884 }
11885
11886 /**
11887 * Do either or both things: (1) change the current configuration, and (2)
11888 * make sure the given activity is running with the (now) current
11889 * configuration. Returns true if the activity has been left running, or
11890 * false if <var>starting</var> is being destroyed to match the new
11891 * configuration.
11892 */
11893 public boolean updateConfigurationLocked(Configuration values,
11894 HistoryRecord starting) {
11895 int changes = 0;
11896
11897 boolean kept = true;
11898
11899 if (values != null) {
11900 Configuration newConfig = new Configuration(mConfiguration);
11901 changes = newConfig.updateFrom(values);
11902 if (changes != 0) {
11903 if (DEBUG_SWITCH) {
11904 Log.i(TAG, "Updating configuration to: " + values);
11905 }
11906
11907 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11908
11909 if (values.locale != null) {
11910 saveLocaleLocked(values.locale,
11911 !values.locale.equals(mConfiguration.locale),
11912 values.userSetLocale);
11913 }
11914
11915 mConfiguration = newConfig;
11916
11917 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11918 msg.obj = new Configuration(mConfiguration);
11919 mHandler.sendMessage(msg);
11920
11921 final int N = mLRUProcesses.size();
11922 for (int i=0; i<N; i++) {
11923 ProcessRecord app = mLRUProcesses.get(i);
11924 try {
11925 if (app.thread != null) {
11926 app.thread.scheduleConfigurationChanged(mConfiguration);
11927 }
11928 } catch (Exception e) {
11929 }
11930 }
11931 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11932 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11933 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011934
11935 AttributeCache ac = AttributeCache.instance();
11936 if (ac != null) {
11937 ac.updateConfiguration(mConfiguration);
11938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011939 }
11940 }
11941
11942 if (changes != 0 && starting == null) {
11943 // If the configuration changed, and the caller is not already
11944 // in the process of starting an activity, then find the top
11945 // activity to check if its configuration needs to change.
11946 starting = topRunningActivityLocked(null);
11947 }
11948
11949 if (starting != null) {
11950 kept = ensureActivityConfigurationLocked(starting, changes);
11951 if (kept) {
11952 // If this didn't result in the starting activity being
11953 // destroyed, then we need to make sure at this point that all
11954 // other activities are made visible.
11955 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11956 + ", ensuring others are correct.");
11957 ensureActivitiesVisibleLocked(starting, changes);
11958 }
11959 }
11960
11961 return kept;
11962 }
11963
11964 private final boolean relaunchActivityLocked(HistoryRecord r,
11965 int changes, boolean andResume) {
11966 List<ResultInfo> results = null;
11967 List<Intent> newIntents = null;
11968 if (andResume) {
11969 results = r.results;
11970 newIntents = r.newIntents;
11971 }
11972 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11973 + " with results=" + results + " newIntents=" + newIntents
11974 + " andResume=" + andResume);
11975 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11976 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11977 r.task.taskId, r.shortComponentName);
11978
11979 r.startFreezingScreenLocked(r.app, 0);
11980
11981 try {
11982 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11983 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11984 changes, !andResume);
11985 // Note: don't need to call pauseIfSleepingLocked() here, because
11986 // the caller will only pass in 'andResume' if this activity is
11987 // currently resumed, which implies we aren't sleeping.
11988 } catch (RemoteException e) {
11989 return false;
11990 }
11991
11992 if (andResume) {
11993 r.results = null;
11994 r.newIntents = null;
11995 }
11996
11997 return true;
11998 }
11999
12000 /**
12001 * Make sure the given activity matches the current configuration. Returns
12002 * false if the activity had to be destroyed. Returns true if the
12003 * configuration is the same, or the activity will remain running as-is
12004 * for whatever reason. Ensures the HistoryRecord is updated with the
12005 * correct configuration and all other bookkeeping is handled.
12006 */
12007 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12008 int globalChanges) {
12009 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12010
12011 // Short circuit: if the two configurations are the exact same
12012 // object (the common case), then there is nothing to do.
12013 Configuration newConfig = mConfiguration;
12014 if (r.configuration == newConfig) {
12015 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12016 return true;
12017 }
12018
12019 // We don't worry about activities that are finishing.
12020 if (r.finishing) {
12021 if (DEBUG_SWITCH) Log.i(TAG,
12022 "Configuration doesn't matter in finishing " + r);
12023 r.stopFreezingScreenLocked(false);
12024 return true;
12025 }
12026
12027 // Okay we now are going to make this activity have the new config.
12028 // But then we need to figure out how it needs to deal with that.
12029 Configuration oldConfig = r.configuration;
12030 r.configuration = newConfig;
12031
12032 // If the activity isn't currently running, just leave the new
12033 // configuration and it will pick that up next time it starts.
12034 if (r.app == null || r.app.thread == null) {
12035 if (DEBUG_SWITCH) Log.i(TAG,
12036 "Configuration doesn't matter not running " + r);
12037 r.stopFreezingScreenLocked(false);
12038 return true;
12039 }
12040
12041 // If the activity isn't persistent, there is a chance we will
12042 // need to restart it.
12043 if (!r.persistent) {
12044
12045 // Figure out what has changed between the two configurations.
12046 int changes = oldConfig.diff(newConfig);
12047 if (DEBUG_SWITCH) {
12048 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12049 + Integer.toHexString(changes) + ", handles=0x"
12050 + Integer.toHexString(r.info.configChanges));
12051 }
12052 if ((changes&(~r.info.configChanges)) != 0) {
12053 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12054 r.configChangeFlags |= changes;
12055 r.startFreezingScreenLocked(r.app, globalChanges);
12056 if (r.app == null || r.app.thread == null) {
12057 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12058 destroyActivityLocked(r, true);
12059 } else if (r.state == ActivityState.PAUSING) {
12060 // A little annoying: we are waiting for this activity to
12061 // finish pausing. Let's not do anything now, but just
12062 // flag that it needs to be restarted when done pausing.
12063 r.configDestroy = true;
12064 return true;
12065 } else if (r.state == ActivityState.RESUMED) {
12066 // Try to optimize this case: the configuration is changing
12067 // and we need to restart the top, resumed activity.
12068 // Instead of doing the normal handshaking, just say
12069 // "restart!".
12070 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12071 relaunchActivityLocked(r, r.configChangeFlags, true);
12072 r.configChangeFlags = 0;
12073 } else {
12074 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12075 relaunchActivityLocked(r, r.configChangeFlags, false);
12076 r.configChangeFlags = 0;
12077 }
12078
12079 // All done... tell the caller we weren't able to keep this
12080 // activity around.
12081 return false;
12082 }
12083 }
12084
12085 // Default case: the activity can handle this new configuration, so
12086 // hand it over. Note that we don't need to give it the new
12087 // configuration, since we always send configuration changes to all
12088 // process when they happen so it can just use whatever configuration
12089 // it last got.
12090 if (r.app != null && r.app.thread != null) {
12091 try {
12092 r.app.thread.scheduleActivityConfigurationChanged(r);
12093 } catch (RemoteException e) {
12094 // If process died, whatever.
12095 }
12096 }
12097 r.stopFreezingScreenLocked(false);
12098
12099 return true;
12100 }
12101
12102 /**
12103 * Save the locale. You must be inside a synchronized (this) block.
12104 */
12105 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12106 if(isDiff) {
12107 SystemProperties.set("user.language", l.getLanguage());
12108 SystemProperties.set("user.region", l.getCountry());
12109 }
12110
12111 if(isPersist) {
12112 SystemProperties.set("persist.sys.language", l.getLanguage());
12113 SystemProperties.set("persist.sys.country", l.getCountry());
12114 SystemProperties.set("persist.sys.localevar", l.getVariant());
12115 }
12116 }
12117
12118 // =========================================================
12119 // LIFETIME MANAGEMENT
12120 // =========================================================
12121
12122 private final int computeOomAdjLocked(
12123 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12124 if (mAdjSeq == app.adjSeq) {
12125 // This adjustment has already been computed.
12126 return app.curAdj;
12127 }
12128
12129 if (app.thread == null) {
12130 app.adjSeq = mAdjSeq;
12131 return (app.curAdj=EMPTY_APP_ADJ);
12132 }
12133
12134 app.isForeground = false;
12135
The Android Open Source Project4df24232009-03-05 14:34:35 -080012136 // Determine the importance of the process, starting with most
12137 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012138 int adj;
12139 int N;
12140 if (app == TOP_APP || app.instrumentationClass != null
12141 || app.persistentActivities > 0) {
12142 // The last app on the list is the foreground app.
12143 adj = FOREGROUND_APP_ADJ;
12144 app.isForeground = true;
12145 } else if (app.curReceiver != null ||
12146 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12147 // An app that is currently receiving a broadcast also
12148 // counts as being in the foreground.
12149 adj = FOREGROUND_APP_ADJ;
12150 } else if (app.executingServices.size() > 0) {
12151 // An app that is currently executing a service callback also
12152 // counts as being in the foreground.
12153 adj = FOREGROUND_APP_ADJ;
12154 } else if (app.foregroundServices || app.forcingToForeground != null) {
12155 // The user is aware of this app, so make it visible.
12156 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012157 } else if (app == mHomeProcess) {
12158 // This process is hosting what we currently consider to be the
12159 // home app, so we don't want to let it go into the background.
12160 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012161 } else if ((N=app.activities.size()) != 0) {
12162 // This app is in the background with paused activities.
12163 adj = hiddenAdj;
12164 for (int j=0; j<N; j++) {
12165 if (((HistoryRecord)app.activities.get(j)).visible) {
12166 // This app has a visible activity!
12167 adj = VISIBLE_APP_ADJ;
12168 break;
12169 }
12170 }
12171 } else {
12172 // A very not-needed process.
12173 adj = EMPTY_APP_ADJ;
12174 }
12175
The Android Open Source Project4df24232009-03-05 14:34:35 -080012176 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012177 // there are applications dependent on our services or providers, but
12178 // this gives us a baseline and makes sure we don't get into an
12179 // infinite recursion.
12180 app.adjSeq = mAdjSeq;
12181 app.curRawAdj = adj;
12182 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12183
Christopher Tate6fa95972009-06-05 18:43:55 -070012184 if (mBackupTarget != null && app == mBackupTarget.app) {
12185 // If possible we want to avoid killing apps while they're being backed up
12186 if (adj > BACKUP_APP_ADJ) {
12187 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12188 adj = BACKUP_APP_ADJ;
12189 }
12190 }
12191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012192 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12193 // If this process has active services running in it, we would
12194 // like to avoid killing it unless it would prevent the current
12195 // application from running.
12196 if (adj > hiddenAdj) {
12197 adj = hiddenAdj;
12198 }
12199 final long now = SystemClock.uptimeMillis();
12200 // This process is more important if the top activity is
12201 // bound to the service.
12202 Iterator jt = app.services.iterator();
12203 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12204 ServiceRecord s = (ServiceRecord)jt.next();
12205 if (s.startRequested) {
12206 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12207 // This service has seen some activity within
12208 // recent memory, so we will keep its process ahead
12209 // of the background processes.
12210 if (adj > SECONDARY_SERVER_ADJ) {
12211 adj = SECONDARY_SERVER_ADJ;
12212 }
12213 } else {
12214 // This service has been inactive for too long, just
12215 // put it with the rest of the background processes.
12216 if (adj > hiddenAdj) {
12217 adj = hiddenAdj;
12218 }
12219 }
12220 }
12221 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12222 Iterator<ConnectionRecord> kt
12223 = s.connections.values().iterator();
12224 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12225 // XXX should compute this based on the max of
12226 // all connected clients.
12227 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012228 if (cr.binding.client == app) {
12229 // Binding to ourself is not interesting.
12230 continue;
12231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012232 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12233 ProcessRecord client = cr.binding.client;
12234 int myHiddenAdj = hiddenAdj;
12235 if (myHiddenAdj > client.hiddenAdj) {
12236 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12237 myHiddenAdj = client.hiddenAdj;
12238 } else {
12239 myHiddenAdj = VISIBLE_APP_ADJ;
12240 }
12241 }
12242 int clientAdj = computeOomAdjLocked(
12243 client, myHiddenAdj, TOP_APP);
12244 if (adj > clientAdj) {
12245 adj = clientAdj > VISIBLE_APP_ADJ
12246 ? clientAdj : VISIBLE_APP_ADJ;
12247 }
12248 }
12249 HistoryRecord a = cr.activity;
12250 //if (a != null) {
12251 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12252 //}
12253 if (a != null && adj > FOREGROUND_APP_ADJ &&
12254 (a.state == ActivityState.RESUMED
12255 || a.state == ActivityState.PAUSING)) {
12256 adj = FOREGROUND_APP_ADJ;
12257 }
12258 }
12259 }
12260 }
12261 }
12262
12263 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12264 // If this process has published any content providers, then
12265 // its adjustment makes it at least as important as any of the
12266 // processes using those providers, and no less important than
12267 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12268 if (adj > CONTENT_PROVIDER_ADJ) {
12269 adj = CONTENT_PROVIDER_ADJ;
12270 }
12271 Iterator jt = app.pubProviders.values().iterator();
12272 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12273 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12274 if (cpr.clients.size() != 0) {
12275 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12276 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12277 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012278 if (client == app) {
12279 // Being our own client is not interesting.
12280 continue;
12281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012282 int myHiddenAdj = hiddenAdj;
12283 if (myHiddenAdj > client.hiddenAdj) {
12284 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12285 myHiddenAdj = client.hiddenAdj;
12286 } else {
12287 myHiddenAdj = FOREGROUND_APP_ADJ;
12288 }
12289 }
12290 int clientAdj = computeOomAdjLocked(
12291 client, myHiddenAdj, TOP_APP);
12292 if (adj > clientAdj) {
12293 adj = clientAdj > FOREGROUND_APP_ADJ
12294 ? clientAdj : FOREGROUND_APP_ADJ;
12295 }
12296 }
12297 }
12298 // If the provider has external (non-framework) process
12299 // dependencies, ensure that its adjustment is at least
12300 // FOREGROUND_APP_ADJ.
12301 if (cpr.externals != 0) {
12302 if (adj > FOREGROUND_APP_ADJ) {
12303 adj = FOREGROUND_APP_ADJ;
12304 }
12305 }
12306 }
12307 }
12308
12309 app.curRawAdj = adj;
12310
12311 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12312 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12313 if (adj > app.maxAdj) {
12314 adj = app.maxAdj;
12315 }
12316
12317 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012318 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12319 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12320 : Process.THREAD_GROUP_DEFAULT;
12321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012322 return adj;
12323 }
12324
12325 /**
12326 * Ask a given process to GC right now.
12327 */
12328 final void performAppGcLocked(ProcessRecord app) {
12329 try {
12330 app.lastRequestedGc = SystemClock.uptimeMillis();
12331 if (app.thread != null) {
12332 app.thread.processInBackground();
12333 }
12334 } catch (Exception e) {
12335 // whatever.
12336 }
12337 }
12338
12339 /**
12340 * Returns true if things are idle enough to perform GCs.
12341 */
12342 private final boolean canGcNow() {
12343 return mParallelBroadcasts.size() == 0
12344 && mOrderedBroadcasts.size() == 0
12345 && (mSleeping || (mResumedActivity != null &&
12346 mResumedActivity.idle));
12347 }
12348
12349 /**
12350 * Perform GCs on all processes that are waiting for it, but only
12351 * if things are idle.
12352 */
12353 final void performAppGcsLocked() {
12354 final int N = mProcessesToGc.size();
12355 if (N <= 0) {
12356 return;
12357 }
12358 if (canGcNow()) {
12359 while (mProcessesToGc.size() > 0) {
12360 ProcessRecord proc = mProcessesToGc.remove(0);
12361 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12362 // To avoid spamming the system, we will GC processes one
12363 // at a time, waiting a few seconds between each.
12364 performAppGcLocked(proc);
12365 scheduleAppGcsLocked();
12366 return;
12367 }
12368 }
12369 }
12370 }
12371
12372 /**
12373 * If all looks good, perform GCs on all processes waiting for them.
12374 */
12375 final void performAppGcsIfAppropriateLocked() {
12376 if (canGcNow()) {
12377 performAppGcsLocked();
12378 return;
12379 }
12380 // Still not idle, wait some more.
12381 scheduleAppGcsLocked();
12382 }
12383
12384 /**
12385 * Schedule the execution of all pending app GCs.
12386 */
12387 final void scheduleAppGcsLocked() {
12388 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12389 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12390 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12391 }
12392
12393 /**
12394 * Set up to ask a process to GC itself. This will either do it
12395 * immediately, or put it on the list of processes to gc the next
12396 * time things are idle.
12397 */
12398 final void scheduleAppGcLocked(ProcessRecord app) {
12399 long now = SystemClock.uptimeMillis();
12400 if ((app.lastRequestedGc+5000) > now) {
12401 return;
12402 }
12403 if (!mProcessesToGc.contains(app)) {
12404 mProcessesToGc.add(app);
12405 scheduleAppGcsLocked();
12406 }
12407 }
12408
12409 private final boolean updateOomAdjLocked(
12410 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12411 app.hiddenAdj = hiddenAdj;
12412
12413 if (app.thread == null) {
12414 return true;
12415 }
12416
12417 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12418
12419 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12420 //Thread priority adjustment is disabled out to see
12421 //how the kernel scheduler performs.
12422 if (false) {
12423 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12424 app.setIsForeground = app.isForeground;
12425 if (app.pid != MY_PID) {
12426 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12427 + " to " + (app.isForeground
12428 ? Process.THREAD_PRIORITY_FOREGROUND
12429 : Process.THREAD_PRIORITY_DEFAULT));
12430 try {
12431 Process.setThreadPriority(app.pid, app.isForeground
12432 ? Process.THREAD_PRIORITY_FOREGROUND
12433 : Process.THREAD_PRIORITY_DEFAULT);
12434 } catch (RuntimeException e) {
12435 Log.w(TAG, "Exception trying to set priority of application thread "
12436 + app.pid, e);
12437 }
12438 }
12439 }
12440 }
12441 if (app.pid != 0 && app.pid != MY_PID) {
12442 if (app.curRawAdj != app.setRawAdj) {
12443 if (app.curRawAdj > FOREGROUND_APP_ADJ
12444 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12445 // If this app is transitioning from foreground to
12446 // non-foreground, have it do a gc.
12447 scheduleAppGcLocked(app);
12448 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12449 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12450 // Likewise do a gc when an app is moving in to the
12451 // background (such as a service stopping).
12452 scheduleAppGcLocked(app);
12453 }
12454 app.setRawAdj = app.curRawAdj;
12455 }
12456 if (adj != app.setAdj) {
12457 if (Process.setOomAdj(app.pid, adj)) {
12458 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12459 TAG, "Set app " + app.processName +
12460 " oom adj to " + adj);
12461 app.setAdj = adj;
12462 } else {
12463 return false;
12464 }
12465 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012466 if (app.setSchedGroup != app.curSchedGroup) {
12467 app.setSchedGroup = app.curSchedGroup;
12468 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12469 "Setting process group of " + app.processName
12470 + " to " + app.curSchedGroup);
12471 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012472 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012473 try {
12474 Process.setProcessGroup(app.pid, app.curSchedGroup);
12475 } catch (Exception e) {
12476 Log.w(TAG, "Failed setting process group of " + app.pid
12477 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012478 e.printStackTrace();
12479 } finally {
12480 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012481 }
12482 }
12483 if (false) {
12484 if (app.thread != null) {
12485 try {
12486 app.thread.setSchedulingGroup(app.curSchedGroup);
12487 } catch (RemoteException e) {
12488 }
12489 }
12490 }
12491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012492 }
12493
12494 return true;
12495 }
12496
12497 private final HistoryRecord resumedAppLocked() {
12498 HistoryRecord resumedActivity = mResumedActivity;
12499 if (resumedActivity == null || resumedActivity.app == null) {
12500 resumedActivity = mPausingActivity;
12501 if (resumedActivity == null || resumedActivity.app == null) {
12502 resumedActivity = topRunningActivityLocked(null);
12503 }
12504 }
12505 return resumedActivity;
12506 }
12507
12508 private final boolean updateOomAdjLocked(ProcessRecord app) {
12509 final HistoryRecord TOP_ACT = resumedAppLocked();
12510 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12511 int curAdj = app.curAdj;
12512 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12513 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12514
12515 mAdjSeq++;
12516
12517 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12518 if (res) {
12519 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12520 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12521 if (nowHidden != wasHidden) {
12522 // Changed to/from hidden state, so apps after it in the LRU
12523 // list may also be changed.
12524 updateOomAdjLocked();
12525 }
12526 }
12527 return res;
12528 }
12529
12530 private final boolean updateOomAdjLocked() {
12531 boolean didOomAdj = true;
12532 final HistoryRecord TOP_ACT = resumedAppLocked();
12533 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12534
12535 if (false) {
12536 RuntimeException e = new RuntimeException();
12537 e.fillInStackTrace();
12538 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12539 }
12540
12541 mAdjSeq++;
12542
12543 // First try updating the OOM adjustment for each of the
12544 // application processes based on their current state.
12545 int i = mLRUProcesses.size();
12546 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12547 while (i > 0) {
12548 i--;
12549 ProcessRecord app = mLRUProcesses.get(i);
12550 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12551 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12552 && app.curAdj == curHiddenAdj) {
12553 curHiddenAdj++;
12554 }
12555 } else {
12556 didOomAdj = false;
12557 }
12558 }
12559
12560 // todo: for now pretend like OOM ADJ didn't work, because things
12561 // aren't behaving as expected on Linux -- it's not killing processes.
12562 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12563 }
12564
12565 private final void trimApplications() {
12566 synchronized (this) {
12567 int i;
12568
12569 // First remove any unused application processes whose package
12570 // has been removed.
12571 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12572 final ProcessRecord app = mRemovedProcesses.get(i);
12573 if (app.activities.size() == 0
12574 && app.curReceiver == null && app.services.size() == 0) {
12575 Log.i(
12576 TAG, "Exiting empty application process "
12577 + app.processName + " ("
12578 + (app.thread != null ? app.thread.asBinder() : null)
12579 + ")\n");
12580 if (app.pid > 0 && app.pid != MY_PID) {
12581 Process.killProcess(app.pid);
12582 } else {
12583 try {
12584 app.thread.scheduleExit();
12585 } catch (Exception e) {
12586 // Ignore exceptions.
12587 }
12588 }
12589 cleanUpApplicationRecordLocked(app, false, -1);
12590 mRemovedProcesses.remove(i);
12591
12592 if (app.persistent) {
12593 if (app.persistent) {
12594 addAppLocked(app.info);
12595 }
12596 }
12597 }
12598 }
12599
12600 // Now try updating the OOM adjustment for each of the
12601 // application processes based on their current state.
12602 // If the setOomAdj() API is not supported, then go with our
12603 // back-up plan...
12604 if (!updateOomAdjLocked()) {
12605
12606 // Count how many processes are running services.
12607 int numServiceProcs = 0;
12608 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12609 final ProcessRecord app = mLRUProcesses.get(i);
12610
12611 if (app.persistent || app.services.size() != 0
12612 || app.curReceiver != null
12613 || app.persistentActivities > 0) {
12614 // Don't count processes holding services against our
12615 // maximum process count.
12616 if (localLOGV) Log.v(
12617 TAG, "Not trimming app " + app + " with services: "
12618 + app.services);
12619 numServiceProcs++;
12620 }
12621 }
12622
12623 int curMaxProcs = mProcessLimit;
12624 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12625 if (mAlwaysFinishActivities) {
12626 curMaxProcs = 1;
12627 }
12628 curMaxProcs += numServiceProcs;
12629
12630 // Quit as many processes as we can to get down to the desired
12631 // process count. First remove any processes that no longer
12632 // have activites running in them.
12633 for ( i=0;
12634 i<mLRUProcesses.size()
12635 && mLRUProcesses.size() > curMaxProcs;
12636 i++) {
12637 final ProcessRecord app = mLRUProcesses.get(i);
12638 // Quit an application only if it is not currently
12639 // running any activities.
12640 if (!app.persistent && app.activities.size() == 0
12641 && app.curReceiver == null && app.services.size() == 0) {
12642 Log.i(
12643 TAG, "Exiting empty application process "
12644 + app.processName + " ("
12645 + (app.thread != null ? app.thread.asBinder() : null)
12646 + ")\n");
12647 if (app.pid > 0 && app.pid != MY_PID) {
12648 Process.killProcess(app.pid);
12649 } else {
12650 try {
12651 app.thread.scheduleExit();
12652 } catch (Exception e) {
12653 // Ignore exceptions.
12654 }
12655 }
12656 // todo: For now we assume the application is not buggy
12657 // or evil, and will quit as a result of our request.
12658 // Eventually we need to drive this off of the death
12659 // notification, and kill the process if it takes too long.
12660 cleanUpApplicationRecordLocked(app, false, i);
12661 i--;
12662 }
12663 }
12664
12665 // If we still have too many processes, now from the least
12666 // recently used process we start finishing activities.
12667 if (Config.LOGV) Log.v(
12668 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12669 " of " + curMaxProcs + " processes");
12670 for ( i=0;
12671 i<mLRUProcesses.size()
12672 && mLRUProcesses.size() > curMaxProcs;
12673 i++) {
12674 final ProcessRecord app = mLRUProcesses.get(i);
12675 // Quit the application only if we have a state saved for
12676 // all of its activities.
12677 boolean canQuit = !app.persistent && app.curReceiver == null
12678 && app.services.size() == 0
12679 && app.persistentActivities == 0;
12680 int NUMA = app.activities.size();
12681 int j;
12682 if (Config.LOGV) Log.v(
12683 TAG, "Looking to quit " + app.processName);
12684 for (j=0; j<NUMA && canQuit; j++) {
12685 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12686 if (Config.LOGV) Log.v(
12687 TAG, " " + r.intent.getComponent().flattenToShortString()
12688 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12689 canQuit = (r.haveState || !r.stateNotNeeded)
12690 && !r.visible && r.stopped;
12691 }
12692 if (canQuit) {
12693 // Finish all of the activities, and then the app itself.
12694 for (j=0; j<NUMA; j++) {
12695 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12696 if (!r.finishing) {
12697 destroyActivityLocked(r, false);
12698 }
12699 r.resultTo = null;
12700 }
12701 Log.i(TAG, "Exiting application process "
12702 + app.processName + " ("
12703 + (app.thread != null ? app.thread.asBinder() : null)
12704 + ")\n");
12705 if (app.pid > 0 && app.pid != MY_PID) {
12706 Process.killProcess(app.pid);
12707 } else {
12708 try {
12709 app.thread.scheduleExit();
12710 } catch (Exception e) {
12711 // Ignore exceptions.
12712 }
12713 }
12714 // todo: For now we assume the application is not buggy
12715 // or evil, and will quit as a result of our request.
12716 // Eventually we need to drive this off of the death
12717 // notification, and kill the process if it takes too long.
12718 cleanUpApplicationRecordLocked(app, false, i);
12719 i--;
12720 //dump();
12721 }
12722 }
12723
12724 }
12725
12726 int curMaxActivities = MAX_ACTIVITIES;
12727 if (mAlwaysFinishActivities) {
12728 curMaxActivities = 1;
12729 }
12730
12731 // Finally, if there are too many activities now running, try to
12732 // finish as many as we can to get back down to the limit.
12733 for ( i=0;
12734 i<mLRUActivities.size()
12735 && mLRUActivities.size() > curMaxActivities;
12736 i++) {
12737 final HistoryRecord r
12738 = (HistoryRecord)mLRUActivities.get(i);
12739
12740 // We can finish this one if we have its icicle saved and
12741 // it is not persistent.
12742 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12743 && r.stopped && !r.persistent && !r.finishing) {
12744 final int origSize = mLRUActivities.size();
12745 destroyActivityLocked(r, true);
12746
12747 // This will remove it from the LRU list, so keep
12748 // our index at the same value. Note that this check to
12749 // see if the size changes is just paranoia -- if
12750 // something unexpected happens, we don't want to end up
12751 // in an infinite loop.
12752 if (origSize > mLRUActivities.size()) {
12753 i--;
12754 }
12755 }
12756 }
12757 }
12758 }
12759
12760 /** This method sends the specified signal to each of the persistent apps */
12761 public void signalPersistentProcesses(int sig) throws RemoteException {
12762 if (sig != Process.SIGNAL_USR1) {
12763 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12764 }
12765
12766 synchronized (this) {
12767 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12768 != PackageManager.PERMISSION_GRANTED) {
12769 throw new SecurityException("Requires permission "
12770 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12771 }
12772
12773 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12774 ProcessRecord r = mLRUProcesses.get(i);
12775 if (r.thread != null && r.persistent) {
12776 Process.sendSignal(r.pid, sig);
12777 }
12778 }
12779 }
12780 }
12781
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012782 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012783 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012784
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012785 try {
12786 synchronized (this) {
12787 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12788 // its own permission.
12789 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12790 != PackageManager.PERMISSION_GRANTED) {
12791 throw new SecurityException("Requires permission "
12792 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012793 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012794
12795 if (start && fd == null) {
12796 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012797 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012798
12799 ProcessRecord proc = null;
12800 try {
12801 int pid = Integer.parseInt(process);
12802 synchronized (mPidsSelfLocked) {
12803 proc = mPidsSelfLocked.get(pid);
12804 }
12805 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012806 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012807
12808 if (proc == null) {
12809 HashMap<String, SparseArray<ProcessRecord>> all
12810 = mProcessNames.getMap();
12811 SparseArray<ProcessRecord> procs = all.get(process);
12812 if (procs != null && procs.size() > 0) {
12813 proc = procs.valueAt(0);
12814 }
12815 }
12816
12817 if (proc == null || proc.thread == null) {
12818 throw new IllegalArgumentException("Unknown process: " + process);
12819 }
12820
12821 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12822 if (isSecure) {
12823 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12824 throw new SecurityException("Process not debuggable: " + proc);
12825 }
12826 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012827
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012828 proc.thread.profilerControl(start, path, fd);
12829 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012830 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012831 }
12832 } catch (RemoteException e) {
12833 throw new IllegalStateException("Process disappeared");
12834 } finally {
12835 if (fd != null) {
12836 try {
12837 fd.close();
12838 } catch (IOException e) {
12839 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012840 }
12841 }
12842 }
12843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012844 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12845 public void monitor() {
12846 synchronized (this) { }
12847 }
12848}