blob: 8e4c8974ef5240b6923451a8e98caef5f49d96d2 [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 /**
726 * List of initialization arguments to pass to all processes when binding applications to them.
727 * For example, references to the commonly used services.
728 */
729 HashMap<String, IBinder> mAppBindArgs;
730
731 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700732 * Temporary to avoid allocations. Protected by main lock.
733 */
734 final StringBuilder mStringBuilder = new StringBuilder(256);
735
736 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 * Used to control how we initialize the service.
738 */
739 boolean mStartRunning = false;
740 ComponentName mTopComponent;
741 String mTopAction;
742 String mTopData;
743 boolean mSystemReady = false;
744 boolean mBooting = false;
745
746 Context mContext;
747
748 int mFactoryTest;
749
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700750 boolean mCheckedForSetup;
751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700753 * The time at which we will allow normal application switches again,
754 * after a call to {@link #stopAppSwitches()}.
755 */
756 long mAppSwitchesAllowedTime;
757
758 /**
759 * This is set to true after the first switch after mAppSwitchesAllowedTime
760 * is set; any switches after that will clear the time.
761 */
762 boolean mDidAppSwitch;
763
764 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 * Set while we are wanting to sleep, to prevent any
766 * activities from being started/resumed.
767 */
768 boolean mSleeping = false;
769
770 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700771 * Set if we are shutting down the system, similar to sleeping.
772 */
773 boolean mShuttingDown = false;
774
775 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 * Set when the system is going to sleep, until we have
777 * successfully paused the current activity and released our wake lock.
778 * At that point the system is allowed to actually sleep.
779 */
780 PowerManager.WakeLock mGoingToSleep;
781
782 /**
783 * We don't want to allow the device to go to sleep while in the process
784 * of launching an activity. This is primarily to allow alarm intent
785 * receivers to launch an activity and get that to run before the device
786 * goes back to sleep.
787 */
788 PowerManager.WakeLock mLaunchingActivity;
789
790 /**
791 * Task identifier that activities are currently being started
792 * in. Incremented each time a new task is created.
793 * todo: Replace this with a TokenSpace class that generates non-repeating
794 * integers that won't wrap.
795 */
796 int mCurTask = 1;
797
798 /**
799 * Current sequence id for oom_adj computation traversal.
800 */
801 int mAdjSeq = 0;
802
803 /**
804 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
805 * is set, indicating the user wants processes started in such a way
806 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
807 * running in each process (thus no pre-initialized process, etc).
808 */
809 boolean mSimpleProcessManagement = false;
810
811 /**
812 * System monitoring: number of processes that died since the last
813 * N procs were started.
814 */
815 int[] mProcDeaths = new int[20];
816
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700817 /**
818 * This is set if we had to do a delayed dexopt of an app before launching
819 * it, to increasing the ANR timeouts in that case.
820 */
821 boolean mDidDexOpt;
822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 String mDebugApp = null;
824 boolean mWaitForDebugger = false;
825 boolean mDebugTransient = false;
826 String mOrigDebugApp = null;
827 boolean mOrigWaitForDebugger = false;
828 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700829 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700831 final RemoteCallbackList<IActivityWatcher> mWatchers
832 = new RemoteCallbackList<IActivityWatcher>();
833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 /**
835 * Callback of last caller to {@link #requestPss}.
836 */
837 Runnable mRequestPssCallback;
838
839 /**
840 * Remaining processes for which we are waiting results from the last
841 * call to {@link #requestPss}.
842 */
843 final ArrayList<ProcessRecord> mRequestPssList
844 = new ArrayList<ProcessRecord>();
845
846 /**
847 * Runtime statistics collection thread. This object's lock is used to
848 * protect all related state.
849 */
850 final Thread mProcessStatsThread;
851
852 /**
853 * Used to collect process stats when showing not responding dialog.
854 * Protected by mProcessStatsThread.
855 */
856 final ProcessStats mProcessStats = new ProcessStats(
857 MONITOR_THREAD_CPU_USAGE);
858 long mLastCpuTime = 0;
859 long mLastWriteTime = 0;
860
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700861 long mInitialStartTime = 0;
862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 /**
864 * Set to true after the system has finished booting.
865 */
866 boolean mBooted = false;
867
868 int mProcessLimit = 0;
869
870 WindowManagerService mWindowManager;
871
872 static ActivityManagerService mSelf;
873 static ActivityThread mSystemThread;
874
875 private final class AppDeathRecipient implements IBinder.DeathRecipient {
876 final ProcessRecord mApp;
877 final int mPid;
878 final IApplicationThread mAppThread;
879
880 AppDeathRecipient(ProcessRecord app, int pid,
881 IApplicationThread thread) {
882 if (localLOGV) Log.v(
883 TAG, "New death recipient " + this
884 + " for thread " + thread.asBinder());
885 mApp = app;
886 mPid = pid;
887 mAppThread = thread;
888 }
889
890 public void binderDied() {
891 if (localLOGV) Log.v(
892 TAG, "Death received in " + this
893 + " for thread " + mAppThread.asBinder());
894 removeRequestedPss(mApp);
895 synchronized(ActivityManagerService.this) {
896 appDiedLocked(mApp, mPid, mAppThread);
897 }
898 }
899 }
900
901 static final int SHOW_ERROR_MSG = 1;
902 static final int SHOW_NOT_RESPONDING_MSG = 2;
903 static final int SHOW_FACTORY_ERROR_MSG = 3;
904 static final int UPDATE_CONFIGURATION_MSG = 4;
905 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
906 static final int WAIT_FOR_DEBUGGER_MSG = 6;
907 static final int BROADCAST_INTENT_MSG = 7;
908 static final int BROADCAST_TIMEOUT_MSG = 8;
909 static final int PAUSE_TIMEOUT_MSG = 9;
910 static final int IDLE_TIMEOUT_MSG = 10;
911 static final int IDLE_NOW_MSG = 11;
912 static final int SERVICE_TIMEOUT_MSG = 12;
913 static final int UPDATE_TIME_ZONE = 13;
914 static final int SHOW_UID_ERROR_MSG = 14;
915 static final int IM_FEELING_LUCKY_MSG = 15;
916 static final int LAUNCH_TIMEOUT_MSG = 16;
917 static final int DESTROY_TIMEOUT_MSG = 17;
918 static final int SERVICE_ERROR_MSG = 18;
919 static final int RESUME_TOP_ACTIVITY_MSG = 19;
920 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700921 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922
923 AlertDialog mUidAlert;
924
925 final Handler mHandler = new Handler() {
926 //public Handler() {
927 // if (localLOGV) Log.v(TAG, "Handler started!");
928 //}
929
930 public void handleMessage(Message msg) {
931 switch (msg.what) {
932 case SHOW_ERROR_MSG: {
933 HashMap data = (HashMap) msg.obj;
934 byte[] crashData = (byte[])data.get("crashData");
935 if (crashData != null) {
936 // This needs to be *un*synchronized to avoid deadlock.
937 ContentResolver resolver = mContext.getContentResolver();
938 Checkin.reportCrash(resolver, crashData);
939 }
940 synchronized (ActivityManagerService.this) {
941 ProcessRecord proc = (ProcessRecord)data.get("app");
942 if (proc != null && proc.crashDialog != null) {
943 Log.e(TAG, "App already has crash dialog: " + proc);
944 return;
945 }
946 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700947 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 Dialog d = new AppErrorDialog(
949 mContext, res, proc,
950 (Integer)data.get("flags"),
951 (String)data.get("shortMsg"),
952 (String)data.get("longMsg"));
953 d.show();
954 proc.crashDialog = d;
955 } else {
956 // The device is asleep, so just pretend that the user
957 // saw a crash dialog and hit "force quit".
958 res.set(0);
959 }
960 }
961 } break;
962 case SHOW_NOT_RESPONDING_MSG: {
963 synchronized (ActivityManagerService.this) {
964 HashMap data = (HashMap) msg.obj;
965 ProcessRecord proc = (ProcessRecord)data.get("app");
966 if (proc != null && proc.anrDialog != null) {
967 Log.e(TAG, "App already has anr dialog: " + proc);
968 return;
969 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800970
971 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
972 null, null, 0, null, null, null,
973 false, false, MY_PID, Process.SYSTEM_UID);
974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
976 mContext, proc, (HistoryRecord)data.get("activity"));
977 d.show();
978 proc.anrDialog = d;
979 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700980
981 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 } break;
983 case SHOW_FACTORY_ERROR_MSG: {
984 Dialog d = new FactoryErrorDialog(
985 mContext, msg.getData().getCharSequence("msg"));
986 d.show();
987 enableScreenAfterBoot();
988 } break;
989 case UPDATE_CONFIGURATION_MSG: {
990 final ContentResolver resolver = mContext.getContentResolver();
991 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
992 } break;
993 case GC_BACKGROUND_PROCESSES_MSG: {
994 synchronized (ActivityManagerService.this) {
995 performAppGcsIfAppropriateLocked();
996 }
997 } break;
998 case WAIT_FOR_DEBUGGER_MSG: {
999 synchronized (ActivityManagerService.this) {
1000 ProcessRecord app = (ProcessRecord)msg.obj;
1001 if (msg.arg1 != 0) {
1002 if (!app.waitedForDebugger) {
1003 Dialog d = new AppWaitingForDebuggerDialog(
1004 ActivityManagerService.this,
1005 mContext, app);
1006 app.waitDialog = d;
1007 app.waitedForDebugger = true;
1008 d.show();
1009 }
1010 } else {
1011 if (app.waitDialog != null) {
1012 app.waitDialog.dismiss();
1013 app.waitDialog = null;
1014 }
1015 }
1016 }
1017 } break;
1018 case BROADCAST_INTENT_MSG: {
1019 if (DEBUG_BROADCAST) Log.v(
1020 TAG, "Received BROADCAST_INTENT_MSG");
1021 processNextBroadcast(true);
1022 } break;
1023 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001024 if (mDidDexOpt) {
1025 mDidDexOpt = false;
1026 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1027 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1028 return;
1029 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 broadcastTimeout();
1031 } break;
1032 case PAUSE_TIMEOUT_MSG: {
1033 IBinder token = (IBinder)msg.obj;
1034 // We don't at this point know if the activity is fullscreen,
1035 // so we need to be conservative and assume it isn't.
1036 Log.w(TAG, "Activity pause timeout for " + token);
1037 activityPaused(token, null, true);
1038 } break;
1039 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001040 if (mDidDexOpt) {
1041 mDidDexOpt = false;
1042 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1043 nmsg.obj = msg.obj;
1044 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1045 return;
1046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 // We don't at this point know if the activity is fullscreen,
1048 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001049 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 Log.w(TAG, "Activity idle timeout for " + token);
1051 activityIdleInternal(token, true);
1052 } break;
1053 case DESTROY_TIMEOUT_MSG: {
1054 IBinder token = (IBinder)msg.obj;
1055 // We don't at this point know if the activity is fullscreen,
1056 // so we need to be conservative and assume it isn't.
1057 Log.w(TAG, "Activity destroy timeout for " + token);
1058 activityDestroyed(token);
1059 } break;
1060 case IDLE_NOW_MSG: {
1061 IBinder token = (IBinder)msg.obj;
1062 activityIdle(token);
1063 } break;
1064 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001065 if (mDidDexOpt) {
1066 mDidDexOpt = false;
1067 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1068 nmsg.obj = msg.obj;
1069 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1070 return;
1071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 serviceTimeout((ProcessRecord)msg.obj);
1073 } break;
1074 case UPDATE_TIME_ZONE: {
1075 synchronized (ActivityManagerService.this) {
1076 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1077 ProcessRecord r = mLRUProcesses.get(i);
1078 if (r.thread != null) {
1079 try {
1080 r.thread.updateTimeZone();
1081 } catch (RemoteException ex) {
1082 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1083 }
1084 }
1085 }
1086 }
1087 break;
1088 }
1089 case SHOW_UID_ERROR_MSG: {
1090 // XXX This is a temporary dialog, no need to localize.
1091 AlertDialog d = new BaseErrorDialog(mContext);
1092 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1093 d.setCancelable(false);
1094 d.setTitle("System UIDs Inconsistent");
1095 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1096 d.setButton("I'm Feeling Lucky",
1097 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1098 mUidAlert = d;
1099 d.show();
1100 } break;
1101 case IM_FEELING_LUCKY_MSG: {
1102 if (mUidAlert != null) {
1103 mUidAlert.dismiss();
1104 mUidAlert = null;
1105 }
1106 } break;
1107 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001108 if (mDidDexOpt) {
1109 mDidDexOpt = false;
1110 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1111 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1112 return;
1113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 synchronized (ActivityManagerService.this) {
1115 if (mLaunchingActivity.isHeld()) {
1116 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1117 mLaunchingActivity.release();
1118 }
1119 }
1120 } break;
1121 case SERVICE_ERROR_MSG: {
1122 ServiceRecord srv = (ServiceRecord)msg.obj;
1123 // This needs to be *un*synchronized to avoid deadlock.
1124 Checkin.logEvent(mContext.getContentResolver(),
1125 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1126 srv.name.toShortString());
1127 } break;
1128 case RESUME_TOP_ACTIVITY_MSG: {
1129 synchronized (ActivityManagerService.this) {
1130 resumeTopActivityLocked(null);
1131 }
1132 }
1133 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001134 if (mDidDexOpt) {
1135 mDidDexOpt = false;
1136 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1137 nmsg.obj = msg.obj;
1138 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1139 return;
1140 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 ProcessRecord app = (ProcessRecord)msg.obj;
1142 synchronized (ActivityManagerService.this) {
1143 processStartTimedOutLocked(app);
1144 }
1145 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001146 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1147 synchronized (ActivityManagerService.this) {
1148 doPendingActivityLaunchesLocked(true);
1149 }
1150 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 }
1152 }
1153 };
1154
1155 public static void setSystemProcess() {
1156 try {
1157 ActivityManagerService m = mSelf;
1158
1159 ServiceManager.addService("activity", m);
1160 ServiceManager.addService("meminfo", new MemBinder(m));
1161 if (MONITOR_CPU_USAGE) {
1162 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1163 }
1164 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1165 ServiceManager.addService("activity.services", new ServicesBinder(m));
1166 ServiceManager.addService("activity.senders", new SendersBinder(m));
1167 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1168 ServiceManager.addService("permission", new PermissionController(m));
1169
1170 ApplicationInfo info =
1171 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001172 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 synchronized (mSelf) {
1174 ProcessRecord app = mSelf.newProcessRecordLocked(
1175 mSystemThread.getApplicationThread(), info,
1176 info.processName);
1177 app.persistent = true;
1178 app.pid = Process.myPid();
1179 app.maxAdj = SYSTEM_ADJ;
1180 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1181 synchronized (mSelf.mPidsSelfLocked) {
1182 mSelf.mPidsSelfLocked.put(app.pid, app);
1183 }
1184 mSelf.updateLRUListLocked(app, true);
1185 }
1186 } catch (PackageManager.NameNotFoundException e) {
1187 throw new RuntimeException(
1188 "Unable to find android system package", e);
1189 }
1190 }
1191
1192 public void setWindowManager(WindowManagerService wm) {
1193 mWindowManager = wm;
1194 }
1195
1196 public static final Context main(int factoryTest) {
1197 AThread thr = new AThread();
1198 thr.start();
1199
1200 synchronized (thr) {
1201 while (thr.mService == null) {
1202 try {
1203 thr.wait();
1204 } catch (InterruptedException e) {
1205 }
1206 }
1207 }
1208
1209 ActivityManagerService m = thr.mService;
1210 mSelf = m;
1211 ActivityThread at = ActivityThread.systemMain();
1212 mSystemThread = at;
1213 Context context = at.getSystemContext();
1214 m.mContext = context;
1215 m.mFactoryTest = factoryTest;
1216 PowerManager pm =
1217 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1218 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1219 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1220 m.mLaunchingActivity.setReferenceCounted(false);
1221
1222 m.mBatteryStatsService.publish(context);
1223 m.mUsageStatsService.publish(context);
1224
1225 synchronized (thr) {
1226 thr.mReady = true;
1227 thr.notifyAll();
1228 }
1229
1230 m.startRunning(null, null, null, null);
1231
1232 return context;
1233 }
1234
1235 public static ActivityManagerService self() {
1236 return mSelf;
1237 }
1238
1239 static class AThread extends Thread {
1240 ActivityManagerService mService;
1241 boolean mReady = false;
1242
1243 public AThread() {
1244 super("ActivityManager");
1245 }
1246
1247 public void run() {
1248 Looper.prepare();
1249
1250 android.os.Process.setThreadPriority(
1251 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1252
1253 ActivityManagerService m = new ActivityManagerService();
1254
1255 synchronized (this) {
1256 mService = m;
1257 notifyAll();
1258 }
1259
1260 synchronized (this) {
1261 while (!mReady) {
1262 try {
1263 wait();
1264 } catch (InterruptedException e) {
1265 }
1266 }
1267 }
1268
1269 Looper.loop();
1270 }
1271 }
1272
1273 static class BroadcastsBinder extends Binder {
1274 ActivityManagerService mActivityManagerService;
1275 BroadcastsBinder(ActivityManagerService activityManagerService) {
1276 mActivityManagerService = activityManagerService;
1277 }
1278
1279 @Override
1280 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1281 mActivityManagerService.dumpBroadcasts(pw);
1282 }
1283 }
1284
1285 static class ServicesBinder extends Binder {
1286 ActivityManagerService mActivityManagerService;
1287 ServicesBinder(ActivityManagerService activityManagerService) {
1288 mActivityManagerService = activityManagerService;
1289 }
1290
1291 @Override
1292 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1293 mActivityManagerService.dumpServices(pw);
1294 }
1295 }
1296
1297 static class SendersBinder extends Binder {
1298 ActivityManagerService mActivityManagerService;
1299 SendersBinder(ActivityManagerService activityManagerService) {
1300 mActivityManagerService = activityManagerService;
1301 }
1302
1303 @Override
1304 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1305 mActivityManagerService.dumpSenders(pw);
1306 }
1307 }
1308
1309 static class ProvidersBinder extends Binder {
1310 ActivityManagerService mActivityManagerService;
1311 ProvidersBinder(ActivityManagerService activityManagerService) {
1312 mActivityManagerService = activityManagerService;
1313 }
1314
1315 @Override
1316 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1317 mActivityManagerService.dumpProviders(pw);
1318 }
1319 }
1320
1321 static class MemBinder extends Binder {
1322 ActivityManagerService mActivityManagerService;
1323 MemBinder(ActivityManagerService activityManagerService) {
1324 mActivityManagerService = activityManagerService;
1325 }
1326
1327 @Override
1328 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1329 ActivityManagerService service = mActivityManagerService;
1330 ArrayList<ProcessRecord> procs;
1331 synchronized (mActivityManagerService) {
1332 if (args != null && args.length > 0
1333 && args[0].charAt(0) != '-') {
1334 procs = new ArrayList<ProcessRecord>();
1335 int pid = -1;
1336 try {
1337 pid = Integer.parseInt(args[0]);
1338 } catch (NumberFormatException e) {
1339
1340 }
1341 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1342 ProcessRecord proc = service.mLRUProcesses.get(i);
1343 if (proc.pid == pid) {
1344 procs.add(proc);
1345 } else if (proc.processName.equals(args[0])) {
1346 procs.add(proc);
1347 }
1348 }
1349 if (procs.size() <= 0) {
1350 pw.println("No process found for: " + args[0]);
1351 return;
1352 }
1353 } else {
1354 procs = service.mLRUProcesses;
1355 }
1356 }
1357 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1358 }
1359 }
1360
1361 static class CpuBinder extends Binder {
1362 ActivityManagerService mActivityManagerService;
1363 CpuBinder(ActivityManagerService activityManagerService) {
1364 mActivityManagerService = activityManagerService;
1365 }
1366
1367 @Override
1368 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1369 synchronized (mActivityManagerService.mProcessStatsThread) {
1370 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1371 }
1372 }
1373 }
1374
1375 private ActivityManagerService() {
1376 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1377 if (v != null && Integer.getInteger(v) != 0) {
1378 mSimpleProcessManagement = true;
1379 }
1380 v = System.getenv("ANDROID_DEBUG_APP");
1381 if (v != null) {
1382 mSimpleProcessManagement = true;
1383 }
1384
1385 MY_PID = Process.myPid();
1386
1387 File dataDir = Environment.getDataDirectory();
1388 File systemDir = new File(dataDir, "system");
1389 systemDir.mkdirs();
1390 mBatteryStatsService = new BatteryStatsService(new File(
1391 systemDir, "batterystats.bin").toString());
1392 mBatteryStatsService.getActiveStatistics().readLocked();
1393 mBatteryStatsService.getActiveStatistics().writeLocked();
1394
1395 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001396 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397
1398 mConfiguration.makeDefault();
1399 mProcessStats.init();
1400
1401 // Add ourself to the Watchdog monitors.
1402 Watchdog.getInstance().addMonitor(this);
1403
1404 // These values are set in system/rootdir/init.rc on startup.
1405 FOREGROUND_APP_ADJ =
1406 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1407 VISIBLE_APP_ADJ =
1408 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1409 SECONDARY_SERVER_ADJ =
1410 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001411 BACKUP_APP_ADJ =
1412 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001413 HOME_APP_ADJ =
1414 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 HIDDEN_APP_MIN_ADJ =
1416 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1417 CONTENT_PROVIDER_ADJ =
1418 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1419 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1420 EMPTY_APP_ADJ =
1421 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1422 FOREGROUND_APP_MEM =
1423 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1424 VISIBLE_APP_MEM =
1425 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1426 SECONDARY_SERVER_MEM =
1427 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001428 BACKUP_APP_MEM =
1429 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001430 HOME_APP_MEM =
1431 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 HIDDEN_APP_MEM =
1433 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1434 EMPTY_APP_MEM =
1435 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1436
1437 mProcessStatsThread = new Thread("ProcessStats") {
1438 public void run() {
1439 while (true) {
1440 try {
1441 try {
1442 synchronized(this) {
1443 final long now = SystemClock.uptimeMillis();
1444 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1445 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1446 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1447 // + ", write delay=" + nextWriteDelay);
1448 if (nextWriteDelay < nextCpuDelay) {
1449 nextCpuDelay = nextWriteDelay;
1450 }
1451 if (nextCpuDelay > 0) {
1452 this.wait(nextCpuDelay);
1453 }
1454 }
1455 } catch (InterruptedException e) {
1456 }
1457
1458 updateCpuStatsNow();
1459 } catch (Exception e) {
1460 Log.e(TAG, "Unexpected exception collecting process stats", e);
1461 }
1462 }
1463 }
1464 };
1465 mProcessStatsThread.start();
1466 }
1467
1468 @Override
1469 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1470 throws RemoteException {
1471 try {
1472 return super.onTransact(code, data, reply, flags);
1473 } catch (RuntimeException e) {
1474 // The activity manager only throws security exceptions, so let's
1475 // log all others.
1476 if (!(e instanceof SecurityException)) {
1477 Log.e(TAG, "Activity Manager Crash", e);
1478 }
1479 throw e;
1480 }
1481 }
1482
1483 void updateCpuStats() {
1484 synchronized (mProcessStatsThread) {
1485 final long now = SystemClock.uptimeMillis();
1486 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1487 mProcessStatsThread.notify();
1488 }
1489 }
1490 }
1491
1492 void updateCpuStatsNow() {
1493 synchronized (mProcessStatsThread) {
1494 final long now = SystemClock.uptimeMillis();
1495 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 if (MONITOR_CPU_USAGE &&
1498 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1499 mLastCpuTime = now;
1500 haveNewCpuStats = true;
1501 mProcessStats.update();
1502 //Log.i(TAG, mProcessStats.printCurrentState());
1503 //Log.i(TAG, "Total CPU usage: "
1504 // + mProcessStats.getTotalCpuPercent() + "%");
1505
1506 // Log the cpu usage if the property is set.
1507 if ("true".equals(SystemProperties.get("events.cpu"))) {
1508 int user = mProcessStats.getLastUserTime();
1509 int system = mProcessStats.getLastSystemTime();
1510 int iowait = mProcessStats.getLastIoWaitTime();
1511 int irq = mProcessStats.getLastIrqTime();
1512 int softIrq = mProcessStats.getLastSoftIrqTime();
1513 int idle = mProcessStats.getLastIdleTime();
1514
1515 int total = user + system + iowait + irq + softIrq + idle;
1516 if (total == 0) total = 1;
1517
1518 EventLog.writeEvent(LOG_CPU,
1519 ((user+system+iowait+irq+softIrq) * 100) / total,
1520 (user * 100) / total,
1521 (system * 100) / total,
1522 (iowait * 100) / total,
1523 (irq * 100) / total,
1524 (softIrq * 100) / total);
1525 }
1526 }
1527
Amith Yamasani819f9282009-06-24 23:18:15 -07001528 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001529 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 synchronized(mPidsSelfLocked) {
1531 if (haveNewCpuStats) {
1532 if (mBatteryStatsService.isOnBattery()) {
1533 final int N = mProcessStats.countWorkingStats();
1534 for (int i=0; i<N; i++) {
1535 ProcessStats.Stats st
1536 = mProcessStats.getWorkingStats(i);
1537 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1538 if (pr != null) {
1539 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1540 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001541 } else {
1542 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001543 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001544 if (ps != null) {
1545 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
1548 }
1549 }
1550 }
1551 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1554 mLastWriteTime = now;
1555 mBatteryStatsService.getActiveStatistics().writeLocked();
1556 }
1557 }
1558 }
1559 }
1560
1561 /**
1562 * Initialize the application bind args. These are passed to each
1563 * process when the bindApplication() IPC is sent to the process. They're
1564 * lazily setup to make sure the services are running when they're asked for.
1565 */
1566 private HashMap<String, IBinder> getCommonServicesLocked() {
1567 if (mAppBindArgs == null) {
1568 mAppBindArgs = new HashMap<String, IBinder>();
1569
1570 // Setup the application init args
1571 mAppBindArgs.put("package", ServiceManager.getService("package"));
1572 mAppBindArgs.put("window", ServiceManager.getService("window"));
1573 mAppBindArgs.put(Context.ALARM_SERVICE,
1574 ServiceManager.getService(Context.ALARM_SERVICE));
1575 }
1576 return mAppBindArgs;
1577 }
1578
1579 private final void setFocusedActivityLocked(HistoryRecord r) {
1580 if (mFocusedActivity != r) {
1581 mFocusedActivity = r;
1582 mWindowManager.setFocusedApp(r, true);
1583 }
1584 }
1585
1586 private final void updateLRUListLocked(ProcessRecord app,
1587 boolean oomAdj) {
1588 // put it on the LRU to keep track of when it should be exited.
1589 int lrui = mLRUProcesses.indexOf(app);
1590 if (lrui >= 0) mLRUProcesses.remove(lrui);
1591 mLRUProcesses.add(app);
1592 //Log.i(TAG, "Putting proc to front: " + app.processName);
1593 if (oomAdj) {
1594 updateOomAdjLocked();
1595 }
1596 }
1597
1598 private final boolean updateLRUListLocked(HistoryRecord r) {
1599 final boolean hadit = mLRUActivities.remove(r);
1600 mLRUActivities.add(r);
1601 return hadit;
1602 }
1603
1604 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1605 int i = mHistory.size()-1;
1606 while (i >= 0) {
1607 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1608 if (!r.finishing && r != notTop) {
1609 return r;
1610 }
1611 i--;
1612 }
1613 return null;
1614 }
1615
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001616 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1617 int i = mHistory.size()-1;
1618 while (i >= 0) {
1619 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1620 if (!r.finishing && !r.delayedResume && r != notTop) {
1621 return r;
1622 }
1623 i--;
1624 }
1625 return null;
1626 }
1627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 /**
1629 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001630 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 *
1632 * @param token If non-null, any history records matching this token will be skipped.
1633 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1634 *
1635 * @return Returns the HistoryRecord of the next activity on the stack.
1636 */
1637 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1638 int i = mHistory.size()-1;
1639 while (i >= 0) {
1640 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1641 // Note: the taskId check depends on real taskId fields being non-zero
1642 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1643 return r;
1644 }
1645 i--;
1646 }
1647 return null;
1648 }
1649
1650 private final ProcessRecord getProcessRecordLocked(
1651 String processName, int uid) {
1652 if (uid == Process.SYSTEM_UID) {
1653 // The system gets to run in any process. If there are multiple
1654 // processes with the same uid, just pick the first (this
1655 // should never happen).
1656 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1657 processName);
1658 return procs != null ? procs.valueAt(0) : null;
1659 }
1660 ProcessRecord proc = mProcessNames.get(processName, uid);
1661 return proc;
1662 }
1663
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001664 private void ensurePackageDexOpt(String packageName) {
1665 IPackageManager pm = ActivityThread.getPackageManager();
1666 try {
1667 if (pm.performDexOpt(packageName)) {
1668 mDidDexOpt = true;
1669 }
1670 } catch (RemoteException e) {
1671 }
1672 }
1673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 private boolean isNextTransitionForward() {
1675 int transit = mWindowManager.getPendingAppTransition();
1676 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1677 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1678 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1679 }
1680
1681 private final boolean realStartActivityLocked(HistoryRecord r,
1682 ProcessRecord app, boolean andResume, boolean checkConfig)
1683 throws RemoteException {
1684
1685 r.startFreezingScreenLocked(app, 0);
1686 mWindowManager.setAppVisibility(r, true);
1687
1688 // Have the window manager re-evaluate the orientation of
1689 // the screen based on the new activity order. Note that
1690 // as a result of this, it can call back into the activity
1691 // manager with a new orientation. We don't care about that,
1692 // because the activity is not currently running so we are
1693 // just restarting it anyway.
1694 if (checkConfig) {
1695 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001696 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 r.mayFreezeScreenLocked(app) ? r : null);
1698 updateConfigurationLocked(config, r);
1699 }
1700
1701 r.app = app;
1702
1703 if (localLOGV) Log.v(TAG, "Launching: " + r);
1704
1705 int idx = app.activities.indexOf(r);
1706 if (idx < 0) {
1707 app.activities.add(r);
1708 }
1709 updateLRUListLocked(app, true);
1710
1711 try {
1712 if (app.thread == null) {
1713 throw new RemoteException();
1714 }
1715 List<ResultInfo> results = null;
1716 List<Intent> newIntents = null;
1717 if (andResume) {
1718 results = r.results;
1719 newIntents = r.newIntents;
1720 }
1721 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1722 + " icicle=" + r.icicle
1723 + " with results=" + results + " newIntents=" + newIntents
1724 + " andResume=" + andResume);
1725 if (andResume) {
1726 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1727 System.identityHashCode(r),
1728 r.task.taskId, r.shortComponentName);
1729 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001730 if (r.isHomeActivity) {
1731 mHomeProcess = app;
1732 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001733 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001735 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 r.info, r.icicle, results, newIntents, !andResume,
1737 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 } catch (RemoteException e) {
1739 if (r.launchFailed) {
1740 // This is the second time we failed -- finish activity
1741 // and give up.
1742 Log.e(TAG, "Second failure launching "
1743 + r.intent.getComponent().flattenToShortString()
1744 + ", giving up", e);
1745 appDiedLocked(app, app.pid, app.thread);
1746 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1747 "2nd-crash");
1748 return false;
1749 }
1750
1751 // This is the first time we failed -- restart process and
1752 // retry.
1753 app.activities.remove(r);
1754 throw e;
1755 }
1756
1757 r.launchFailed = false;
1758 if (updateLRUListLocked(r)) {
1759 Log.w(TAG, "Activity " + r
1760 + " being launched, but already in LRU list");
1761 }
1762
1763 if (andResume) {
1764 // As part of the process of launching, ActivityThread also performs
1765 // a resume.
1766 r.state = ActivityState.RESUMED;
1767 r.icicle = null;
1768 r.haveState = false;
1769 r.stopped = false;
1770 mResumedActivity = r;
1771 r.task.touchActiveTime();
1772 completeResumeLocked(r);
1773 pauseIfSleepingLocked();
1774 } else {
1775 // This activity is not starting in the resumed state... which
1776 // should look like we asked it to pause+stop (but remain visible),
1777 // and it has done so and reported back the current icicle and
1778 // other state.
1779 r.state = ActivityState.STOPPED;
1780 r.stopped = true;
1781 }
1782
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001783 // Launch the new version setup screen if needed. We do this -after-
1784 // launching the initial activity (that is, home), so that it can have
1785 // a chance to initialize itself while in the background, making the
1786 // switch back to it faster and look better.
1787 startSetupActivityLocked();
1788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 return true;
1790 }
1791
1792 private final void startSpecificActivityLocked(HistoryRecord r,
1793 boolean andResume, boolean checkConfig) {
1794 // Is this activity's application already running?
1795 ProcessRecord app = getProcessRecordLocked(r.processName,
1796 r.info.applicationInfo.uid);
1797
1798 if (r.startTime == 0) {
1799 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001800 if (mInitialStartTime == 0) {
1801 mInitialStartTime = r.startTime;
1802 }
1803 } else if (mInitialStartTime == 0) {
1804 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 }
1806
1807 if (app != null && app.thread != null) {
1808 try {
1809 realStartActivityLocked(r, app, andResume, checkConfig);
1810 return;
1811 } catch (RemoteException e) {
1812 Log.w(TAG, "Exception when starting activity "
1813 + r.intent.getComponent().flattenToShortString(), e);
1814 }
1815
1816 // If a dead object exception was thrown -- fall through to
1817 // restart the application.
1818 }
1819
1820 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1821 "activity", r.intent.getComponent());
1822 }
1823
1824 private final ProcessRecord startProcessLocked(String processName,
1825 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1826 String hostingType, ComponentName hostingName) {
1827 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1828 // We don't have to do anything more if:
1829 // (1) There is an existing application record; and
1830 // (2) The caller doesn't think it is dead, OR there is no thread
1831 // object attached to it so we know it couldn't have crashed; and
1832 // (3) There is a pid assigned to it, so it is either starting or
1833 // already running.
1834 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1835 + " app=" + app + " knownToBeDead=" + knownToBeDead
1836 + " thread=" + (app != null ? app.thread : null)
1837 + " pid=" + (app != null ? app.pid : -1));
1838 if (app != null &&
1839 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1840 return app;
1841 }
1842
1843 String hostingNameStr = hostingName != null
1844 ? hostingName.flattenToShortString() : null;
1845
1846 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1847 // If we are in the background, then check to see if this process
1848 // is bad. If so, we will just silently fail.
1849 if (mBadProcesses.get(info.processName, info.uid) != null) {
1850 return null;
1851 }
1852 } else {
1853 // When the user is explicitly starting a process, then clear its
1854 // crash count so that we won't make it bad until they see at
1855 // least one crash dialog again, and make the process good again
1856 // if it had been bad.
1857 mProcessCrashTimes.remove(info.processName, info.uid);
1858 if (mBadProcesses.get(info.processName, info.uid) != null) {
1859 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1860 info.processName);
1861 mBadProcesses.remove(info.processName, info.uid);
1862 if (app != null) {
1863 app.bad = false;
1864 }
1865 }
1866 }
1867
1868 if (app == null) {
1869 app = newProcessRecordLocked(null, info, processName);
1870 mProcessNames.put(processName, info.uid, app);
1871 } else {
1872 // If this is a new package in the process, add the package to the list
1873 app.addPackage(info.packageName);
1874 }
1875
1876 // If the system is not ready yet, then hold off on starting this
1877 // process until it is.
1878 if (!mSystemReady
1879 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1880 if (!mProcessesOnHold.contains(app)) {
1881 mProcessesOnHold.add(app);
1882 }
1883 return app;
1884 }
1885
1886 startProcessLocked(app, hostingType, hostingNameStr);
1887 return (app.pid != 0) ? app : null;
1888 }
1889
1890 private final void startProcessLocked(ProcessRecord app,
1891 String hostingType, String hostingNameStr) {
1892 if (app.pid > 0 && app.pid != MY_PID) {
1893 synchronized (mPidsSelfLocked) {
1894 mPidsSelfLocked.remove(app.pid);
1895 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1896 }
1897 app.pid = 0;
1898 }
1899
1900 mProcessesOnHold.remove(app);
1901
1902 updateCpuStats();
1903
1904 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1905 mProcDeaths[0] = 0;
1906
1907 try {
1908 int uid = app.info.uid;
1909 int[] gids = null;
1910 try {
1911 gids = mContext.getPackageManager().getPackageGids(
1912 app.info.packageName);
1913 } catch (PackageManager.NameNotFoundException e) {
1914 Log.w(TAG, "Unable to retrieve gids", e);
1915 }
1916 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1917 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1918 && mTopComponent != null
1919 && app.processName.equals(mTopComponent.getPackageName())) {
1920 uid = 0;
1921 }
1922 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1923 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1924 uid = 0;
1925 }
1926 }
1927 int debugFlags = 0;
1928 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1929 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1930 }
1931 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1932 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1933 }
1934 if ("1".equals(SystemProperties.get("debug.assert"))) {
1935 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1936 }
1937 int pid = Process.start("android.app.ActivityThread",
1938 mSimpleProcessManagement ? app.processName : null, uid, uid,
1939 gids, debugFlags, null);
1940 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1941 synchronized (bs) {
1942 if (bs.isOnBattery()) {
1943 app.batteryStats.incStartsLocked();
1944 }
1945 }
1946
1947 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1948 app.processName, hostingType,
1949 hostingNameStr != null ? hostingNameStr : "");
1950
1951 if (app.persistent) {
1952 Watchdog.getInstance().processStarted(app, app.processName, pid);
1953 }
1954
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001955 StringBuilder buf = mStringBuilder;
1956 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 buf.append("Start proc ");
1958 buf.append(app.processName);
1959 buf.append(" for ");
1960 buf.append(hostingType);
1961 if (hostingNameStr != null) {
1962 buf.append(" ");
1963 buf.append(hostingNameStr);
1964 }
1965 buf.append(": pid=");
1966 buf.append(pid);
1967 buf.append(" uid=");
1968 buf.append(uid);
1969 buf.append(" gids={");
1970 if (gids != null) {
1971 for (int gi=0; gi<gids.length; gi++) {
1972 if (gi != 0) buf.append(", ");
1973 buf.append(gids[gi]);
1974
1975 }
1976 }
1977 buf.append("}");
1978 Log.i(TAG, buf.toString());
1979 if (pid == 0 || pid == MY_PID) {
1980 // Processes are being emulated with threads.
1981 app.pid = MY_PID;
1982 app.removed = false;
1983 mStartingProcesses.add(app);
1984 } else if (pid > 0) {
1985 app.pid = pid;
1986 app.removed = false;
1987 synchronized (mPidsSelfLocked) {
1988 this.mPidsSelfLocked.put(pid, app);
1989 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1990 msg.obj = app;
1991 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1992 }
1993 } else {
1994 app.pid = 0;
1995 RuntimeException e = new RuntimeException(
1996 "Failure starting process " + app.processName
1997 + ": returned pid=" + pid);
1998 Log.e(TAG, e.getMessage(), e);
1999 }
2000 } catch (RuntimeException e) {
2001 // XXX do better error recovery.
2002 app.pid = 0;
2003 Log.e(TAG, "Failure starting process " + app.processName, e);
2004 }
2005 }
2006
2007 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2008 if (mPausingActivity != null) {
2009 RuntimeException e = new RuntimeException();
2010 Log.e(TAG, "Trying to pause when pause is already pending for "
2011 + mPausingActivity, e);
2012 }
2013 HistoryRecord prev = mResumedActivity;
2014 if (prev == null) {
2015 RuntimeException e = new RuntimeException();
2016 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2017 resumeTopActivityLocked(null);
2018 return;
2019 }
2020 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2021 mResumedActivity = null;
2022 mPausingActivity = prev;
2023 mLastPausedActivity = prev;
2024 prev.state = ActivityState.PAUSING;
2025 prev.task.touchActiveTime();
2026
2027 updateCpuStats();
2028
2029 if (prev.app != null && prev.app.thread != null) {
2030 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2031 try {
2032 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2033 System.identityHashCode(prev),
2034 prev.shortComponentName);
2035 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2036 prev.configChangeFlags);
2037 updateUsageStats(prev, false);
2038 } catch (Exception e) {
2039 // Ignore exception, if process died other code will cleanup.
2040 Log.w(TAG, "Exception thrown during pause", e);
2041 mPausingActivity = null;
2042 mLastPausedActivity = null;
2043 }
2044 } else {
2045 mPausingActivity = null;
2046 mLastPausedActivity = null;
2047 }
2048
2049 // If we are not going to sleep, we want to ensure the device is
2050 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002051 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 mLaunchingActivity.acquire();
2053 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2054 // To be safe, don't allow the wake lock to be held for too long.
2055 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2056 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2057 }
2058 }
2059
2060
2061 if (mPausingActivity != null) {
2062 // Have the window manager pause its key dispatching until the new
2063 // activity has started. If we're pausing the activity just because
2064 // the screen is being turned off and the UI is sleeping, don't interrupt
2065 // key dispatch; the same activity will pick it up again on wakeup.
2066 if (!uiSleeping) {
2067 prev.pauseKeyDispatchingLocked();
2068 } else {
2069 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2070 }
2071
2072 // Schedule a pause timeout in case the app doesn't respond.
2073 // We don't give it much time because this directly impacts the
2074 // responsiveness seen by the user.
2075 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2076 msg.obj = prev;
2077 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2078 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2079 } else {
2080 // This activity failed to schedule the
2081 // pause, so just treat it as being paused now.
2082 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2083 resumeTopActivityLocked(null);
2084 }
2085 }
2086
2087 private final void completePauseLocked() {
2088 HistoryRecord prev = mPausingActivity;
2089 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2090
2091 if (prev != null) {
2092 if (prev.finishing) {
2093 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2094 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2095 } else if (prev.app != null) {
2096 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2097 if (prev.waitingVisible) {
2098 prev.waitingVisible = false;
2099 mWaitingVisibleActivities.remove(prev);
2100 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2101 TAG, "Complete pause, no longer waiting: " + prev);
2102 }
2103 if (prev.configDestroy) {
2104 // The previous is being paused because the configuration
2105 // is changing, which means it is actually stopping...
2106 // To juggle the fact that we are also starting a new
2107 // instance right now, we need to first completely stop
2108 // the current instance before starting the new one.
2109 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2110 destroyActivityLocked(prev, true);
2111 } else {
2112 mStoppingActivities.add(prev);
2113 if (mStoppingActivities.size() > 3) {
2114 // If we already have a few activities waiting to stop,
2115 // then give up on things going idle and start clearing
2116 // them out.
2117 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2118 Message msg = Message.obtain();
2119 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2120 mHandler.sendMessage(msg);
2121 }
2122 }
2123 } else {
2124 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2125 prev = null;
2126 }
2127 mPausingActivity = null;
2128 }
2129
Dianne Hackborn55280a92009-05-07 15:53:46 -07002130 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 resumeTopActivityLocked(prev);
2132 } else {
2133 if (mGoingToSleep.isHeld()) {
2134 mGoingToSleep.release();
2135 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002136 if (mShuttingDown) {
2137 notifyAll();
2138 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 }
2140
2141 if (prev != null) {
2142 prev.resumeKeyDispatchingLocked();
2143 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002144
2145 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2146 long diff = 0;
2147 synchronized (mProcessStatsThread) {
2148 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2149 }
2150 if (diff > 0) {
2151 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2152 synchronized (bsi) {
2153 BatteryStatsImpl.Uid.Proc ps =
2154 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2155 prev.info.packageName);
2156 if (ps != null) {
2157 ps.addForegroundTimeLocked(diff);
2158 }
2159 }
2160 }
2161 }
2162 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
2164
2165 /**
2166 * Once we know that we have asked an application to put an activity in
2167 * the resumed state (either by launching it or explicitly telling it),
2168 * this function updates the rest of our state to match that fact.
2169 */
2170 private final void completeResumeLocked(HistoryRecord next) {
2171 next.idle = false;
2172 next.results = null;
2173 next.newIntents = null;
2174
2175 // schedule an idle timeout in case the app doesn't do it for us.
2176 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2177 msg.obj = next;
2178 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2179
2180 if (false) {
2181 // The activity was never told to pause, so just keep
2182 // things going as-is. To maintain our own state,
2183 // we need to emulate it coming back and saying it is
2184 // idle.
2185 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2186 msg.obj = next;
2187 mHandler.sendMessage(msg);
2188 }
2189
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002190 reportResumedActivity(next);
2191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 next.thumbnail = null;
2193 setFocusedActivityLocked(next);
2194 next.resumeKeyDispatchingLocked();
2195 ensureActivitiesVisibleLocked(null, 0);
2196 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002197
2198 // Mark the point when the activity is resuming
2199 // TODO: To be more accurate, the mark should be before the onCreate,
2200 // not after the onResume. But for subsequent starts, onResume is fine.
2201 if (next.app != null) {
2202 synchronized (mProcessStatsThread) {
2203 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2204 }
2205 } else {
2206 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 }
2209
2210 /**
2211 * Make sure that all activities that need to be visible (that is, they
2212 * currently can be seen by the user) actually are.
2213 */
2214 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2215 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2216 if (DEBUG_VISBILITY) Log.v(
2217 TAG, "ensureActivitiesVisible behind " + top
2218 + " configChanges=0x" + Integer.toHexString(configChanges));
2219
2220 // If the top activity is not fullscreen, then we need to
2221 // make sure any activities under it are now visible.
2222 final int count = mHistory.size();
2223 int i = count-1;
2224 while (mHistory.get(i) != top) {
2225 i--;
2226 }
2227 HistoryRecord r;
2228 boolean behindFullscreen = false;
2229 for (; i>=0; i--) {
2230 r = (HistoryRecord)mHistory.get(i);
2231 if (DEBUG_VISBILITY) Log.v(
2232 TAG, "Make visible? " + r + " finishing=" + r.finishing
2233 + " state=" + r.state);
2234 if (r.finishing) {
2235 continue;
2236 }
2237
2238 final boolean doThisProcess = onlyThisProcess == null
2239 || onlyThisProcess.equals(r.processName);
2240
2241 // First: if this is not the current activity being started, make
2242 // sure it matches the current configuration.
2243 if (r != starting && doThisProcess) {
2244 ensureActivityConfigurationLocked(r, 0);
2245 }
2246
2247 if (r.app == null || r.app.thread == null) {
2248 if (onlyThisProcess == null
2249 || onlyThisProcess.equals(r.processName)) {
2250 // This activity needs to be visible, but isn't even
2251 // running... get it started, but don't resume it
2252 // at this point.
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "Start and freeze screen for " + r);
2255 if (r != starting) {
2256 r.startFreezingScreenLocked(r.app, configChanges);
2257 }
2258 if (!r.visible) {
2259 if (DEBUG_VISBILITY) Log.v(
2260 TAG, "Starting and making visible: " + r);
2261 mWindowManager.setAppVisibility(r, true);
2262 }
2263 if (r != starting) {
2264 startSpecificActivityLocked(r, false, false);
2265 }
2266 }
2267
2268 } else if (r.visible) {
2269 // If this activity is already visible, then there is nothing
2270 // else to do here.
2271 if (DEBUG_VISBILITY) Log.v(
2272 TAG, "Skipping: already visible at " + r);
2273 r.stopFreezingScreenLocked(false);
2274
2275 } else if (onlyThisProcess == null) {
2276 // This activity is not currently visible, but is running.
2277 // Tell it to become visible.
2278 r.visible = true;
2279 if (r.state != ActivityState.RESUMED && r != starting) {
2280 // If this activity is paused, tell it
2281 // to now show its window.
2282 if (DEBUG_VISBILITY) Log.v(
2283 TAG, "Making visible and scheduling visibility: " + r);
2284 try {
2285 mWindowManager.setAppVisibility(r, true);
2286 r.app.thread.scheduleWindowVisibility(r, true);
2287 r.stopFreezingScreenLocked(false);
2288 } catch (Exception e) {
2289 // Just skip on any failure; we'll make it
2290 // visible when it next restarts.
2291 Log.w(TAG, "Exception thrown making visibile: "
2292 + r.intent.getComponent(), e);
2293 }
2294 }
2295 }
2296
2297 // Aggregate current change flags.
2298 configChanges |= r.configChangeFlags;
2299
2300 if (r.fullscreen) {
2301 // At this point, nothing else needs to be shown
2302 if (DEBUG_VISBILITY) Log.v(
2303 TAG, "Stopping: fullscreen at " + r);
2304 behindFullscreen = true;
2305 i--;
2306 break;
2307 }
2308 }
2309
2310 // Now for any activities that aren't visible to the user, make
2311 // sure they no longer are keeping the screen frozen.
2312 while (i >= 0) {
2313 r = (HistoryRecord)mHistory.get(i);
2314 if (DEBUG_VISBILITY) Log.v(
2315 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2316 + " state=" + r.state
2317 + " behindFullscreen=" + behindFullscreen);
2318 if (!r.finishing) {
2319 if (behindFullscreen) {
2320 if (r.visible) {
2321 if (DEBUG_VISBILITY) Log.v(
2322 TAG, "Making invisible: " + r);
2323 r.visible = false;
2324 try {
2325 mWindowManager.setAppVisibility(r, false);
2326 if ((r.state == ActivityState.STOPPING
2327 || r.state == ActivityState.STOPPED)
2328 && r.app != null && r.app.thread != null) {
2329 if (DEBUG_VISBILITY) Log.v(
2330 TAG, "Scheduling invisibility: " + r);
2331 r.app.thread.scheduleWindowVisibility(r, false);
2332 }
2333 } catch (Exception e) {
2334 // Just skip on any failure; we'll make it
2335 // visible when it next restarts.
2336 Log.w(TAG, "Exception thrown making hidden: "
2337 + r.intent.getComponent(), e);
2338 }
2339 } else {
2340 if (DEBUG_VISBILITY) Log.v(
2341 TAG, "Already invisible: " + r);
2342 }
2343 } else if (r.fullscreen) {
2344 if (DEBUG_VISBILITY) Log.v(
2345 TAG, "Now behindFullscreen: " + r);
2346 behindFullscreen = true;
2347 }
2348 }
2349 i--;
2350 }
2351 }
2352
2353 /**
2354 * Version of ensureActivitiesVisible that can easily be called anywhere.
2355 */
2356 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2357 int configChanges) {
2358 HistoryRecord r = topRunningActivityLocked(null);
2359 if (r != null) {
2360 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2361 }
2362 }
2363
2364 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2365 if (resumed) {
2366 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2367 } else {
2368 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2369 }
2370 }
2371
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002372 private boolean startHomeActivityLocked() {
2373 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2374 && mTopAction == null) {
2375 // We are running in factory test mode, but unable to find
2376 // the factory test app, so just sit around displaying the
2377 // error message and don't try to start anything.
2378 return false;
2379 }
2380 Intent intent = new Intent(
2381 mTopAction,
2382 mTopData != null ? Uri.parse(mTopData) : null);
2383 intent.setComponent(mTopComponent);
2384 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2385 intent.addCategory(Intent.CATEGORY_HOME);
2386 }
2387 ActivityInfo aInfo =
2388 intent.resolveActivityInfo(mContext.getPackageManager(),
2389 STOCK_PM_FLAGS);
2390 if (aInfo != null) {
2391 intent.setComponent(new ComponentName(
2392 aInfo.applicationInfo.packageName, aInfo.name));
2393 // Don't do this if the home app is currently being
2394 // instrumented.
2395 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2396 aInfo.applicationInfo.uid);
2397 if (app == null || app.instrumentationClass == null) {
2398 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2399 startActivityLocked(null, intent, null, null, 0, aInfo,
2400 null, null, 0, 0, 0, false, false);
2401 }
2402 }
2403
2404
2405 return true;
2406 }
2407
2408 /**
2409 * Starts the "new version setup screen" if appropriate.
2410 */
2411 private void startSetupActivityLocked() {
2412 // Only do this once per boot.
2413 if (mCheckedForSetup) {
2414 return;
2415 }
2416
2417 // We will show this screen if the current one is a different
2418 // version than the last one shown, and we are not running in
2419 // low-level factory test mode.
2420 final ContentResolver resolver = mContext.getContentResolver();
2421 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2422 Settings.Secure.getInt(resolver,
2423 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2424 mCheckedForSetup = true;
2425
2426 // See if we should be showing the platform update setup UI.
2427 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2428 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2429 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2430
2431 // We don't allow third party apps to replace this.
2432 ResolveInfo ri = null;
2433 for (int i=0; ris != null && i<ris.size(); i++) {
2434 if ((ris.get(i).activityInfo.applicationInfo.flags
2435 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2436 ri = ris.get(i);
2437 break;
2438 }
2439 }
2440
2441 if (ri != null) {
2442 String vers = ri.activityInfo.metaData != null
2443 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2444 : null;
2445 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2446 vers = ri.activityInfo.applicationInfo.metaData.getString(
2447 Intent.METADATA_SETUP_VERSION);
2448 }
2449 String lastVers = Settings.Secure.getString(
2450 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2451 if (vers != null && !vers.equals(lastVers)) {
2452 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2453 intent.setComponent(new ComponentName(
2454 ri.activityInfo.packageName, ri.activityInfo.name));
2455 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2456 null, null, 0, 0, 0, false, false);
2457 }
2458 }
2459 }
2460 }
2461
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002462 private void reportResumedActivity(HistoryRecord r) {
2463 //Log.i(TAG, "**** REPORT RESUME: " + r);
2464
2465 final int identHash = System.identityHashCode(r);
2466 updateUsageStats(r, true);
2467
2468 int i = mWatchers.beginBroadcast();
2469 while (i > 0) {
2470 i--;
2471 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2472 if (w != null) {
2473 try {
2474 w.activityResuming(identHash);
2475 } catch (RemoteException e) {
2476 }
2477 }
2478 }
2479 mWatchers.finishBroadcast();
2480 }
2481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002482 /**
2483 * Ensure that the top activity in the stack is resumed.
2484 *
2485 * @param prev The previously resumed activity, for when in the process
2486 * of pausing; can be null to call from elsewhere.
2487 *
2488 * @return Returns true if something is being resumed, or false if
2489 * nothing happened.
2490 */
2491 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2492 // Find the first activity that is not finishing.
2493 HistoryRecord next = topRunningActivityLocked(null);
2494
2495 // Remember how we'll process this pause/resume situation, and ensure
2496 // that the state is reset however we wind up proceeding.
2497 final boolean userLeaving = mUserLeaving;
2498 mUserLeaving = false;
2499
2500 if (next == null) {
2501 // There are no more activities! Let's just start up the
2502 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002503 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 }
2505
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002506 next.delayedResume = false;
2507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002508 // If the top activity is the resumed one, nothing to do.
2509 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2510 // Make sure we have executed any pending transitions, since there
2511 // should be nothing left to do at this point.
2512 mWindowManager.executeAppTransition();
2513 return false;
2514 }
2515
2516 // If we are sleeping, and there is no resumed activity, and the top
2517 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002518 if ((mSleeping || mShuttingDown)
2519 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002520 // Make sure we have executed any pending transitions, since there
2521 // should be nothing left to do at this point.
2522 mWindowManager.executeAppTransition();
2523 return false;
2524 }
2525
2526 // The activity may be waiting for stop, but that is no longer
2527 // appropriate for it.
2528 mStoppingActivities.remove(next);
2529 mWaitingVisibleActivities.remove(next);
2530
2531 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2532
2533 // If we are currently pausing an activity, then don't do anything
2534 // until that is done.
2535 if (mPausingActivity != null) {
2536 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2537 return false;
2538 }
2539
2540 // We need to start pausing the current activity so the top one
2541 // can be resumed...
2542 if (mResumedActivity != null) {
2543 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2544 startPausingLocked(userLeaving, false);
2545 return true;
2546 }
2547
2548 if (prev != null && prev != next) {
2549 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2550 prev.waitingVisible = true;
2551 mWaitingVisibleActivities.add(prev);
2552 if (DEBUG_SWITCH) Log.v(
2553 TAG, "Resuming top, waiting visible to hide: " + prev);
2554 } else {
2555 // The next activity is already visible, so hide the previous
2556 // activity's windows right now so we can show the new one ASAP.
2557 // We only do this if the previous is finishing, which should mean
2558 // it is on top of the one being resumed so hiding it quickly
2559 // is good. Otherwise, we want to do the normal route of allowing
2560 // the resumed activity to be shown so we can decide if the
2561 // previous should actually be hidden depending on whether the
2562 // new one is found to be full-screen or not.
2563 if (prev.finishing) {
2564 mWindowManager.setAppVisibility(prev, false);
2565 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2566 + prev + ", waitingVisible="
2567 + (prev != null ? prev.waitingVisible : null)
2568 + ", nowVisible=" + next.nowVisible);
2569 } else {
2570 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2571 + prev + ", waitingVisible="
2572 + (prev != null ? prev.waitingVisible : null)
2573 + ", nowVisible=" + next.nowVisible);
2574 }
2575 }
2576 }
2577
2578 // We are starting up the next activity, so tell the window manager
2579 // that the previous one will be hidden soon. This way it can know
2580 // to ignore it when computing the desired screen orientation.
2581 if (prev != null) {
2582 if (prev.finishing) {
2583 if (DEBUG_TRANSITION) Log.v(TAG,
2584 "Prepare close transition: prev=" + prev);
2585 mWindowManager.prepareAppTransition(prev.task == next.task
2586 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2587 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2588 mWindowManager.setAppWillBeHidden(prev);
2589 mWindowManager.setAppVisibility(prev, false);
2590 } else {
2591 if (DEBUG_TRANSITION) Log.v(TAG,
2592 "Prepare open transition: prev=" + prev);
2593 mWindowManager.prepareAppTransition(prev.task == next.task
2594 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2595 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2596 }
2597 if (false) {
2598 mWindowManager.setAppWillBeHidden(prev);
2599 mWindowManager.setAppVisibility(prev, false);
2600 }
2601 } else if (mHistory.size() > 1) {
2602 if (DEBUG_TRANSITION) Log.v(TAG,
2603 "Prepare open transition: no previous");
2604 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2605 }
2606
2607 if (next.app != null && next.app.thread != null) {
2608 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2609
2610 // This activity is now becoming visible.
2611 mWindowManager.setAppVisibility(next, true);
2612
2613 HistoryRecord lastResumedActivity = mResumedActivity;
2614 ActivityState lastState = next.state;
2615
2616 updateCpuStats();
2617
2618 next.state = ActivityState.RESUMED;
2619 mResumedActivity = next;
2620 next.task.touchActiveTime();
2621 updateLRUListLocked(next.app, true);
2622 updateLRUListLocked(next);
2623
2624 // Have the window manager re-evaluate the orientation of
2625 // the screen based on the new activity order.
2626 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002627 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 next.mayFreezeScreenLocked(next.app) ? next : null);
2629 if (config != null) {
2630 next.frozenBeforeDestroy = true;
2631 }
2632 if (!updateConfigurationLocked(config, next)) {
2633 // The configuration update wasn't able to keep the existing
2634 // instance of the activity, and instead started a new one.
2635 // We should be all done, but let's just make sure our activity
2636 // is still at the top and schedule another run if something
2637 // weird happened.
2638 HistoryRecord nextNext = topRunningActivityLocked(null);
2639 if (DEBUG_SWITCH) Log.i(TAG,
2640 "Activity config changed during resume: " + next
2641 + ", new next: " + nextNext);
2642 if (nextNext != next) {
2643 // Do over!
2644 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2645 }
2646 mWindowManager.executeAppTransition();
2647 return true;
2648 }
2649
2650 try {
2651 // Deliver all pending results.
2652 ArrayList a = next.results;
2653 if (a != null) {
2654 final int N = a.size();
2655 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002656 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 TAG, "Delivering results to " + next
2658 + ": " + a);
2659 next.app.thread.scheduleSendResult(next, a);
2660 }
2661 }
2662
2663 if (next.newIntents != null) {
2664 next.app.thread.scheduleNewIntent(next.newIntents, next);
2665 }
2666
2667 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2668 System.identityHashCode(next),
2669 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670
2671 next.app.thread.scheduleResumeActivity(next,
2672 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 pauseIfSleepingLocked();
2675
2676 } catch (Exception e) {
2677 // Whoops, need to restart this activity!
2678 next.state = lastState;
2679 mResumedActivity = lastResumedActivity;
2680 if (Config.LOGD) Log.d(TAG,
2681 "Restarting because process died: " + next);
2682 if (!next.hasBeenLaunched) {
2683 next.hasBeenLaunched = true;
2684 } else {
2685 if (SHOW_APP_STARTING_ICON) {
2686 mWindowManager.setAppStartingWindow(
2687 next, next.packageName, next.theme,
2688 next.nonLocalizedLabel,
2689 next.labelRes, next.icon, null, true);
2690 }
2691 }
2692 startSpecificActivityLocked(next, true, false);
2693 return true;
2694 }
2695
2696 // From this point on, if something goes wrong there is no way
2697 // to recover the activity.
2698 try {
2699 next.visible = true;
2700 completeResumeLocked(next);
2701 } catch (Exception e) {
2702 // If any exception gets thrown, toss away this
2703 // activity and try the next one.
2704 Log.w(TAG, "Exception thrown during resume of " + next, e);
2705 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2706 "resume-exception");
2707 return true;
2708 }
2709
2710 // Didn't need to use the icicle, and it is now out of date.
2711 next.icicle = null;
2712 next.haveState = false;
2713 next.stopped = false;
2714
2715 } else {
2716 // Whoops, need to restart this activity!
2717 if (!next.hasBeenLaunched) {
2718 next.hasBeenLaunched = true;
2719 } else {
2720 if (SHOW_APP_STARTING_ICON) {
2721 mWindowManager.setAppStartingWindow(
2722 next, next.packageName, next.theme,
2723 next.nonLocalizedLabel,
2724 next.labelRes, next.icon, null, true);
2725 }
2726 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2727 }
2728 startSpecificActivityLocked(next, true, true);
2729 }
2730
2731 return true;
2732 }
2733
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002734 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2735 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002736 final int NH = mHistory.size();
2737
2738 int addPos = -1;
2739
2740 if (!newTask) {
2741 // If starting in an existing task, find where that is...
2742 HistoryRecord next = null;
2743 boolean startIt = true;
2744 for (int i = NH-1; i >= 0; i--) {
2745 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2746 if (p.finishing) {
2747 continue;
2748 }
2749 if (p.task == r.task) {
2750 // Here it is! Now, if this is not yet visible to the
2751 // user, then just add it without starting; it will
2752 // get started when the user navigates back to it.
2753 addPos = i+1;
2754 if (!startIt) {
2755 mHistory.add(addPos, r);
2756 r.inHistory = true;
2757 r.task.numActivities++;
2758 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2759 r.info.screenOrientation, r.fullscreen);
2760 if (VALIDATE_TOKENS) {
2761 mWindowManager.validateAppTokens(mHistory);
2762 }
2763 return;
2764 }
2765 break;
2766 }
2767 if (p.fullscreen) {
2768 startIt = false;
2769 }
2770 next = p;
2771 }
2772 }
2773
2774 // Place a new activity at top of stack, so it is next to interact
2775 // with the user.
2776 if (addPos < 0) {
2777 addPos = mHistory.size();
2778 }
2779
2780 // If we are not placing the new activity frontmost, we do not want
2781 // to deliver the onUserLeaving callback to the actual frontmost
2782 // activity
2783 if (addPos < NH) {
2784 mUserLeaving = false;
2785 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2786 }
2787
2788 // Slot the activity into the history stack and proceed
2789 mHistory.add(addPos, r);
2790 r.inHistory = true;
2791 r.frontOfTask = newTask;
2792 r.task.numActivities++;
2793 if (NH > 0) {
2794 // We want to show the starting preview window if we are
2795 // switching to a new task, or the next activity's process is
2796 // not currently running.
2797 boolean showStartingIcon = newTask;
2798 ProcessRecord proc = r.app;
2799 if (proc == null) {
2800 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2801 }
2802 if (proc == null || proc.thread == null) {
2803 showStartingIcon = true;
2804 }
2805 if (DEBUG_TRANSITION) Log.v(TAG,
2806 "Prepare open transition: starting " + r);
2807 mWindowManager.prepareAppTransition(newTask
2808 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2809 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2810 mWindowManager.addAppToken(
2811 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2812 boolean doShow = true;
2813 if (newTask) {
2814 // Even though this activity is starting fresh, we still need
2815 // to reset it to make sure we apply affinities to move any
2816 // existing activities from other tasks in to it.
2817 // If the caller has requested that the target task be
2818 // reset, then do so.
2819 if ((r.intent.getFlags()
2820 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2821 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002822 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823 }
2824 }
2825 if (SHOW_APP_STARTING_ICON && doShow) {
2826 // Figure out if we are transitioning from another activity that is
2827 // "has the same starting icon" as the next one. This allows the
2828 // window manager to keep the previous window it had previously
2829 // created, if it still had one.
2830 HistoryRecord prev = mResumedActivity;
2831 if (prev != null) {
2832 // We don't want to reuse the previous starting preview if:
2833 // (1) The current activity is in a different task.
2834 if (prev.task != r.task) prev = null;
2835 // (2) The current activity is already displayed.
2836 else if (prev.nowVisible) prev = null;
2837 }
2838 mWindowManager.setAppStartingWindow(
2839 r, r.packageName, r.theme, r.nonLocalizedLabel,
2840 r.labelRes, r.icon, prev, showStartingIcon);
2841 }
2842 } else {
2843 // If this is the first activity, don't do any fancy animations,
2844 // because there is nothing for it to animate on top of.
2845 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2846 r.info.screenOrientation, r.fullscreen);
2847 }
2848 if (VALIDATE_TOKENS) {
2849 mWindowManager.validateAppTokens(mHistory);
2850 }
2851
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002852 if (doResume) {
2853 resumeTopActivityLocked(null);
2854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002855 }
2856
2857 /**
2858 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002859 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2860 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 * an instance of that activity in the stack and, if found, finish all
2862 * activities on top of it and return the instance.
2863 *
2864 * @param newR Description of the new activity being started.
2865 * @return Returns the old activity that should be continue to be used,
2866 * or null if none was found.
2867 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002868 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 HistoryRecord newR, boolean doClear) {
2870 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002871
2872 // First find the requested task.
2873 while (i > 0) {
2874 i--;
2875 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2876 if (r.task.taskId == taskId) {
2877 i++;
2878 break;
2879 }
2880 }
2881
2882 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 while (i > 0) {
2884 i--;
2885 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2886 if (r.finishing) {
2887 continue;
2888 }
2889 if (r.task.taskId != taskId) {
2890 return null;
2891 }
2892 if (r.realActivity.equals(newR.realActivity)) {
2893 // Here it is! Now finish everything in front...
2894 HistoryRecord ret = r;
2895 if (doClear) {
2896 while (i < (mHistory.size()-1)) {
2897 i++;
2898 r = (HistoryRecord)mHistory.get(i);
2899 if (r.finishing) {
2900 continue;
2901 }
2902 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2903 null, "clear")) {
2904 i--;
2905 }
2906 }
2907 }
2908
2909 // Finally, if this is a normal launch mode (that is, not
2910 // expecting onNewIntent()), then we will finish the current
2911 // instance of the activity so a new fresh one can be started.
2912 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2913 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002914 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 if (index >= 0) {
2916 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2917 null, "clear");
2918 }
2919 return null;
2920 }
2921 }
2922
2923 return ret;
2924 }
2925 }
2926
2927 return null;
2928 }
2929
2930 /**
2931 * Find the activity in the history stack within the given task. Returns
2932 * the index within the history at which it's found, or < 0 if not found.
2933 */
2934 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2935 int i = mHistory.size();
2936 while (i > 0) {
2937 i--;
2938 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2939 if (candidate.task.taskId != task) {
2940 break;
2941 }
2942 if (candidate.realActivity.equals(r.realActivity)) {
2943 return i;
2944 }
2945 }
2946
2947 return -1;
2948 }
2949
2950 /**
2951 * Reorder the history stack so that the activity at the given index is
2952 * brought to the front.
2953 */
2954 private final HistoryRecord moveActivityToFrontLocked(int where) {
2955 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2956 int top = mHistory.size();
2957 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2958 mHistory.add(top, newTop);
2959 oldTop.frontOfTask = false;
2960 newTop.frontOfTask = true;
2961 return newTop;
2962 }
2963
2964 /**
2965 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2966 * method will be called at the proper time.
2967 */
2968 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2969 boolean sent = false;
2970 if (r.state == ActivityState.RESUMED
2971 && r.app != null && r.app.thread != null) {
2972 try {
2973 ArrayList<Intent> ar = new ArrayList<Intent>();
2974 ar.add(new Intent(intent));
2975 r.app.thread.scheduleNewIntent(ar, r);
2976 sent = true;
2977 } catch (Exception e) {
2978 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2979 }
2980 }
2981 if (!sent) {
2982 r.addNewIntentLocked(new Intent(intent));
2983 }
2984 }
2985
2986 private final void logStartActivity(int tag, HistoryRecord r,
2987 TaskRecord task) {
2988 EventLog.writeEvent(tag,
2989 System.identityHashCode(r), task.taskId,
2990 r.shortComponentName, r.intent.getAction(),
2991 r.intent.getType(), r.intent.getDataString(),
2992 r.intent.getFlags());
2993 }
2994
2995 private final int startActivityLocked(IApplicationThread caller,
2996 Intent intent, String resolvedType,
2997 Uri[] grantedUriPermissions,
2998 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2999 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003000 int callingPid, int callingUid, boolean onlyIfNeeded,
3001 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003002 Log.i(TAG, "Starting activity: " + intent);
3003
3004 HistoryRecord sourceRecord = null;
3005 HistoryRecord resultRecord = null;
3006 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003007 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003008 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3010 if (index >= 0) {
3011 sourceRecord = (HistoryRecord)mHistory.get(index);
3012 if (requestCode >= 0 && !sourceRecord.finishing) {
3013 resultRecord = sourceRecord;
3014 }
3015 }
3016 }
3017
3018 int launchFlags = intent.getFlags();
3019
3020 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3021 && sourceRecord != null) {
3022 // Transfer the result target from the source activity to the new
3023 // one being started, including any failures.
3024 if (requestCode >= 0) {
3025 return START_FORWARD_AND_REQUEST_CONFLICT;
3026 }
3027 resultRecord = sourceRecord.resultTo;
3028 resultWho = sourceRecord.resultWho;
3029 requestCode = sourceRecord.requestCode;
3030 sourceRecord.resultTo = null;
3031 if (resultRecord != null) {
3032 resultRecord.removeResultsLocked(
3033 sourceRecord, resultWho, requestCode);
3034 }
3035 }
3036
3037 int err = START_SUCCESS;
3038
3039 if (intent.getComponent() == null) {
3040 // We couldn't find a class that can handle the given Intent.
3041 // That's the end of that!
3042 err = START_INTENT_NOT_RESOLVED;
3043 }
3044
3045 if (err == START_SUCCESS && aInfo == null) {
3046 // We couldn't find the specific class specified in the Intent.
3047 // Also the end of the line.
3048 err = START_CLASS_NOT_FOUND;
3049 }
3050
3051 ProcessRecord callerApp = null;
3052 if (err == START_SUCCESS && caller != null) {
3053 callerApp = getRecordForAppLocked(caller);
3054 if (callerApp != null) {
3055 callingPid = callerApp.pid;
3056 callingUid = callerApp.info.uid;
3057 } else {
3058 Log.w(TAG, "Unable to find app for caller " + caller
3059 + " (pid=" + callingPid + ") when starting: "
3060 + intent.toString());
3061 err = START_PERMISSION_DENIED;
3062 }
3063 }
3064
3065 if (err != START_SUCCESS) {
3066 if (resultRecord != null) {
3067 sendActivityResultLocked(-1,
3068 resultRecord, resultWho, requestCode,
3069 Activity.RESULT_CANCELED, null);
3070 }
3071 return err;
3072 }
3073
3074 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3075 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3076 if (perm != PackageManager.PERMISSION_GRANTED) {
3077 if (resultRecord != null) {
3078 sendActivityResultLocked(-1,
3079 resultRecord, resultWho, requestCode,
3080 Activity.RESULT_CANCELED, null);
3081 }
3082 String msg = "Permission Denial: starting " + intent.toString()
3083 + " from " + callerApp + " (pid=" + callingPid
3084 + ", uid=" + callingUid + ")"
3085 + " requires " + aInfo.permission;
3086 Log.w(TAG, msg);
3087 throw new SecurityException(msg);
3088 }
3089
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003090 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 boolean abort = false;
3092 try {
3093 // The Intent we give to the watcher has the extra data
3094 // stripped off, since it can contain private information.
3095 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003096 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 aInfo.applicationInfo.packageName);
3098 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003099 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 }
3101
3102 if (abort) {
3103 if (resultRecord != null) {
3104 sendActivityResultLocked(-1,
3105 resultRecord, resultWho, requestCode,
3106 Activity.RESULT_CANCELED, null);
3107 }
3108 // We pretend to the caller that it was really started, but
3109 // they will just get a cancel result.
3110 return START_SUCCESS;
3111 }
3112 }
3113
3114 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3115 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003116 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003118 if (mResumedActivity == null
3119 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3120 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3121 PendingActivityLaunch pal = new PendingActivityLaunch();
3122 pal.r = r;
3123 pal.sourceRecord = sourceRecord;
3124 pal.grantedUriPermissions = grantedUriPermissions;
3125 pal.grantedMode = grantedMode;
3126 pal.onlyIfNeeded = onlyIfNeeded;
3127 mPendingActivityLaunches.add(pal);
3128 return START_SWITCHES_CANCELED;
3129 }
3130 }
3131
3132 if (mDidAppSwitch) {
3133 // This is the second allowed switch since we stopped switches,
3134 // so now just generally allow switches. Use case: user presses
3135 // home (switches disabled, switch to home, mDidAppSwitch now true);
3136 // user taps a home icon (coming from home so allowed, we hit here
3137 // and now allow anyone to switch again).
3138 mAppSwitchesAllowedTime = 0;
3139 } else {
3140 mDidAppSwitch = true;
3141 }
3142
3143 doPendingActivityLaunchesLocked(false);
3144
3145 return startActivityUncheckedLocked(r, sourceRecord,
3146 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3147 }
3148
3149 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3150 final int N = mPendingActivityLaunches.size();
3151 if (N <= 0) {
3152 return;
3153 }
3154 for (int i=0; i<N; i++) {
3155 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3156 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3157 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3158 doResume && i == (N-1));
3159 }
3160 mPendingActivityLaunches.clear();
3161 }
3162
3163 private final int startActivityUncheckedLocked(HistoryRecord r,
3164 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3165 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3166 final Intent intent = r.intent;
3167 final int callingUid = r.launchedFromUid;
3168
3169 int launchFlags = intent.getFlags();
3170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 // We'll invoke onUserLeaving before onPause only if the launching
3172 // activity did not explicitly state that this is an automated launch.
3173 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3174 if (DEBUG_USER_LEAVING) Log.v(TAG,
3175 "startActivity() => mUserLeaving=" + mUserLeaving);
3176
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003177 // If the caller has asked not to resume at this point, we make note
3178 // of this in the record so that we can skip it when trying to find
3179 // the top running activity.
3180 if (!doResume) {
3181 r.delayedResume = true;
3182 }
3183
3184 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3185 != 0 ? r : null;
3186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 // If the onlyIfNeeded flag is set, then we can do this if the activity
3188 // being launched is the same as the one making the call... or, as
3189 // a special case, if we do not know the caller then we count the
3190 // current top activity as the caller.
3191 if (onlyIfNeeded) {
3192 HistoryRecord checkedCaller = sourceRecord;
3193 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003194 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
3196 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3197 // Caller is not the same as launcher, so always needed.
3198 onlyIfNeeded = false;
3199 }
3200 }
3201
3202 if (grantedUriPermissions != null && callingUid > 0) {
3203 for (int i=0; i<grantedUriPermissions.length; i++) {
3204 grantUriPermissionLocked(callingUid, r.packageName,
3205 grantedUriPermissions[i], grantedMode, r);
3206 }
3207 }
3208
3209 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3210 intent, r);
3211
3212 if (sourceRecord == null) {
3213 // This activity is not being started from another... in this
3214 // case we -always- start a new task.
3215 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3216 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3217 + intent);
3218 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3219 }
3220 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3221 // The original activity who is starting us is running as a single
3222 // instance... this new activity it is starting must go on its
3223 // own task.
3224 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3225 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3226 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3227 // The activity being started is a single instance... it always
3228 // gets launched into its own task.
3229 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3230 }
3231
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003232 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 // For whatever reason this activity is being launched into a new
3234 // task... yet the caller has requested a result back. Well, that
3235 // is pretty messed up, so instead immediately send back a cancel
3236 // and let the new task continue launched as normal without a
3237 // dependency on its originator.
3238 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3239 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003240 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 Activity.RESULT_CANCELED, null);
3242 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 }
3244
3245 boolean addingToTask = false;
3246 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3247 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3248 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3249 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3250 // If bring to front is requested, and no result is requested, and
3251 // we can find a task that was started with this same
3252 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003253 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 // See if there is a task to bring to the front. If this is
3255 // a SINGLE_INSTANCE activity, there can be one and only one
3256 // instance of it in the history, and it is always in its own
3257 // unique task, so we do a special search.
3258 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3259 ? findTaskLocked(intent, r.info)
3260 : findActivityLocked(intent, r.info);
3261 if (taskTop != null) {
3262 if (taskTop.task.intent == null) {
3263 // This task was started because of movement of
3264 // the activity based on affinity... now that we
3265 // are actually launching it, we can assign the
3266 // base intent.
3267 taskTop.task.setIntent(intent, r.info);
3268 }
3269 // If the target task is not in the front, then we need
3270 // to bring it to the front... except... well, with
3271 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3272 // to have the same behavior as if a new instance was
3273 // being started, which means not bringing it to the front
3274 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003275 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003276 if (curTop.task != taskTop.task) {
3277 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3278 boolean callerAtFront = sourceRecord == null
3279 || curTop.task == sourceRecord.task;
3280 if (callerAtFront) {
3281 // We really do want to push this one into the
3282 // user's face, right now.
3283 moveTaskToFrontLocked(taskTop.task);
3284 }
3285 }
3286 // If the caller has requested that the target task be
3287 // reset, then do so.
3288 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3289 taskTop = resetTaskIfNeededLocked(taskTop, r);
3290 }
3291 if (onlyIfNeeded) {
3292 // We don't need to start a new activity, and
3293 // the client said not to do anything if that
3294 // is the case, so this is it! And for paranoia, make
3295 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003296 if (doResume) {
3297 resumeTopActivityLocked(null);
3298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 return START_RETURN_INTENT_TO_CALLER;
3300 }
3301 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3302 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3303 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3304 // In this situation we want to remove all activities
3305 // from the task up to the one being started. In most
3306 // cases this means we are resetting the task to its
3307 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003308 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 taskTop.task.taskId, r, true);
3310 if (top != null) {
3311 if (top.frontOfTask) {
3312 // Activity aliases may mean we use different
3313 // intents for the top activity, so make sure
3314 // the task now has the identity of the new
3315 // intent.
3316 top.task.setIntent(r.intent, r.info);
3317 }
3318 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3319 deliverNewIntentLocked(top, r.intent);
3320 } else {
3321 // A special case: we need to
3322 // start the activity because it is not currently
3323 // running, and the caller has asked to clear the
3324 // current task to have this activity at the top.
3325 addingToTask = true;
3326 // Now pretend like this activity is being started
3327 // by the top of its task, so it is put in the
3328 // right place.
3329 sourceRecord = taskTop;
3330 }
3331 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3332 // In this case the top activity on the task is the
3333 // same as the one being launched, so we take that
3334 // as a request to bring the task to the foreground.
3335 // If the top activity in the task is the root
3336 // activity, deliver this new intent to it if it
3337 // desires.
3338 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3339 && taskTop.realActivity.equals(r.realActivity)) {
3340 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3341 if (taskTop.frontOfTask) {
3342 taskTop.task.setIntent(r.intent, r.info);
3343 }
3344 deliverNewIntentLocked(taskTop, r.intent);
3345 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3346 // In this case we are launching the root activity
3347 // of the task, but with a different intent. We
3348 // should start a new instance on top.
3349 addingToTask = true;
3350 sourceRecord = taskTop;
3351 }
3352 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3353 // In this case an activity is being launched in to an
3354 // existing task, without resetting that task. This
3355 // is typically the situation of launching an activity
3356 // from a notification or shortcut. We want to place
3357 // the new activity on top of the current task.
3358 addingToTask = true;
3359 sourceRecord = taskTop;
3360 } else if (!taskTop.task.rootWasReset) {
3361 // In this case we are launching in to an existing task
3362 // that has not yet been started from its front door.
3363 // The current task has been brought to the front.
3364 // Ideally, we'd probably like to place this new task
3365 // at the bottom of its stack, but that's a little hard
3366 // to do with the current organization of the code so
3367 // for now we'll just drop it.
3368 taskTop.task.setIntent(r.intent, r.info);
3369 }
3370 if (!addingToTask) {
3371 // We didn't do anything... but it was needed (a.k.a., client
3372 // don't use that intent!) And for paranoia, make
3373 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003374 if (doResume) {
3375 resumeTopActivityLocked(null);
3376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 return START_TASK_TO_FRONT;
3378 }
3379 }
3380 }
3381 }
3382
3383 //String uri = r.intent.toURI();
3384 //Intent intent2 = new Intent(uri);
3385 //Log.i(TAG, "Given intent: " + r.intent);
3386 //Log.i(TAG, "URI is: " + uri);
3387 //Log.i(TAG, "To intent: " + intent2);
3388
3389 if (r.packageName != null) {
3390 // If the activity being launched is the same as the one currently
3391 // at the top, then we need to check if it should only be launched
3392 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003393 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3394 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 if (top.realActivity.equals(r.realActivity)) {
3396 if (top.app != null && top.app.thread != null) {
3397 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3398 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3399 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3400 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3401 // For paranoia, make sure we have correctly
3402 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003403 if (doResume) {
3404 resumeTopActivityLocked(null);
3405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 if (onlyIfNeeded) {
3407 // We don't need to start a new activity, and
3408 // the client said not to do anything if that
3409 // is the case, so this is it!
3410 return START_RETURN_INTENT_TO_CALLER;
3411 }
3412 deliverNewIntentLocked(top, r.intent);
3413 return START_DELIVERED_TO_TOP;
3414 }
3415 }
3416 }
3417 }
3418
3419 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003420 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003422 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 Activity.RESULT_CANCELED, null);
3424 }
3425 return START_CLASS_NOT_FOUND;
3426 }
3427
3428 boolean newTask = false;
3429
3430 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003431 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003432 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3433 // todo: should do better management of integers.
3434 mCurTask++;
3435 if (mCurTask <= 0) {
3436 mCurTask = 1;
3437 }
3438 r.task = new TaskRecord(mCurTask, r.info, intent,
3439 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3440 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3441 + " in new task " + r.task);
3442 newTask = true;
3443 addRecentTask(r.task);
3444
3445 } else if (sourceRecord != null) {
3446 if (!addingToTask &&
3447 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3448 // In this case, we are adding the activity to an existing
3449 // task, but the caller has asked to clear that task if the
3450 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003451 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003452 sourceRecord.task.taskId, r, true);
3453 if (top != null) {
3454 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3455 deliverNewIntentLocked(top, r.intent);
3456 // For paranoia, make sure we have correctly
3457 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003458 if (doResume) {
3459 resumeTopActivityLocked(null);
3460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 return START_DELIVERED_TO_TOP;
3462 }
3463 } else if (!addingToTask &&
3464 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3465 // In this case, we are launching an activity in our own task
3466 // that may already be running somewhere in the history, and
3467 // we want to shuffle it to the front of the stack if so.
3468 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3469 if (where >= 0) {
3470 HistoryRecord top = moveActivityToFrontLocked(where);
3471 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3472 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 if (doResume) {
3474 resumeTopActivityLocked(null);
3475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 return START_DELIVERED_TO_TOP;
3477 }
3478 }
3479 // An existing activity is starting this new activity, so we want
3480 // to keep the new one in the same task as the one that is starting
3481 // it.
3482 r.task = sourceRecord.task;
3483 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3484 + " in existing task " + r.task);
3485
3486 } else {
3487 // This not being started from an existing activity, and not part
3488 // of a new task... just put it in the top task, though these days
3489 // this case should never happen.
3490 final int N = mHistory.size();
3491 HistoryRecord prev =
3492 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3493 r.task = prev != null
3494 ? prev.task
3495 : new TaskRecord(mCurTask, r.info, intent,
3496 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3497 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3498 + " in new guessed " + r.task);
3499 }
3500 if (newTask) {
3501 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3502 }
3503 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003504 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 return START_SUCCESS;
3506 }
3507
3508 public final int startActivity(IApplicationThread caller,
3509 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3510 int grantedMode, IBinder resultTo,
3511 String resultWho, int requestCode, boolean onlyIfNeeded,
3512 boolean debug) {
3513 // Refuse possible leaked file descriptors
3514 if (intent != null && intent.hasFileDescriptors()) {
3515 throw new IllegalArgumentException("File descriptors passed in Intent");
3516 }
3517
The Android Open Source Project4df24232009-03-05 14:34:35 -08003518 final boolean componentSpecified = intent.getComponent() != null;
3519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 // Don't modify the client's object!
3521 intent = new Intent(intent);
3522
3523 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 ActivityInfo aInfo;
3525 try {
3526 ResolveInfo rInfo =
3527 ActivityThread.getPackageManager().resolveIntent(
3528 intent, resolvedType,
3529 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003530 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 aInfo = rInfo != null ? rInfo.activityInfo : null;
3532 } catch (RemoteException e) {
3533 aInfo = null;
3534 }
3535
3536 if (aInfo != null) {
3537 // Store the found target back into the intent, because now that
3538 // we have it we never want to do this again. For example, if the
3539 // user navigates back to this point in the history, we should
3540 // always restart the exact same activity.
3541 intent.setComponent(new ComponentName(
3542 aInfo.applicationInfo.packageName, aInfo.name));
3543
3544 // Don't debug things in the system process
3545 if (debug) {
3546 if (!aInfo.processName.equals("system")) {
3547 setDebugApp(aInfo.processName, true, false);
3548 }
3549 }
3550 }
3551
3552 synchronized(this) {
3553 final long origId = Binder.clearCallingIdentity();
3554 int res = startActivityLocked(caller, intent, resolvedType,
3555 grantedUriPermissions, grantedMode, aInfo,
3556 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003557 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 Binder.restoreCallingIdentity(origId);
3559 return res;
3560 }
3561 }
3562
3563 public boolean startNextMatchingActivity(IBinder callingActivity,
3564 Intent intent) {
3565 // Refuse possible leaked file descriptors
3566 if (intent != null && intent.hasFileDescriptors() == true) {
3567 throw new IllegalArgumentException("File descriptors passed in Intent");
3568 }
3569
3570 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003571 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 if (index < 0) {
3573 return false;
3574 }
3575 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3576 if (r.app == null || r.app.thread == null) {
3577 // The caller is not running... d'oh!
3578 return false;
3579 }
3580 intent = new Intent(intent);
3581 // The caller is not allowed to change the data.
3582 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3583 // And we are resetting to find the next component...
3584 intent.setComponent(null);
3585
3586 ActivityInfo aInfo = null;
3587 try {
3588 List<ResolveInfo> resolves =
3589 ActivityThread.getPackageManager().queryIntentActivities(
3590 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003591 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592
3593 // Look for the original activity in the list...
3594 final int N = resolves != null ? resolves.size() : 0;
3595 for (int i=0; i<N; i++) {
3596 ResolveInfo rInfo = resolves.get(i);
3597 if (rInfo.activityInfo.packageName.equals(r.packageName)
3598 && rInfo.activityInfo.name.equals(r.info.name)) {
3599 // We found the current one... the next matching is
3600 // after it.
3601 i++;
3602 if (i<N) {
3603 aInfo = resolves.get(i).activityInfo;
3604 }
3605 break;
3606 }
3607 }
3608 } catch (RemoteException e) {
3609 }
3610
3611 if (aInfo == null) {
3612 // Nobody who is next!
3613 return false;
3614 }
3615
3616 intent.setComponent(new ComponentName(
3617 aInfo.applicationInfo.packageName, aInfo.name));
3618 intent.setFlags(intent.getFlags()&~(
3619 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3620 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3621 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3622 Intent.FLAG_ACTIVITY_NEW_TASK));
3623
3624 // Okay now we need to start the new activity, replacing the
3625 // currently running activity. This is a little tricky because
3626 // we want to start the new one as if the current one is finished,
3627 // but not finish the current one first so that there is no flicker.
3628 // And thus...
3629 final boolean wasFinishing = r.finishing;
3630 r.finishing = true;
3631
3632 // Propagate reply information over to the new activity.
3633 final HistoryRecord resultTo = r.resultTo;
3634 final String resultWho = r.resultWho;
3635 final int requestCode = r.requestCode;
3636 r.resultTo = null;
3637 if (resultTo != null) {
3638 resultTo.removeResultsLocked(r, resultWho, requestCode);
3639 }
3640
3641 final long origId = Binder.clearCallingIdentity();
3642 // XXX we are not dealing with propagating grantedUriPermissions...
3643 // those are not yet exposed to user code, so there is no need.
3644 int res = startActivityLocked(r.app.thread, intent,
3645 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003646 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003647 Binder.restoreCallingIdentity(origId);
3648
3649 r.finishing = wasFinishing;
3650 if (res != START_SUCCESS) {
3651 return false;
3652 }
3653 return true;
3654 }
3655 }
3656
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003657 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003658 Intent intent, String resolvedType, IBinder resultTo,
3659 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003660
3661 // This is so super not safe, that only the system (or okay root)
3662 // can do it.
3663 final int callingUid = Binder.getCallingUid();
3664 if (callingUid != 0 && callingUid != Process.myUid()) {
3665 throw new SecurityException(
3666 "startActivityInPackage only available to the system");
3667 }
3668
The Android Open Source Project4df24232009-03-05 14:34:35 -08003669 final boolean componentSpecified = intent.getComponent() != null;
3670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003671 // Don't modify the client's object!
3672 intent = new Intent(intent);
3673
3674 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003675 ActivityInfo aInfo;
3676 try {
3677 ResolveInfo rInfo =
3678 ActivityThread.getPackageManager().resolveIntent(
3679 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003680 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003681 aInfo = rInfo != null ? rInfo.activityInfo : null;
3682 } catch (RemoteException e) {
3683 aInfo = null;
3684 }
3685
3686 if (aInfo != null) {
3687 // Store the found target back into the intent, because now that
3688 // we have it we never want to do this again. For example, if the
3689 // user navigates back to this point in the history, we should
3690 // always restart the exact same activity.
3691 intent.setComponent(new ComponentName(
3692 aInfo.applicationInfo.packageName, aInfo.name));
3693 }
3694
3695 synchronized(this) {
3696 return startActivityLocked(null, intent, resolvedType,
3697 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003698 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003699 }
3700 }
3701
3702 private final void addRecentTask(TaskRecord task) {
3703 // Remove any existing entries that are the same kind of task.
3704 int N = mRecentTasks.size();
3705 for (int i=0; i<N; i++) {
3706 TaskRecord tr = mRecentTasks.get(i);
3707 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3708 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3709 mRecentTasks.remove(i);
3710 i--;
3711 N--;
3712 if (task.intent == null) {
3713 // If the new recent task we are adding is not fully
3714 // specified, then replace it with the existing recent task.
3715 task = tr;
3716 }
3717 }
3718 }
3719 if (N >= MAX_RECENT_TASKS) {
3720 mRecentTasks.remove(N-1);
3721 }
3722 mRecentTasks.add(0, task);
3723 }
3724
3725 public void setRequestedOrientation(IBinder token,
3726 int requestedOrientation) {
3727 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003728 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003729 if (index < 0) {
3730 return;
3731 }
3732 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3733 final long origId = Binder.clearCallingIdentity();
3734 mWindowManager.setAppOrientation(r, requestedOrientation);
3735 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003736 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 r.mayFreezeScreenLocked(r.app) ? r : null);
3738 if (config != null) {
3739 r.frozenBeforeDestroy = true;
3740 if (!updateConfigurationLocked(config, r)) {
3741 resumeTopActivityLocked(null);
3742 }
3743 }
3744 Binder.restoreCallingIdentity(origId);
3745 }
3746 }
3747
3748 public int getRequestedOrientation(IBinder token) {
3749 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003750 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 if (index < 0) {
3752 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3753 }
3754 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3755 return mWindowManager.getAppOrientation(r);
3756 }
3757 }
3758
3759 private final void stopActivityLocked(HistoryRecord r) {
3760 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3761 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3762 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3763 if (!r.finishing) {
3764 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3765 "no-history");
3766 }
3767 } else if (r.app != null && r.app.thread != null) {
3768 if (mFocusedActivity == r) {
3769 setFocusedActivityLocked(topRunningActivityLocked(null));
3770 }
3771 r.resumeKeyDispatchingLocked();
3772 try {
3773 r.stopped = false;
3774 r.state = ActivityState.STOPPING;
3775 if (DEBUG_VISBILITY) Log.v(
3776 TAG, "Stopping visible=" + r.visible + " for " + r);
3777 if (!r.visible) {
3778 mWindowManager.setAppVisibility(r, false);
3779 }
3780 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3781 } catch (Exception e) {
3782 // Maybe just ignore exceptions here... if the process
3783 // has crashed, our death notification will clean things
3784 // up.
3785 Log.w(TAG, "Exception thrown during pause", e);
3786 // Just in case, assume it to be stopped.
3787 r.stopped = true;
3788 r.state = ActivityState.STOPPED;
3789 if (r.configDestroy) {
3790 destroyActivityLocked(r, true);
3791 }
3792 }
3793 }
3794 }
3795
3796 /**
3797 * @return Returns true if the activity is being finished, false if for
3798 * some reason it is being left as-is.
3799 */
3800 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3801 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003802 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 TAG, "Finishing activity: token=" + token
3804 + ", result=" + resultCode + ", data=" + resultData);
3805
Dianne Hackborn75b03852009-06-12 15:43:26 -07003806 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807 if (index < 0) {
3808 return false;
3809 }
3810 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3811
3812 // Is this the last activity left?
3813 boolean lastActivity = true;
3814 for (int i=mHistory.size()-1; i>=0; i--) {
3815 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3816 if (!p.finishing && p != r) {
3817 lastActivity = false;
3818 break;
3819 }
3820 }
3821
3822 // If this is the last activity, but it is the home activity, then
3823 // just don't finish it.
3824 if (lastActivity) {
3825 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3826 return false;
3827 }
3828 }
3829
3830 finishActivityLocked(r, index, resultCode, resultData, reason);
3831 return true;
3832 }
3833
3834 /**
3835 * @return Returns true if this activity has been removed from the history
3836 * list, or false if it is still in the list and will be removed later.
3837 */
3838 private final boolean finishActivityLocked(HistoryRecord r, int index,
3839 int resultCode, Intent resultData, String reason) {
3840 if (r.finishing) {
3841 Log.w(TAG, "Duplicate finish request for " + r);
3842 return false;
3843 }
3844
3845 r.finishing = true;
3846 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3847 System.identityHashCode(r),
3848 r.task.taskId, r.shortComponentName, reason);
3849 r.task.numActivities--;
3850 if (r.frontOfTask && index < (mHistory.size()-1)) {
3851 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3852 if (next.task == r.task) {
3853 next.frontOfTask = true;
3854 }
3855 }
3856
3857 r.pauseKeyDispatchingLocked();
3858 if (mFocusedActivity == r) {
3859 setFocusedActivityLocked(topRunningActivityLocked(null));
3860 }
3861
3862 // send the result
3863 HistoryRecord resultTo = r.resultTo;
3864 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003865 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3866 + " who=" + r.resultWho + " req=" + r.requestCode
3867 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003868 if (r.info.applicationInfo.uid > 0) {
3869 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3870 r.packageName, resultData, r);
3871 }
3872 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3873 resultData);
3874 r.resultTo = null;
3875 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003876 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003877
3878 // Make sure this HistoryRecord is not holding on to other resources,
3879 // because clients have remote IPC references to this object so we
3880 // can't assume that will go away and want to avoid circular IPC refs.
3881 r.results = null;
3882 r.pendingResults = null;
3883 r.newIntents = null;
3884 r.icicle = null;
3885
3886 if (mPendingThumbnails.size() > 0) {
3887 // There are clients waiting to receive thumbnails so, in case
3888 // this is an activity that someone is waiting for, add it
3889 // to the pending list so we can correctly update the clients.
3890 mCancelledThumbnails.add(r);
3891 }
3892
3893 if (mResumedActivity == r) {
3894 boolean endTask = index <= 0
3895 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3896 if (DEBUG_TRANSITION) Log.v(TAG,
3897 "Prepare close transition: finishing " + r);
3898 mWindowManager.prepareAppTransition(endTask
3899 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3900 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3901
3902 // Tell window manager to prepare for this one to be removed.
3903 mWindowManager.setAppVisibility(r, false);
3904
3905 if (mPausingActivity == null) {
3906 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3907 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3908 startPausingLocked(false, false);
3909 }
3910
3911 } else if (r.state != ActivityState.PAUSING) {
3912 // If the activity is PAUSING, we will complete the finish once
3913 // it is done pausing; else we can just directly finish it here.
3914 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3915 return finishCurrentActivityLocked(r, index,
3916 FINISH_AFTER_PAUSE) == null;
3917 } else {
3918 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3919 }
3920
3921 return false;
3922 }
3923
3924 private static final int FINISH_IMMEDIATELY = 0;
3925 private static final int FINISH_AFTER_PAUSE = 1;
3926 private static final int FINISH_AFTER_VISIBLE = 2;
3927
3928 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3929 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003930 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003931 if (index < 0) {
3932 return null;
3933 }
3934
3935 return finishCurrentActivityLocked(r, index, mode);
3936 }
3937
3938 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3939 int index, int mode) {
3940 // First things first: if this activity is currently visible,
3941 // and the resumed activity is not yet visible, then hold off on
3942 // finishing until the resumed one becomes visible.
3943 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3944 if (!mStoppingActivities.contains(r)) {
3945 mStoppingActivities.add(r);
3946 if (mStoppingActivities.size() > 3) {
3947 // If we already have a few activities waiting to stop,
3948 // then give up on things going idle and start clearing
3949 // them out.
3950 Message msg = Message.obtain();
3951 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3952 mHandler.sendMessage(msg);
3953 }
3954 }
3955 r.state = ActivityState.STOPPING;
3956 updateOomAdjLocked();
3957 return r;
3958 }
3959
3960 // make sure the record is cleaned out of other places.
3961 mStoppingActivities.remove(r);
3962 mWaitingVisibleActivities.remove(r);
3963 if (mResumedActivity == r) {
3964 mResumedActivity = null;
3965 }
3966 final ActivityState prevState = r.state;
3967 r.state = ActivityState.FINISHING;
3968
3969 if (mode == FINISH_IMMEDIATELY
3970 || prevState == ActivityState.STOPPED
3971 || prevState == ActivityState.INITIALIZING) {
3972 // If this activity is already stopped, we can just finish
3973 // it right now.
3974 return destroyActivityLocked(r, true) ? null : r;
3975 } else {
3976 // Need to go through the full pause cycle to get this
3977 // activity into the stopped state and then finish it.
3978 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3979 mFinishingActivities.add(r);
3980 resumeTopActivityLocked(null);
3981 }
3982 return r;
3983 }
3984
3985 /**
3986 * This is the internal entry point for handling Activity.finish().
3987 *
3988 * @param token The Binder token referencing the Activity we want to finish.
3989 * @param resultCode Result code, if any, from this Activity.
3990 * @param resultData Result data (Intent), if any, from this Activity.
3991 *
3992 * @result Returns true if the activity successfully finished, or false if it is still running.
3993 */
3994 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3995 // Refuse possible leaked file descriptors
3996 if (resultData != null && resultData.hasFileDescriptors() == true) {
3997 throw new IllegalArgumentException("File descriptors passed in Intent");
3998 }
3999
4000 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004001 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002 // Find the first activity that is not finishing.
4003 HistoryRecord next = topRunningActivityLocked(token, 0);
4004 if (next != null) {
4005 // ask watcher if this is allowed
4006 boolean resumeOK = true;
4007 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004008 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004009 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004010 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 }
4012
4013 if (!resumeOK) {
4014 return false;
4015 }
4016 }
4017 }
4018 final long origId = Binder.clearCallingIdentity();
4019 boolean res = requestFinishActivityLocked(token, resultCode,
4020 resultData, "app-request");
4021 Binder.restoreCallingIdentity(origId);
4022 return res;
4023 }
4024 }
4025
4026 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4027 String resultWho, int requestCode, int resultCode, Intent data) {
4028
4029 if (callingUid > 0) {
4030 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4031 data, r);
4032 }
4033
The Android Open Source Project10592532009-03-18 17:39:46 -07004034 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4035 + " : who=" + resultWho + " req=" + requestCode
4036 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4038 try {
4039 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4040 list.add(new ResultInfo(resultWho, requestCode,
4041 resultCode, data));
4042 r.app.thread.scheduleSendResult(r, list);
4043 return;
4044 } catch (Exception e) {
4045 Log.w(TAG, "Exception thrown sending result to " + r, e);
4046 }
4047 }
4048
4049 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4050 }
4051
4052 public final void finishSubActivity(IBinder token, String resultWho,
4053 int requestCode) {
4054 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004055 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004056 if (index < 0) {
4057 return;
4058 }
4059 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4060
4061 final long origId = Binder.clearCallingIdentity();
4062
4063 int i;
4064 for (i=mHistory.size()-1; i>=0; i--) {
4065 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4066 if (r.resultTo == self && r.requestCode == requestCode) {
4067 if ((r.resultWho == null && resultWho == null) ||
4068 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4069 finishActivityLocked(r, i,
4070 Activity.RESULT_CANCELED, null, "request-sub");
4071 }
4072 }
4073 }
4074
4075 Binder.restoreCallingIdentity(origId);
4076 }
4077 }
4078
4079 /**
4080 * Perform clean-up of service connections in an activity record.
4081 */
4082 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4083 // Throw away any services that have been bound by this activity.
4084 if (r.connections != null) {
4085 Iterator<ConnectionRecord> it = r.connections.iterator();
4086 while (it.hasNext()) {
4087 ConnectionRecord c = it.next();
4088 removeConnectionLocked(c, null, r);
4089 }
4090 r.connections = null;
4091 }
4092 }
4093
4094 /**
4095 * Perform the common clean-up of an activity record. This is called both
4096 * as part of destroyActivityLocked() (when destroying the client-side
4097 * representation) and cleaning things up as a result of its hosting
4098 * processing going away, in which case there is no remaining client-side
4099 * state to destroy so only the cleanup here is needed.
4100 */
4101 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4102 if (mResumedActivity == r) {
4103 mResumedActivity = null;
4104 }
4105 if (mFocusedActivity == r) {
4106 mFocusedActivity = null;
4107 }
4108
4109 r.configDestroy = false;
4110 r.frozenBeforeDestroy = false;
4111
4112 // Make sure this record is no longer in the pending finishes list.
4113 // This could happen, for example, if we are trimming activities
4114 // down to the max limit while they are still waiting to finish.
4115 mFinishingActivities.remove(r);
4116 mWaitingVisibleActivities.remove(r);
4117
4118 // Remove any pending results.
4119 if (r.finishing && r.pendingResults != null) {
4120 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4121 PendingIntentRecord rec = apr.get();
4122 if (rec != null) {
4123 cancelIntentSenderLocked(rec, false);
4124 }
4125 }
4126 r.pendingResults = null;
4127 }
4128
4129 if (cleanServices) {
4130 cleanUpActivityServicesLocked(r);
4131 }
4132
4133 if (mPendingThumbnails.size() > 0) {
4134 // There are clients waiting to receive thumbnails so, in case
4135 // this is an activity that someone is waiting for, add it
4136 // to the pending list so we can correctly update the clients.
4137 mCancelledThumbnails.add(r);
4138 }
4139
4140 // Get rid of any pending idle timeouts.
4141 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4142 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4143 }
4144
4145 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4146 if (r.state != ActivityState.DESTROYED) {
4147 mHistory.remove(r);
4148 r.inHistory = false;
4149 r.state = ActivityState.DESTROYED;
4150 mWindowManager.removeAppToken(r);
4151 if (VALIDATE_TOKENS) {
4152 mWindowManager.validateAppTokens(mHistory);
4153 }
4154 cleanUpActivityServicesLocked(r);
4155 removeActivityUriPermissionsLocked(r);
4156 }
4157 }
4158
4159 /**
4160 * Destroy the current CLIENT SIDE instance of an activity. This may be
4161 * called both when actually finishing an activity, or when performing
4162 * a configuration switch where we destroy the current client-side object
4163 * but then create a new client-side object for this same HistoryRecord.
4164 */
4165 private final boolean destroyActivityLocked(HistoryRecord r,
4166 boolean removeFromApp) {
4167 if (DEBUG_SWITCH) Log.v(
4168 TAG, "Removing activity: token=" + r
4169 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4170 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4171 System.identityHashCode(r),
4172 r.task.taskId, r.shortComponentName);
4173
4174 boolean removedFromHistory = false;
4175
4176 cleanUpActivityLocked(r, false);
4177
4178 if (r.app != null) {
4179 if (removeFromApp) {
4180 int idx = r.app.activities.indexOf(r);
4181 if (idx >= 0) {
4182 r.app.activities.remove(idx);
4183 }
4184 if (r.persistent) {
4185 decPersistentCountLocked(r.app);
4186 }
4187 }
4188
4189 boolean skipDestroy = false;
4190
4191 try {
4192 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4193 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4194 r.configChangeFlags);
4195 } catch (Exception e) {
4196 // We can just ignore exceptions here... if the process
4197 // has crashed, our death notification will clean things
4198 // up.
4199 //Log.w(TAG, "Exception thrown during finish", e);
4200 if (r.finishing) {
4201 removeActivityFromHistoryLocked(r);
4202 removedFromHistory = true;
4203 skipDestroy = true;
4204 }
4205 }
4206
4207 r.app = null;
4208 r.nowVisible = false;
4209
4210 if (r.finishing && !skipDestroy) {
4211 r.state = ActivityState.DESTROYING;
4212 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4213 msg.obj = r;
4214 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4215 } else {
4216 r.state = ActivityState.DESTROYED;
4217 }
4218 } else {
4219 // remove this record from the history.
4220 if (r.finishing) {
4221 removeActivityFromHistoryLocked(r);
4222 removedFromHistory = true;
4223 } else {
4224 r.state = ActivityState.DESTROYED;
4225 }
4226 }
4227
4228 r.configChangeFlags = 0;
4229
4230 if (!mLRUActivities.remove(r)) {
4231 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4232 }
4233
4234 return removedFromHistory;
4235 }
4236
4237 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4238 ProcessRecord app)
4239 {
4240 int i = list.size();
4241 if (localLOGV) Log.v(
4242 TAG, "Removing app " + app + " from list " + list
4243 + " with " + i + " entries");
4244 while (i > 0) {
4245 i--;
4246 HistoryRecord r = (HistoryRecord)list.get(i);
4247 if (localLOGV) Log.v(
4248 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4249 if (r.app == app) {
4250 if (localLOGV) Log.v(TAG, "Removing this entry!");
4251 list.remove(i);
4252 }
4253 }
4254 }
4255
4256 /**
4257 * Main function for removing an existing process from the activity manager
4258 * as a result of that process going away. Clears out all connections
4259 * to the process.
4260 */
4261 private final void handleAppDiedLocked(ProcessRecord app,
4262 boolean restarting) {
4263 cleanUpApplicationRecordLocked(app, restarting, -1);
4264 if (!restarting) {
4265 mLRUProcesses.remove(app);
4266 }
4267
4268 // Just in case...
4269 if (mPausingActivity != null && mPausingActivity.app == app) {
4270 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4271 mPausingActivity = null;
4272 }
4273 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4274 mLastPausedActivity = null;
4275 }
4276
4277 // Remove this application's activities from active lists.
4278 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4279 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4280 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4281 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4282
4283 boolean atTop = true;
4284 boolean hasVisibleActivities = false;
4285
4286 // Clean out the history list.
4287 int i = mHistory.size();
4288 if (localLOGV) Log.v(
4289 TAG, "Removing app " + app + " from history with " + i + " entries");
4290 while (i > 0) {
4291 i--;
4292 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4293 if (localLOGV) Log.v(
4294 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4295 if (r.app == app) {
4296 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4297 if (localLOGV) Log.v(
4298 TAG, "Removing this entry! frozen=" + r.haveState
4299 + " finishing=" + r.finishing);
4300 mHistory.remove(i);
4301
4302 r.inHistory = false;
4303 mWindowManager.removeAppToken(r);
4304 if (VALIDATE_TOKENS) {
4305 mWindowManager.validateAppTokens(mHistory);
4306 }
4307 removeActivityUriPermissionsLocked(r);
4308
4309 } else {
4310 // We have the current state for this activity, so
4311 // it can be restarted later when needed.
4312 if (localLOGV) Log.v(
4313 TAG, "Keeping entry, setting app to null");
4314 if (r.visible) {
4315 hasVisibleActivities = true;
4316 }
4317 r.app = null;
4318 r.nowVisible = false;
4319 if (!r.haveState) {
4320 r.icicle = null;
4321 }
4322 }
4323
4324 cleanUpActivityLocked(r, true);
4325 r.state = ActivityState.STOPPED;
4326 }
4327 atTop = false;
4328 }
4329
4330 app.activities.clear();
4331
4332 if (app.instrumentationClass != null) {
4333 Log.w(TAG, "Crash of app " + app.processName
4334 + " running instrumentation " + app.instrumentationClass);
4335 Bundle info = new Bundle();
4336 info.putString("shortMsg", "Process crashed.");
4337 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4338 }
4339
4340 if (!restarting) {
4341 if (!resumeTopActivityLocked(null)) {
4342 // If there was nothing to resume, and we are not already
4343 // restarting this process, but there is a visible activity that
4344 // is hosted by the process... then make sure all visible
4345 // activities are running, taking care of restarting this
4346 // process.
4347 if (hasVisibleActivities) {
4348 ensureActivitiesVisibleLocked(null, 0);
4349 }
4350 }
4351 }
4352 }
4353
4354 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4355 IBinder threadBinder = thread.asBinder();
4356
4357 // Find the application record.
4358 int count = mLRUProcesses.size();
4359 int i;
4360 for (i=0; i<count; i++) {
4361 ProcessRecord rec = mLRUProcesses.get(i);
4362 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4363 return i;
4364 }
4365 }
4366 return -1;
4367 }
4368
4369 private final ProcessRecord getRecordForAppLocked(
4370 IApplicationThread thread) {
4371 if (thread == null) {
4372 return null;
4373 }
4374
4375 int appIndex = getLRURecordIndexForAppLocked(thread);
4376 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4377 }
4378
4379 private final void appDiedLocked(ProcessRecord app, int pid,
4380 IApplicationThread thread) {
4381
4382 mProcDeaths[0]++;
4383
4384 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4385 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4386 + ") has died.");
4387 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4388 if (localLOGV) Log.v(
4389 TAG, "Dying app: " + app + ", pid: " + pid
4390 + ", thread: " + thread.asBinder());
4391 boolean doLowMem = app.instrumentationClass == null;
4392 handleAppDiedLocked(app, false);
4393
4394 if (doLowMem) {
4395 // If there are no longer any background processes running,
4396 // and the app that died was not running instrumentation,
4397 // then tell everyone we are now low on memory.
4398 boolean haveBg = false;
4399 int count = mLRUProcesses.size();
4400 int i;
4401 for (i=0; i<count; i++) {
4402 ProcessRecord rec = mLRUProcesses.get(i);
4403 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4404 haveBg = true;
4405 break;
4406 }
4407 }
4408
4409 if (!haveBg) {
4410 Log.i(TAG, "Low Memory: No more background processes.");
4411 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4412 for (i=0; i<count; i++) {
4413 ProcessRecord rec = mLRUProcesses.get(i);
4414 if (rec.thread != null) {
4415 rec.lastRequestedGc = SystemClock.uptimeMillis();
4416 try {
4417 rec.thread.scheduleLowMemory();
4418 } catch (RemoteException e) {
4419 // Don't care if the process is gone.
4420 }
4421 }
4422 }
4423 }
4424 }
4425 } else if (Config.LOGD) {
4426 Log.d(TAG, "Received spurious death notification for thread "
4427 + thread.asBinder());
4428 }
4429 }
4430
4431 final String readFile(String filename) {
4432 try {
4433 FileInputStream fs = new FileInputStream(filename);
4434 byte[] inp = new byte[8192];
4435 int size = fs.read(inp);
4436 fs.close();
4437 return new String(inp, 0, 0, size);
4438 } catch (java.io.IOException e) {
4439 }
4440 return "";
4441 }
4442
4443 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4444 final String annotation) {
4445 if (app.notResponding || app.crashing) {
4446 return;
4447 }
4448
4449 // Log the ANR to the event log.
4450 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4451
4452 // If we are on a secure build and the application is not interesting to the user (it is
4453 // not visible or in the background), just kill it instead of displaying a dialog.
4454 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4455 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4456 Process.killProcess(app.pid);
4457 return;
4458 }
4459
4460 // DeviceMonitor.start();
4461
4462 String processInfo = null;
4463 if (MONITOR_CPU_USAGE) {
4464 updateCpuStatsNow();
4465 synchronized (mProcessStatsThread) {
4466 processInfo = mProcessStats.printCurrentState();
4467 }
4468 }
4469
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004470 StringBuilder info = mStringBuilder;
4471 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004472 info.append("ANR (application not responding) in process: ");
4473 info.append(app.processName);
4474 if (annotation != null) {
4475 info.append("\nAnnotation: ");
4476 info.append(annotation);
4477 }
4478 if (MONITOR_CPU_USAGE) {
4479 info.append("\nCPU usage:\n");
4480 info.append(processInfo);
4481 }
4482 Log.i(TAG, info.toString());
4483
4484 // The application is not responding. Dump as many thread traces as we can.
4485 boolean fileDump = prepareTraceFile(true);
4486 if (!fileDump) {
4487 // Dumping traces to the log, just dump the process that isn't responding so
4488 // we don't overflow the log
4489 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4490 } else {
4491 // Dumping traces to a file so dump all active processes we know about
4492 synchronized (this) {
4493 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4494 ProcessRecord r = mLRUProcesses.get(i);
4495 if (r.thread != null) {
4496 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4497 }
4498 }
4499 }
4500 }
4501
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004502 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004503 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004504 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 app.pid, info.toString());
4506 if (res != 0) {
4507 if (res < 0) {
4508 // wait until the SIGQUIT has had a chance to process before killing the
4509 // process.
4510 try {
4511 wait(2000);
4512 } catch (InterruptedException e) {
4513 }
4514
4515 Process.killProcess(app.pid);
4516 return;
4517 }
4518 }
4519 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004520 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004521 }
4522 }
4523
4524 makeAppNotRespondingLocked(app,
4525 activity != null ? activity.shortComponentName : null,
4526 annotation != null ? "ANR " + annotation : "ANR",
4527 info.toString(), null);
4528 Message msg = Message.obtain();
4529 HashMap map = new HashMap();
4530 msg.what = SHOW_NOT_RESPONDING_MSG;
4531 msg.obj = map;
4532 map.put("app", app);
4533 if (activity != null) {
4534 map.put("activity", activity);
4535 }
4536
4537 mHandler.sendMessage(msg);
4538 return;
4539 }
4540
4541 /**
4542 * If a stack trace file has been configured, prepare the filesystem
4543 * by creating the directory if it doesn't exist and optionally
4544 * removing the old trace file.
4545 *
4546 * @param removeExisting If set, the existing trace file will be removed.
4547 * @return Returns true if the trace file preparations succeeded
4548 */
4549 public static boolean prepareTraceFile(boolean removeExisting) {
4550 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4551 boolean fileReady = false;
4552 if (!TextUtils.isEmpty(tracesPath)) {
4553 File f = new File(tracesPath);
4554 if (!f.exists()) {
4555 // Ensure the enclosing directory exists
4556 File dir = f.getParentFile();
4557 if (!dir.exists()) {
4558 fileReady = dir.mkdirs();
4559 FileUtils.setPermissions(dir.getAbsolutePath(),
4560 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4561 } else if (dir.isDirectory()) {
4562 fileReady = true;
4563 }
4564 } else if (removeExisting) {
4565 // Remove the previous traces file, so we don't fill the disk.
4566 // The VM will recreate it
4567 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4568 fileReady = f.delete();
4569 }
4570 }
4571
4572 return fileReady;
4573 }
4574
4575
4576 private final void decPersistentCountLocked(ProcessRecord app)
4577 {
4578 app.persistentActivities--;
4579 if (app.persistentActivities > 0) {
4580 // Still more of 'em...
4581 return;
4582 }
4583 if (app.persistent) {
4584 // Ah, but the application itself is persistent. Whatever!
4585 return;
4586 }
4587
4588 // App is no longer persistent... make sure it and the ones
4589 // following it in the LRU list have the correc oom_adj.
4590 updateOomAdjLocked();
4591 }
4592
4593 public void setPersistent(IBinder token, boolean isPersistent) {
4594 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4595 != PackageManager.PERMISSION_GRANTED) {
4596 String msg = "Permission Denial: setPersistent() from pid="
4597 + Binder.getCallingPid()
4598 + ", uid=" + Binder.getCallingUid()
4599 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4600 Log.w(TAG, msg);
4601 throw new SecurityException(msg);
4602 }
4603
4604 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004605 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004606 if (index < 0) {
4607 return;
4608 }
4609 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4610 ProcessRecord app = r.app;
4611
4612 if (localLOGV) Log.v(
4613 TAG, "Setting persistence " + isPersistent + ": " + r);
4614
4615 if (isPersistent) {
4616 if (r.persistent) {
4617 // Okay okay, I heard you already!
4618 if (localLOGV) Log.v(TAG, "Already persistent!");
4619 return;
4620 }
4621 r.persistent = true;
4622 app.persistentActivities++;
4623 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4624 if (app.persistentActivities > 1) {
4625 // We aren't the first...
4626 if (localLOGV) Log.v(TAG, "Not the first!");
4627 return;
4628 }
4629 if (app.persistent) {
4630 // This would be redundant.
4631 if (localLOGV) Log.v(TAG, "App is persistent!");
4632 return;
4633 }
4634
4635 // App is now persistent... make sure it and the ones
4636 // following it now have the correct oom_adj.
4637 final long origId = Binder.clearCallingIdentity();
4638 updateOomAdjLocked();
4639 Binder.restoreCallingIdentity(origId);
4640
4641 } else {
4642 if (!r.persistent) {
4643 // Okay okay, I heard you already!
4644 return;
4645 }
4646 r.persistent = false;
4647 final long origId = Binder.clearCallingIdentity();
4648 decPersistentCountLocked(app);
4649 Binder.restoreCallingIdentity(origId);
4650
4651 }
4652 }
4653 }
4654
4655 public boolean clearApplicationUserData(final String packageName,
4656 final IPackageDataObserver observer) {
4657 int uid = Binder.getCallingUid();
4658 int pid = Binder.getCallingPid();
4659 long callingId = Binder.clearCallingIdentity();
4660 try {
4661 IPackageManager pm = ActivityThread.getPackageManager();
4662 int pkgUid = -1;
4663 synchronized(this) {
4664 try {
4665 pkgUid = pm.getPackageUid(packageName);
4666 } catch (RemoteException e) {
4667 }
4668 if (pkgUid == -1) {
4669 Log.w(TAG, "Invalid packageName:" + packageName);
4670 return false;
4671 }
4672 if (uid == pkgUid || checkComponentPermission(
4673 android.Manifest.permission.CLEAR_APP_USER_DATA,
4674 pid, uid, -1)
4675 == PackageManager.PERMISSION_GRANTED) {
4676 restartPackageLocked(packageName, pkgUid);
4677 } else {
4678 throw new SecurityException(pid+" does not have permission:"+
4679 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4680 "for process:"+packageName);
4681 }
4682 }
4683
4684 try {
4685 //clear application user data
4686 pm.clearApplicationUserData(packageName, observer);
4687 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4688 Uri.fromParts("package", packageName, null));
4689 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4690 broadcastIntentLocked(null, null, intent,
4691 null, null, 0, null, null, null,
4692 false, false, MY_PID, Process.SYSTEM_UID);
4693 } catch (RemoteException e) {
4694 }
4695 } finally {
4696 Binder.restoreCallingIdentity(callingId);
4697 }
4698 return true;
4699 }
4700
4701 public void restartPackage(final String packageName) {
4702 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4703 != PackageManager.PERMISSION_GRANTED) {
4704 String msg = "Permission Denial: restartPackage() from pid="
4705 + Binder.getCallingPid()
4706 + ", uid=" + Binder.getCallingUid()
4707 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4708 Log.w(TAG, msg);
4709 throw new SecurityException(msg);
4710 }
4711
4712 long callingId = Binder.clearCallingIdentity();
4713 try {
4714 IPackageManager pm = ActivityThread.getPackageManager();
4715 int pkgUid = -1;
4716 synchronized(this) {
4717 try {
4718 pkgUid = pm.getPackageUid(packageName);
4719 } catch (RemoteException e) {
4720 }
4721 if (pkgUid == -1) {
4722 Log.w(TAG, "Invalid packageName: " + packageName);
4723 return;
4724 }
4725 restartPackageLocked(packageName, pkgUid);
4726 }
4727 } finally {
4728 Binder.restoreCallingIdentity(callingId);
4729 }
4730 }
4731
4732 private void restartPackageLocked(final String packageName, int uid) {
4733 uninstallPackageLocked(packageName, uid, false);
4734 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4735 Uri.fromParts("package", packageName, null));
4736 intent.putExtra(Intent.EXTRA_UID, uid);
4737 broadcastIntentLocked(null, null, intent,
4738 null, null, 0, null, null, null,
4739 false, false, MY_PID, Process.SYSTEM_UID);
4740 }
4741
4742 private final void uninstallPackageLocked(String name, int uid,
4743 boolean callerWillRestart) {
4744 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4745
4746 int i, N;
4747
4748 final String procNamePrefix = name + ":";
4749 if (uid < 0) {
4750 try {
4751 uid = ActivityThread.getPackageManager().getPackageUid(name);
4752 } catch (RemoteException e) {
4753 }
4754 }
4755
4756 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4757 while (badApps.hasNext()) {
4758 SparseArray<Long> ba = badApps.next();
4759 if (ba.get(uid) != null) {
4760 badApps.remove();
4761 }
4762 }
4763
4764 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4765
4766 // Remove all processes this package may have touched: all with the
4767 // same UID (except for the system or root user), and all whose name
4768 // matches the package name.
4769 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4770 final int NA = apps.size();
4771 for (int ia=0; ia<NA; ia++) {
4772 ProcessRecord app = apps.valueAt(ia);
4773 if (app.removed) {
4774 procs.add(app);
4775 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4776 || app.processName.equals(name)
4777 || app.processName.startsWith(procNamePrefix)) {
4778 app.removed = true;
4779 procs.add(app);
4780 }
4781 }
4782 }
4783
4784 N = procs.size();
4785 for (i=0; i<N; i++) {
4786 removeProcessLocked(procs.get(i), callerWillRestart);
4787 }
4788
4789 for (i=mHistory.size()-1; i>=0; i--) {
4790 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4791 if (r.packageName.equals(name)) {
4792 if (Config.LOGD) Log.d(
4793 TAG, " Force finishing activity "
4794 + r.intent.getComponent().flattenToShortString());
4795 if (r.app != null) {
4796 r.app.removed = true;
4797 }
4798 r.app = null;
4799 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4800 }
4801 }
4802
4803 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4804 for (ServiceRecord service : mServices.values()) {
4805 if (service.packageName.equals(name)) {
4806 if (service.app != null) {
4807 service.app.removed = true;
4808 }
4809 service.app = null;
4810 services.add(service);
4811 }
4812 }
4813
4814 N = services.size();
4815 for (i=0; i<N; i++) {
4816 bringDownServiceLocked(services.get(i), true);
4817 }
4818
4819 resumeTopActivityLocked(null);
4820 }
4821
4822 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4823 final String name = app.processName;
4824 final int uid = app.info.uid;
4825 if (Config.LOGD) Log.d(
4826 TAG, "Force removing process " + app + " (" + name
4827 + "/" + uid + ")");
4828
4829 mProcessNames.remove(name, uid);
4830 boolean needRestart = false;
4831 if (app.pid > 0 && app.pid != MY_PID) {
4832 int pid = app.pid;
4833 synchronized (mPidsSelfLocked) {
4834 mPidsSelfLocked.remove(pid);
4835 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4836 }
4837 handleAppDiedLocked(app, true);
4838 mLRUProcesses.remove(app);
4839 Process.killProcess(pid);
4840
4841 if (app.persistent) {
4842 if (!callerWillRestart) {
4843 addAppLocked(app.info);
4844 } else {
4845 needRestart = true;
4846 }
4847 }
4848 } else {
4849 mRemovedProcesses.add(app);
4850 }
4851
4852 return needRestart;
4853 }
4854
4855 private final void processStartTimedOutLocked(ProcessRecord app) {
4856 final int pid = app.pid;
4857 boolean gone = false;
4858 synchronized (mPidsSelfLocked) {
4859 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4860 if (knownApp != null && knownApp.thread == null) {
4861 mPidsSelfLocked.remove(pid);
4862 gone = true;
4863 }
4864 }
4865
4866 if (gone) {
4867 Log.w(TAG, "Process " + app + " failed to attach");
4868 mProcessNames.remove(app.processName, app.info.uid);
4869 Process.killProcess(pid);
4870 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4871 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4872 mPendingBroadcast = null;
4873 scheduleBroadcastsLocked();
4874 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004875 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4876 Log.w(TAG, "Unattached app died before backup, skipping");
4877 try {
4878 IBackupManager bm = IBackupManager.Stub.asInterface(
4879 ServiceManager.getService(Context.BACKUP_SERVICE));
4880 bm.agentDisconnected(app.info.packageName);
4881 } catch (RemoteException e) {
4882 // Can't happen; the backup manager is local
4883 }
4884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004885 } else {
4886 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4887 }
4888 }
4889
4890 private final boolean attachApplicationLocked(IApplicationThread thread,
4891 int pid) {
4892
4893 // Find the application record that is being attached... either via
4894 // the pid if we are running in multiple processes, or just pull the
4895 // next app record if we are emulating process with anonymous threads.
4896 ProcessRecord app;
4897 if (pid != MY_PID && pid >= 0) {
4898 synchronized (mPidsSelfLocked) {
4899 app = mPidsSelfLocked.get(pid);
4900 }
4901 } else if (mStartingProcesses.size() > 0) {
4902 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004903 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004904 } else {
4905 app = null;
4906 }
4907
4908 if (app == null) {
4909 Log.w(TAG, "No pending application record for pid " + pid
4910 + " (IApplicationThread " + thread + "); dropping process");
4911 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4912 if (pid > 0 && pid != MY_PID) {
4913 Process.killProcess(pid);
4914 } else {
4915 try {
4916 thread.scheduleExit();
4917 } catch (Exception e) {
4918 // Ignore exceptions.
4919 }
4920 }
4921 return false;
4922 }
4923
4924 // If this application record is still attached to a previous
4925 // process, clean it up now.
4926 if (app.thread != null) {
4927 handleAppDiedLocked(app, true);
4928 }
4929
4930 // Tell the process all about itself.
4931
4932 if (localLOGV) Log.v(
4933 TAG, "Binding process pid " + pid + " to record " + app);
4934
4935 String processName = app.processName;
4936 try {
4937 thread.asBinder().linkToDeath(new AppDeathRecipient(
4938 app, pid, thread), 0);
4939 } catch (RemoteException e) {
4940 app.resetPackageList();
4941 startProcessLocked(app, "link fail", processName);
4942 return false;
4943 }
4944
4945 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4946
4947 app.thread = thread;
4948 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004949 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004950 app.forcingToForeground = null;
4951 app.foregroundServices = false;
4952 app.debugging = false;
4953
4954 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4955
4956 List providers = generateApplicationProvidersLocked(app);
4957
4958 if (localLOGV) Log.v(
4959 TAG, "New app record " + app
4960 + " thread=" + thread.asBinder() + " pid=" + pid);
4961 try {
4962 int testMode = IApplicationThread.DEBUG_OFF;
4963 if (mDebugApp != null && mDebugApp.equals(processName)) {
4964 testMode = mWaitForDebugger
4965 ? IApplicationThread.DEBUG_WAIT
4966 : IApplicationThread.DEBUG_ON;
4967 app.debugging = true;
4968 if (mDebugTransient) {
4969 mDebugApp = mOrigDebugApp;
4970 mWaitForDebugger = mOrigWaitForDebugger;
4971 }
4972 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004973 // If the app is being launched for restore or full backup, set it up specially
4974 boolean isRestrictedBackupMode = false;
4975 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4976 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4977 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4978 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004979 ensurePackageDexOpt(app.instrumentationInfo != null
4980 ? app.instrumentationInfo.packageName
4981 : app.info.packageName);
4982 if (app.instrumentationClass != null) {
4983 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004984 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004985 thread.bindApplication(processName, app.instrumentationInfo != null
4986 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004987 app.instrumentationClass, app.instrumentationProfileFile,
4988 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004989 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004990 updateLRUListLocked(app, false);
4991 app.lastRequestedGc = SystemClock.uptimeMillis();
4992 } catch (Exception e) {
4993 // todo: Yikes! What should we do? For now we will try to
4994 // start another process, but that could easily get us in
4995 // an infinite loop of restarting processes...
4996 Log.w(TAG, "Exception thrown during bind!", e);
4997
4998 app.resetPackageList();
4999 startProcessLocked(app, "bind fail", processName);
5000 return false;
5001 }
5002
5003 // Remove this record from the list of starting applications.
5004 mPersistentStartingProcesses.remove(app);
5005 mProcessesOnHold.remove(app);
5006
5007 boolean badApp = false;
5008 boolean didSomething = false;
5009
5010 // See if the top visible activity is waiting to run in this process...
5011 HistoryRecord hr = topRunningActivityLocked(null);
5012 if (hr != null) {
5013 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5014 && processName.equals(hr.processName)) {
5015 try {
5016 if (realStartActivityLocked(hr, app, true, true)) {
5017 didSomething = true;
5018 }
5019 } catch (Exception e) {
5020 Log.w(TAG, "Exception in new application when starting activity "
5021 + hr.intent.getComponent().flattenToShortString(), e);
5022 badApp = true;
5023 }
5024 } else {
5025 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5026 }
5027 }
5028
5029 // Find any services that should be running in this process...
5030 if (!badApp && mPendingServices.size() > 0) {
5031 ServiceRecord sr = null;
5032 try {
5033 for (int i=0; i<mPendingServices.size(); i++) {
5034 sr = mPendingServices.get(i);
5035 if (app.info.uid != sr.appInfo.uid
5036 || !processName.equals(sr.processName)) {
5037 continue;
5038 }
5039
5040 mPendingServices.remove(i);
5041 i--;
5042 realStartServiceLocked(sr, app);
5043 didSomething = true;
5044 }
5045 } catch (Exception e) {
5046 Log.w(TAG, "Exception in new application when starting service "
5047 + sr.shortName, e);
5048 badApp = true;
5049 }
5050 }
5051
5052 // Check if the next broadcast receiver is in this process...
5053 BroadcastRecord br = mPendingBroadcast;
5054 if (!badApp && br != null && br.curApp == app) {
5055 try {
5056 mPendingBroadcast = null;
5057 processCurBroadcastLocked(br, app);
5058 didSomething = true;
5059 } catch (Exception e) {
5060 Log.w(TAG, "Exception in new application when starting receiver "
5061 + br.curComponent.flattenToShortString(), e);
5062 badApp = true;
5063 logBroadcastReceiverDiscard(br);
5064 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5065 br.resultExtras, br.resultAbort, true);
5066 scheduleBroadcastsLocked();
5067 }
5068 }
5069
Christopher Tate181fafa2009-05-14 11:12:14 -07005070 // Check whether the next backup agent is in this process...
5071 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5072 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005073 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005074 try {
5075 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5076 } catch (Exception e) {
5077 Log.w(TAG, "Exception scheduling backup agent creation: ");
5078 e.printStackTrace();
5079 }
5080 }
5081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005082 if (badApp) {
5083 // todo: Also need to kill application to deal with all
5084 // kinds of exceptions.
5085 handleAppDiedLocked(app, false);
5086 return false;
5087 }
5088
5089 if (!didSomething) {
5090 updateOomAdjLocked();
5091 }
5092
5093 return true;
5094 }
5095
5096 public final void attachApplication(IApplicationThread thread) {
5097 synchronized (this) {
5098 int callingPid = Binder.getCallingPid();
5099 final long origId = Binder.clearCallingIdentity();
5100 attachApplicationLocked(thread, callingPid);
5101 Binder.restoreCallingIdentity(origId);
5102 }
5103 }
5104
5105 public final void activityIdle(IBinder token) {
5106 final long origId = Binder.clearCallingIdentity();
5107 activityIdleInternal(token, false);
5108 Binder.restoreCallingIdentity(origId);
5109 }
5110
5111 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5112 boolean remove) {
5113 int N = mStoppingActivities.size();
5114 if (N <= 0) return null;
5115
5116 ArrayList<HistoryRecord> stops = null;
5117
5118 final boolean nowVisible = mResumedActivity != null
5119 && mResumedActivity.nowVisible
5120 && !mResumedActivity.waitingVisible;
5121 for (int i=0; i<N; i++) {
5122 HistoryRecord s = mStoppingActivities.get(i);
5123 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5124 + nowVisible + " waitingVisible=" + s.waitingVisible
5125 + " finishing=" + s.finishing);
5126 if (s.waitingVisible && nowVisible) {
5127 mWaitingVisibleActivities.remove(s);
5128 s.waitingVisible = false;
5129 if (s.finishing) {
5130 // If this activity is finishing, it is sitting on top of
5131 // everyone else but we now know it is no longer needed...
5132 // so get rid of it. Otherwise, we need to go through the
5133 // normal flow and hide it once we determine that it is
5134 // hidden by the activities in front of it.
5135 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5136 mWindowManager.setAppVisibility(s, false);
5137 }
5138 }
5139 if (!s.waitingVisible && remove) {
5140 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5141 if (stops == null) {
5142 stops = new ArrayList<HistoryRecord>();
5143 }
5144 stops.add(s);
5145 mStoppingActivities.remove(i);
5146 N--;
5147 i--;
5148 }
5149 }
5150
5151 return stops;
5152 }
5153
5154 void enableScreenAfterBoot() {
5155 mWindowManager.enableScreenAfterBoot();
5156 }
5157
5158 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5159 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5160
5161 ArrayList<HistoryRecord> stops = null;
5162 ArrayList<HistoryRecord> finishes = null;
5163 ArrayList<HistoryRecord> thumbnails = null;
5164 int NS = 0;
5165 int NF = 0;
5166 int NT = 0;
5167 IApplicationThread sendThumbnail = null;
5168 boolean booting = false;
5169 boolean enableScreen = false;
5170
5171 synchronized (this) {
5172 if (token != null) {
5173 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5174 }
5175
5176 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005177 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005178 if (index >= 0) {
5179 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5180
5181 // No longer need to keep the device awake.
5182 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5183 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5184 mLaunchingActivity.release();
5185 }
5186
5187 // We are now idle. If someone is waiting for a thumbnail from
5188 // us, we can now deliver.
5189 r.idle = true;
5190 scheduleAppGcsLocked();
5191 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5192 sendThumbnail = r.app.thread;
5193 r.thumbnailNeeded = false;
5194 }
5195
5196 // If this activity is fullscreen, set up to hide those under it.
5197
5198 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5199 ensureActivitiesVisibleLocked(null, 0);
5200
5201 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5202 if (!mBooted && !fromTimeout) {
5203 mBooted = true;
5204 enableScreen = true;
5205 }
5206 }
5207
5208 // Atomically retrieve all of the other things to do.
5209 stops = processStoppingActivitiesLocked(true);
5210 NS = stops != null ? stops.size() : 0;
5211 if ((NF=mFinishingActivities.size()) > 0) {
5212 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5213 mFinishingActivities.clear();
5214 }
5215 if ((NT=mCancelledThumbnails.size()) > 0) {
5216 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5217 mCancelledThumbnails.clear();
5218 }
5219
5220 booting = mBooting;
5221 mBooting = false;
5222 }
5223
5224 int i;
5225
5226 // Send thumbnail if requested.
5227 if (sendThumbnail != null) {
5228 try {
5229 sendThumbnail.requestThumbnail(token);
5230 } catch (Exception e) {
5231 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5232 sendPendingThumbnail(null, token, null, null, true);
5233 }
5234 }
5235
5236 // Stop any activities that are scheduled to do so but have been
5237 // waiting for the next one to start.
5238 for (i=0; i<NS; i++) {
5239 HistoryRecord r = (HistoryRecord)stops.get(i);
5240 synchronized (this) {
5241 if (r.finishing) {
5242 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5243 } else {
5244 stopActivityLocked(r);
5245 }
5246 }
5247 }
5248
5249 // Finish any activities that are scheduled to do so but have been
5250 // waiting for the next one to start.
5251 for (i=0; i<NF; i++) {
5252 HistoryRecord r = (HistoryRecord)finishes.get(i);
5253 synchronized (this) {
5254 destroyActivityLocked(r, true);
5255 }
5256 }
5257
5258 // Report back to any thumbnail receivers.
5259 for (i=0; i<NT; i++) {
5260 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5261 sendPendingThumbnail(r, null, null, null, true);
5262 }
5263
5264 if (booting) {
5265 // Ensure that any processes we had put on hold are now started
5266 // up.
5267 final int NP = mProcessesOnHold.size();
5268 if (NP > 0) {
5269 ArrayList<ProcessRecord> procs =
5270 new ArrayList<ProcessRecord>(mProcessesOnHold);
5271 for (int ip=0; ip<NP; ip++) {
5272 this.startProcessLocked(procs.get(ip), "on-hold", null);
5273 }
5274 }
5275 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5276 // Tell anyone interested that we are done booting!
5277 synchronized (this) {
5278 broadcastIntentLocked(null, null,
5279 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5280 null, null, 0, null, null,
5281 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5282 false, false, MY_PID, Process.SYSTEM_UID);
5283 }
5284 }
5285 }
5286
5287 trimApplications();
5288 //dump();
5289 //mWindowManager.dump();
5290
5291 if (enableScreen) {
5292 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5293 SystemClock.uptimeMillis());
5294 enableScreenAfterBoot();
5295 }
5296 }
5297
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005298 final void ensureScreenEnabled() {
5299 boolean enableScreen;
5300 synchronized (this) {
5301 enableScreen = !mBooted;
5302 mBooted = true;
5303 }
5304
5305 if (enableScreen) {
5306 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5307 SystemClock.uptimeMillis());
5308 enableScreenAfterBoot();
5309 }
5310 }
5311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005312 public final void activityPaused(IBinder token, Bundle icicle) {
5313 // Refuse possible leaked file descriptors
5314 if (icicle != null && icicle.hasFileDescriptors()) {
5315 throw new IllegalArgumentException("File descriptors passed in Bundle");
5316 }
5317
5318 final long origId = Binder.clearCallingIdentity();
5319 activityPaused(token, icicle, false);
5320 Binder.restoreCallingIdentity(origId);
5321 }
5322
5323 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5324 if (DEBUG_PAUSE) Log.v(
5325 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5326 + ", timeout=" + timeout);
5327
5328 HistoryRecord r = null;
5329
5330 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005331 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005332 if (index >= 0) {
5333 r = (HistoryRecord)mHistory.get(index);
5334 if (!timeout) {
5335 r.icicle = icicle;
5336 r.haveState = true;
5337 }
5338 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5339 if (mPausingActivity == r) {
5340 r.state = ActivityState.PAUSED;
5341 completePauseLocked();
5342 } else {
5343 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5344 System.identityHashCode(r), r.shortComponentName,
5345 mPausingActivity != null
5346 ? mPausingActivity.shortComponentName : "(none)");
5347 }
5348 }
5349 }
5350 }
5351
5352 public final void activityStopped(IBinder token, Bitmap thumbnail,
5353 CharSequence description) {
5354 if (localLOGV) Log.v(
5355 TAG, "Activity stopped: token=" + token);
5356
5357 HistoryRecord r = null;
5358
5359 final long origId = Binder.clearCallingIdentity();
5360
5361 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005362 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005363 if (index >= 0) {
5364 r = (HistoryRecord)mHistory.get(index);
5365 r.thumbnail = thumbnail;
5366 r.description = description;
5367 r.stopped = true;
5368 r.state = ActivityState.STOPPED;
5369 if (!r.finishing) {
5370 if (r.configDestroy) {
5371 destroyActivityLocked(r, true);
5372 resumeTopActivityLocked(null);
5373 }
5374 }
5375 }
5376 }
5377
5378 if (r != null) {
5379 sendPendingThumbnail(r, null, null, null, false);
5380 }
5381
5382 trimApplications();
5383
5384 Binder.restoreCallingIdentity(origId);
5385 }
5386
5387 public final void activityDestroyed(IBinder token) {
5388 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5389 synchronized (this) {
5390 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5391
Dianne Hackborn75b03852009-06-12 15:43:26 -07005392 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005393 if (index >= 0) {
5394 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5395 if (r.state == ActivityState.DESTROYING) {
5396 final long origId = Binder.clearCallingIdentity();
5397 removeActivityFromHistoryLocked(r);
5398 Binder.restoreCallingIdentity(origId);
5399 }
5400 }
5401 }
5402 }
5403
5404 public String getCallingPackage(IBinder token) {
5405 synchronized (this) {
5406 HistoryRecord r = getCallingRecordLocked(token);
5407 return r != null && r.app != null ? r.app.processName : null;
5408 }
5409 }
5410
5411 public ComponentName getCallingActivity(IBinder token) {
5412 synchronized (this) {
5413 HistoryRecord r = getCallingRecordLocked(token);
5414 return r != null ? r.intent.getComponent() : null;
5415 }
5416 }
5417
5418 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005419 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005420 if (index >= 0) {
5421 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5422 if (r != null) {
5423 return r.resultTo;
5424 }
5425 }
5426 return null;
5427 }
5428
5429 public ComponentName getActivityClassForToken(IBinder token) {
5430 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005431 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005432 if (index >= 0) {
5433 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5434 return r.intent.getComponent();
5435 }
5436 return null;
5437 }
5438 }
5439
5440 public String getPackageForToken(IBinder token) {
5441 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005442 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005443 if (index >= 0) {
5444 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5445 return r.packageName;
5446 }
5447 return null;
5448 }
5449 }
5450
5451 public IIntentSender getIntentSender(int type,
5452 String packageName, IBinder token, String resultWho,
5453 int requestCode, Intent intent, String resolvedType, int flags) {
5454 // Refuse possible leaked file descriptors
5455 if (intent != null && intent.hasFileDescriptors() == true) {
5456 throw new IllegalArgumentException("File descriptors passed in Intent");
5457 }
5458
5459 synchronized(this) {
5460 int callingUid = Binder.getCallingUid();
5461 try {
5462 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5463 Process.supportsProcesses()) {
5464 int uid = ActivityThread.getPackageManager()
5465 .getPackageUid(packageName);
5466 if (uid != Binder.getCallingUid()) {
5467 String msg = "Permission Denial: getIntentSender() from pid="
5468 + Binder.getCallingPid()
5469 + ", uid=" + Binder.getCallingUid()
5470 + ", (need uid=" + uid + ")"
5471 + " is not allowed to send as package " + packageName;
5472 Log.w(TAG, msg);
5473 throw new SecurityException(msg);
5474 }
5475 }
5476 } catch (RemoteException e) {
5477 throw new SecurityException(e);
5478 }
5479 HistoryRecord activity = null;
5480 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005481 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005482 if (index < 0) {
5483 return null;
5484 }
5485 activity = (HistoryRecord)mHistory.get(index);
5486 if (activity.finishing) {
5487 return null;
5488 }
5489 }
5490
5491 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5492 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5493 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5494 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5495 |PendingIntent.FLAG_UPDATE_CURRENT);
5496
5497 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5498 type, packageName, activity, resultWho,
5499 requestCode, intent, resolvedType, flags);
5500 WeakReference<PendingIntentRecord> ref;
5501 ref = mIntentSenderRecords.get(key);
5502 PendingIntentRecord rec = ref != null ? ref.get() : null;
5503 if (rec != null) {
5504 if (!cancelCurrent) {
5505 if (updateCurrent) {
5506 rec.key.requestIntent.replaceExtras(intent);
5507 }
5508 return rec;
5509 }
5510 rec.canceled = true;
5511 mIntentSenderRecords.remove(key);
5512 }
5513 if (noCreate) {
5514 return rec;
5515 }
5516 rec = new PendingIntentRecord(this, key, callingUid);
5517 mIntentSenderRecords.put(key, rec.ref);
5518 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5519 if (activity.pendingResults == null) {
5520 activity.pendingResults
5521 = new HashSet<WeakReference<PendingIntentRecord>>();
5522 }
5523 activity.pendingResults.add(rec.ref);
5524 }
5525 return rec;
5526 }
5527 }
5528
5529 public void cancelIntentSender(IIntentSender sender) {
5530 if (!(sender instanceof PendingIntentRecord)) {
5531 return;
5532 }
5533 synchronized(this) {
5534 PendingIntentRecord rec = (PendingIntentRecord)sender;
5535 try {
5536 int uid = ActivityThread.getPackageManager()
5537 .getPackageUid(rec.key.packageName);
5538 if (uid != Binder.getCallingUid()) {
5539 String msg = "Permission Denial: cancelIntentSender() from pid="
5540 + Binder.getCallingPid()
5541 + ", uid=" + Binder.getCallingUid()
5542 + " is not allowed to cancel packges "
5543 + rec.key.packageName;
5544 Log.w(TAG, msg);
5545 throw new SecurityException(msg);
5546 }
5547 } catch (RemoteException e) {
5548 throw new SecurityException(e);
5549 }
5550 cancelIntentSenderLocked(rec, true);
5551 }
5552 }
5553
5554 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5555 rec.canceled = true;
5556 mIntentSenderRecords.remove(rec.key);
5557 if (cleanActivity && rec.key.activity != null) {
5558 rec.key.activity.pendingResults.remove(rec.ref);
5559 }
5560 }
5561
5562 public String getPackageForIntentSender(IIntentSender pendingResult) {
5563 if (!(pendingResult instanceof PendingIntentRecord)) {
5564 return null;
5565 }
5566 synchronized(this) {
5567 try {
5568 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5569 return res.key.packageName;
5570 } catch (ClassCastException e) {
5571 }
5572 }
5573 return null;
5574 }
5575
5576 public void setProcessLimit(int max) {
5577 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5578 "setProcessLimit()");
5579 mProcessLimit = max;
5580 }
5581
5582 public int getProcessLimit() {
5583 return mProcessLimit;
5584 }
5585
5586 void foregroundTokenDied(ForegroundToken token) {
5587 synchronized (ActivityManagerService.this) {
5588 synchronized (mPidsSelfLocked) {
5589 ForegroundToken cur
5590 = mForegroundProcesses.get(token.pid);
5591 if (cur != token) {
5592 return;
5593 }
5594 mForegroundProcesses.remove(token.pid);
5595 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5596 if (pr == null) {
5597 return;
5598 }
5599 pr.forcingToForeground = null;
5600 pr.foregroundServices = false;
5601 }
5602 updateOomAdjLocked();
5603 }
5604 }
5605
5606 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5607 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5608 "setProcessForeground()");
5609 synchronized(this) {
5610 boolean changed = false;
5611
5612 synchronized (mPidsSelfLocked) {
5613 ProcessRecord pr = mPidsSelfLocked.get(pid);
5614 if (pr == null) {
5615 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5616 return;
5617 }
5618 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5619 if (oldToken != null) {
5620 oldToken.token.unlinkToDeath(oldToken, 0);
5621 mForegroundProcesses.remove(pid);
5622 pr.forcingToForeground = null;
5623 changed = true;
5624 }
5625 if (isForeground && token != null) {
5626 ForegroundToken newToken = new ForegroundToken() {
5627 public void binderDied() {
5628 foregroundTokenDied(this);
5629 }
5630 };
5631 newToken.pid = pid;
5632 newToken.token = token;
5633 try {
5634 token.linkToDeath(newToken, 0);
5635 mForegroundProcesses.put(pid, newToken);
5636 pr.forcingToForeground = token;
5637 changed = true;
5638 } catch (RemoteException e) {
5639 // If the process died while doing this, we will later
5640 // do the cleanup with the process death link.
5641 }
5642 }
5643 }
5644
5645 if (changed) {
5646 updateOomAdjLocked();
5647 }
5648 }
5649 }
5650
5651 // =========================================================
5652 // PERMISSIONS
5653 // =========================================================
5654
5655 static class PermissionController extends IPermissionController.Stub {
5656 ActivityManagerService mActivityManagerService;
5657 PermissionController(ActivityManagerService activityManagerService) {
5658 mActivityManagerService = activityManagerService;
5659 }
5660
5661 public boolean checkPermission(String permission, int pid, int uid) {
5662 return mActivityManagerService.checkPermission(permission, pid,
5663 uid) == PackageManager.PERMISSION_GRANTED;
5664 }
5665 }
5666
5667 /**
5668 * This can be called with or without the global lock held.
5669 */
5670 int checkComponentPermission(String permission, int pid, int uid,
5671 int reqUid) {
5672 // We might be performing an operation on behalf of an indirect binder
5673 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5674 // client identity accordingly before proceeding.
5675 Identity tlsIdentity = sCallerIdentity.get();
5676 if (tlsIdentity != null) {
5677 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5678 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5679 uid = tlsIdentity.uid;
5680 pid = tlsIdentity.pid;
5681 }
5682
5683 // Root, system server and our own process get to do everything.
5684 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5685 !Process.supportsProcesses()) {
5686 return PackageManager.PERMISSION_GRANTED;
5687 }
5688 // If the target requires a specific UID, always fail for others.
5689 if (reqUid >= 0 && uid != reqUid) {
5690 return PackageManager.PERMISSION_DENIED;
5691 }
5692 if (permission == null) {
5693 return PackageManager.PERMISSION_GRANTED;
5694 }
5695 try {
5696 return ActivityThread.getPackageManager()
5697 .checkUidPermission(permission, uid);
5698 } catch (RemoteException e) {
5699 // Should never happen, but if it does... deny!
5700 Log.e(TAG, "PackageManager is dead?!?", e);
5701 }
5702 return PackageManager.PERMISSION_DENIED;
5703 }
5704
5705 /**
5706 * As the only public entry point for permissions checking, this method
5707 * can enforce the semantic that requesting a check on a null global
5708 * permission is automatically denied. (Internally a null permission
5709 * string is used when calling {@link #checkComponentPermission} in cases
5710 * when only uid-based security is needed.)
5711 *
5712 * This can be called with or without the global lock held.
5713 */
5714 public int checkPermission(String permission, int pid, int uid) {
5715 if (permission == null) {
5716 return PackageManager.PERMISSION_DENIED;
5717 }
5718 return checkComponentPermission(permission, pid, uid, -1);
5719 }
5720
5721 /**
5722 * Binder IPC calls go through the public entry point.
5723 * This can be called with or without the global lock held.
5724 */
5725 int checkCallingPermission(String permission) {
5726 return checkPermission(permission,
5727 Binder.getCallingPid(),
5728 Binder.getCallingUid());
5729 }
5730
5731 /**
5732 * This can be called with or without the global lock held.
5733 */
5734 void enforceCallingPermission(String permission, String func) {
5735 if (checkCallingPermission(permission)
5736 == PackageManager.PERMISSION_GRANTED) {
5737 return;
5738 }
5739
5740 String msg = "Permission Denial: " + func + " from pid="
5741 + Binder.getCallingPid()
5742 + ", uid=" + Binder.getCallingUid()
5743 + " requires " + permission;
5744 Log.w(TAG, msg);
5745 throw new SecurityException(msg);
5746 }
5747
5748 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5749 ProviderInfo pi, int uid, int modeFlags) {
5750 try {
5751 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5752 if ((pi.readPermission != null) &&
5753 (pm.checkUidPermission(pi.readPermission, uid)
5754 != PackageManager.PERMISSION_GRANTED)) {
5755 return false;
5756 }
5757 }
5758 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5759 if ((pi.writePermission != null) &&
5760 (pm.checkUidPermission(pi.writePermission, uid)
5761 != PackageManager.PERMISSION_GRANTED)) {
5762 return false;
5763 }
5764 }
5765 return true;
5766 } catch (RemoteException e) {
5767 return false;
5768 }
5769 }
5770
5771 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5772 int modeFlags) {
5773 // Root gets to do everything.
5774 if (uid == 0 || !Process.supportsProcesses()) {
5775 return true;
5776 }
5777 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5778 if (perms == null) return false;
5779 UriPermission perm = perms.get(uri);
5780 if (perm == null) return false;
5781 return (modeFlags&perm.modeFlags) == modeFlags;
5782 }
5783
5784 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5785 // Another redirected-binder-call permissions check as in
5786 // {@link checkComponentPermission}.
5787 Identity tlsIdentity = sCallerIdentity.get();
5788 if (tlsIdentity != null) {
5789 uid = tlsIdentity.uid;
5790 pid = tlsIdentity.pid;
5791 }
5792
5793 // Our own process gets to do everything.
5794 if (pid == MY_PID) {
5795 return PackageManager.PERMISSION_GRANTED;
5796 }
5797 synchronized(this) {
5798 return checkUriPermissionLocked(uri, uid, modeFlags)
5799 ? PackageManager.PERMISSION_GRANTED
5800 : PackageManager.PERMISSION_DENIED;
5801 }
5802 }
5803
5804 private void grantUriPermissionLocked(int callingUid,
5805 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5806 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5807 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5808 if (modeFlags == 0) {
5809 return;
5810 }
5811
5812 final IPackageManager pm = ActivityThread.getPackageManager();
5813
5814 // If this is not a content: uri, we can't do anything with it.
5815 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5816 return;
5817 }
5818
5819 String name = uri.getAuthority();
5820 ProviderInfo pi = null;
5821 ContentProviderRecord cpr
5822 = (ContentProviderRecord)mProvidersByName.get(name);
5823 if (cpr != null) {
5824 pi = cpr.info;
5825 } else {
5826 try {
5827 pi = pm.resolveContentProvider(name,
5828 PackageManager.GET_URI_PERMISSION_PATTERNS);
5829 } catch (RemoteException ex) {
5830 }
5831 }
5832 if (pi == null) {
5833 Log.w(TAG, "No content provider found for: " + name);
5834 return;
5835 }
5836
5837 int targetUid;
5838 try {
5839 targetUid = pm.getPackageUid(targetPkg);
5840 if (targetUid < 0) {
5841 return;
5842 }
5843 } catch (RemoteException ex) {
5844 return;
5845 }
5846
5847 // First... does the target actually need this permission?
5848 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5849 // No need to grant the target this permission.
5850 return;
5851 }
5852
5853 // Second... maybe someone else has already granted the
5854 // permission?
5855 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5856 // No need to grant the target this permission.
5857 return;
5858 }
5859
5860 // Third... is the provider allowing granting of URI permissions?
5861 if (!pi.grantUriPermissions) {
5862 throw new SecurityException("Provider " + pi.packageName
5863 + "/" + pi.name
5864 + " does not allow granting of Uri permissions (uri "
5865 + uri + ")");
5866 }
5867 if (pi.uriPermissionPatterns != null) {
5868 final int N = pi.uriPermissionPatterns.length;
5869 boolean allowed = false;
5870 for (int i=0; i<N; i++) {
5871 if (pi.uriPermissionPatterns[i] != null
5872 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5873 allowed = true;
5874 break;
5875 }
5876 }
5877 if (!allowed) {
5878 throw new SecurityException("Provider " + pi.packageName
5879 + "/" + pi.name
5880 + " does not allow granting of permission to path of Uri "
5881 + uri);
5882 }
5883 }
5884
5885 // Fourth... does the caller itself have permission to access
5886 // this uri?
5887 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5888 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5889 throw new SecurityException("Uid " + callingUid
5890 + " does not have permission to uri " + uri);
5891 }
5892 }
5893
5894 // Okay! So here we are: the caller has the assumed permission
5895 // to the uri, and the target doesn't. Let's now give this to
5896 // the target.
5897
5898 HashMap<Uri, UriPermission> targetUris
5899 = mGrantedUriPermissions.get(targetUid);
5900 if (targetUris == null) {
5901 targetUris = new HashMap<Uri, UriPermission>();
5902 mGrantedUriPermissions.put(targetUid, targetUris);
5903 }
5904
5905 UriPermission perm = targetUris.get(uri);
5906 if (perm == null) {
5907 perm = new UriPermission(targetUid, uri);
5908 targetUris.put(uri, perm);
5909
5910 }
5911 perm.modeFlags |= modeFlags;
5912 if (activity == null) {
5913 perm.globalModeFlags |= modeFlags;
5914 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5915 perm.readActivities.add(activity);
5916 if (activity.readUriPermissions == null) {
5917 activity.readUriPermissions = new HashSet<UriPermission>();
5918 }
5919 activity.readUriPermissions.add(perm);
5920 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5921 perm.writeActivities.add(activity);
5922 if (activity.writeUriPermissions == null) {
5923 activity.writeUriPermissions = new HashSet<UriPermission>();
5924 }
5925 activity.writeUriPermissions.add(perm);
5926 }
5927 }
5928
5929 private void grantUriPermissionFromIntentLocked(int callingUid,
5930 String targetPkg, Intent intent, HistoryRecord activity) {
5931 if (intent == null) {
5932 return;
5933 }
5934 Uri data = intent.getData();
5935 if (data == null) {
5936 return;
5937 }
5938 grantUriPermissionLocked(callingUid, targetPkg, data,
5939 intent.getFlags(), activity);
5940 }
5941
5942 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5943 Uri uri, int modeFlags) {
5944 synchronized(this) {
5945 final ProcessRecord r = getRecordForAppLocked(caller);
5946 if (r == null) {
5947 throw new SecurityException("Unable to find app for caller "
5948 + caller
5949 + " when granting permission to uri " + uri);
5950 }
5951 if (targetPkg == null) {
5952 Log.w(TAG, "grantUriPermission: null target");
5953 return;
5954 }
5955 if (uri == null) {
5956 Log.w(TAG, "grantUriPermission: null uri");
5957 return;
5958 }
5959
5960 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5961 null);
5962 }
5963 }
5964
5965 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5966 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5967 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5968 HashMap<Uri, UriPermission> perms
5969 = mGrantedUriPermissions.get(perm.uid);
5970 if (perms != null) {
5971 perms.remove(perm.uri);
5972 if (perms.size() == 0) {
5973 mGrantedUriPermissions.remove(perm.uid);
5974 }
5975 }
5976 }
5977 }
5978
5979 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5980 if (activity.readUriPermissions != null) {
5981 for (UriPermission perm : activity.readUriPermissions) {
5982 perm.readActivities.remove(activity);
5983 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5984 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5985 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5986 removeUriPermissionIfNeededLocked(perm);
5987 }
5988 }
5989 }
5990 if (activity.writeUriPermissions != null) {
5991 for (UriPermission perm : activity.writeUriPermissions) {
5992 perm.writeActivities.remove(activity);
5993 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5994 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5995 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5996 removeUriPermissionIfNeededLocked(perm);
5997 }
5998 }
5999 }
6000 }
6001
6002 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6003 int modeFlags) {
6004 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6005 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6006 if (modeFlags == 0) {
6007 return;
6008 }
6009
6010 final IPackageManager pm = ActivityThread.getPackageManager();
6011
6012 final String authority = uri.getAuthority();
6013 ProviderInfo pi = null;
6014 ContentProviderRecord cpr
6015 = (ContentProviderRecord)mProvidersByName.get(authority);
6016 if (cpr != null) {
6017 pi = cpr.info;
6018 } else {
6019 try {
6020 pi = pm.resolveContentProvider(authority,
6021 PackageManager.GET_URI_PERMISSION_PATTERNS);
6022 } catch (RemoteException ex) {
6023 }
6024 }
6025 if (pi == null) {
6026 Log.w(TAG, "No content provider found for: " + authority);
6027 return;
6028 }
6029
6030 // Does the caller have this permission on the URI?
6031 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6032 // Right now, if you are not the original owner of the permission,
6033 // you are not allowed to revoke it.
6034 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6035 throw new SecurityException("Uid " + callingUid
6036 + " does not have permission to uri " + uri);
6037 //}
6038 }
6039
6040 // Go through all of the permissions and remove any that match.
6041 final List<String> SEGMENTS = uri.getPathSegments();
6042 if (SEGMENTS != null) {
6043 final int NS = SEGMENTS.size();
6044 int N = mGrantedUriPermissions.size();
6045 for (int i=0; i<N; i++) {
6046 HashMap<Uri, UriPermission> perms
6047 = mGrantedUriPermissions.valueAt(i);
6048 Iterator<UriPermission> it = perms.values().iterator();
6049 toploop:
6050 while (it.hasNext()) {
6051 UriPermission perm = it.next();
6052 Uri targetUri = perm.uri;
6053 if (!authority.equals(targetUri.getAuthority())) {
6054 continue;
6055 }
6056 List<String> targetSegments = targetUri.getPathSegments();
6057 if (targetSegments == null) {
6058 continue;
6059 }
6060 if (targetSegments.size() < NS) {
6061 continue;
6062 }
6063 for (int j=0; j<NS; j++) {
6064 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6065 continue toploop;
6066 }
6067 }
6068 perm.clearModes(modeFlags);
6069 if (perm.modeFlags == 0) {
6070 it.remove();
6071 }
6072 }
6073 if (perms.size() == 0) {
6074 mGrantedUriPermissions.remove(
6075 mGrantedUriPermissions.keyAt(i));
6076 N--;
6077 i--;
6078 }
6079 }
6080 }
6081 }
6082
6083 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6084 int modeFlags) {
6085 synchronized(this) {
6086 final ProcessRecord r = getRecordForAppLocked(caller);
6087 if (r == null) {
6088 throw new SecurityException("Unable to find app for caller "
6089 + caller
6090 + " when revoking permission to uri " + uri);
6091 }
6092 if (uri == null) {
6093 Log.w(TAG, "revokeUriPermission: null uri");
6094 return;
6095 }
6096
6097 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6098 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6099 if (modeFlags == 0) {
6100 return;
6101 }
6102
6103 final IPackageManager pm = ActivityThread.getPackageManager();
6104
6105 final String authority = uri.getAuthority();
6106 ProviderInfo pi = null;
6107 ContentProviderRecord cpr
6108 = (ContentProviderRecord)mProvidersByName.get(authority);
6109 if (cpr != null) {
6110 pi = cpr.info;
6111 } else {
6112 try {
6113 pi = pm.resolveContentProvider(authority,
6114 PackageManager.GET_URI_PERMISSION_PATTERNS);
6115 } catch (RemoteException ex) {
6116 }
6117 }
6118 if (pi == null) {
6119 Log.w(TAG, "No content provider found for: " + authority);
6120 return;
6121 }
6122
6123 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6124 }
6125 }
6126
6127 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6128 synchronized (this) {
6129 ProcessRecord app =
6130 who != null ? getRecordForAppLocked(who) : null;
6131 if (app == null) return;
6132
6133 Message msg = Message.obtain();
6134 msg.what = WAIT_FOR_DEBUGGER_MSG;
6135 msg.obj = app;
6136 msg.arg1 = waiting ? 1 : 0;
6137 mHandler.sendMessage(msg);
6138 }
6139 }
6140
6141 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6142 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006143 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006144 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006145 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006146 }
6147
6148 // =========================================================
6149 // TASK MANAGEMENT
6150 // =========================================================
6151
6152 public List getTasks(int maxNum, int flags,
6153 IThumbnailReceiver receiver) {
6154 ArrayList list = new ArrayList();
6155
6156 PendingThumbnailsRecord pending = null;
6157 IApplicationThread topThumbnail = null;
6158 HistoryRecord topRecord = null;
6159
6160 synchronized(this) {
6161 if (localLOGV) Log.v(
6162 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6163 + ", receiver=" + receiver);
6164
6165 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6166 != PackageManager.PERMISSION_GRANTED) {
6167 if (receiver != null) {
6168 // If the caller wants to wait for pending thumbnails,
6169 // it ain't gonna get them.
6170 try {
6171 receiver.finished();
6172 } catch (RemoteException ex) {
6173 }
6174 }
6175 String msg = "Permission Denial: getTasks() from pid="
6176 + Binder.getCallingPid()
6177 + ", uid=" + Binder.getCallingUid()
6178 + " requires " + android.Manifest.permission.GET_TASKS;
6179 Log.w(TAG, msg);
6180 throw new SecurityException(msg);
6181 }
6182
6183 int pos = mHistory.size()-1;
6184 HistoryRecord next =
6185 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6186 HistoryRecord top = null;
6187 CharSequence topDescription = null;
6188 TaskRecord curTask = null;
6189 int numActivities = 0;
6190 int numRunning = 0;
6191 while (pos >= 0 && maxNum > 0) {
6192 final HistoryRecord r = next;
6193 pos--;
6194 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6195
6196 // Initialize state for next task if needed.
6197 if (top == null ||
6198 (top.state == ActivityState.INITIALIZING
6199 && top.task == r.task)) {
6200 top = r;
6201 topDescription = r.description;
6202 curTask = r.task;
6203 numActivities = numRunning = 0;
6204 }
6205
6206 // Add 'r' into the current task.
6207 numActivities++;
6208 if (r.app != null && r.app.thread != null) {
6209 numRunning++;
6210 }
6211 if (topDescription == null) {
6212 topDescription = r.description;
6213 }
6214
6215 if (localLOGV) Log.v(
6216 TAG, r.intent.getComponent().flattenToShortString()
6217 + ": task=" + r.task);
6218
6219 // If the next one is a different task, generate a new
6220 // TaskInfo entry for what we have.
6221 if (next == null || next.task != curTask) {
6222 ActivityManager.RunningTaskInfo ci
6223 = new ActivityManager.RunningTaskInfo();
6224 ci.id = curTask.taskId;
6225 ci.baseActivity = r.intent.getComponent();
6226 ci.topActivity = top.intent.getComponent();
6227 ci.thumbnail = top.thumbnail;
6228 ci.description = topDescription;
6229 ci.numActivities = numActivities;
6230 ci.numRunning = numRunning;
6231 //System.out.println(
6232 // "#" + maxNum + ": " + " descr=" + ci.description);
6233 if (ci.thumbnail == null && receiver != null) {
6234 if (localLOGV) Log.v(
6235 TAG, "State=" + top.state + "Idle=" + top.idle
6236 + " app=" + top.app
6237 + " thr=" + (top.app != null ? top.app.thread : null));
6238 if (top.state == ActivityState.RESUMED
6239 || top.state == ActivityState.PAUSING) {
6240 if (top.idle && top.app != null
6241 && top.app.thread != null) {
6242 topRecord = top;
6243 topThumbnail = top.app.thread;
6244 } else {
6245 top.thumbnailNeeded = true;
6246 }
6247 }
6248 if (pending == null) {
6249 pending = new PendingThumbnailsRecord(receiver);
6250 }
6251 pending.pendingRecords.add(top);
6252 }
6253 list.add(ci);
6254 maxNum--;
6255 top = null;
6256 }
6257 }
6258
6259 if (pending != null) {
6260 mPendingThumbnails.add(pending);
6261 }
6262 }
6263
6264 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6265
6266 if (topThumbnail != null) {
6267 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6268 try {
6269 topThumbnail.requestThumbnail(topRecord);
6270 } catch (Exception e) {
6271 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6272 sendPendingThumbnail(null, topRecord, null, null, true);
6273 }
6274 }
6275
6276 if (pending == null && receiver != null) {
6277 // In this case all thumbnails were available and the client
6278 // is being asked to be told when the remaining ones come in...
6279 // which is unusually, since the top-most currently running
6280 // activity should never have a canned thumbnail! Oh well.
6281 try {
6282 receiver.finished();
6283 } catch (RemoteException ex) {
6284 }
6285 }
6286
6287 return list;
6288 }
6289
6290 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6291 int flags) {
6292 synchronized (this) {
6293 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6294 "getRecentTasks()");
6295
6296 final int N = mRecentTasks.size();
6297 ArrayList<ActivityManager.RecentTaskInfo> res
6298 = new ArrayList<ActivityManager.RecentTaskInfo>(
6299 maxNum < N ? maxNum : N);
6300 for (int i=0; i<N && maxNum > 0; i++) {
6301 TaskRecord tr = mRecentTasks.get(i);
6302 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6303 || (tr.intent == null)
6304 || ((tr.intent.getFlags()
6305 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6306 ActivityManager.RecentTaskInfo rti
6307 = new ActivityManager.RecentTaskInfo();
6308 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6309 rti.baseIntent = new Intent(
6310 tr.intent != null ? tr.intent : tr.affinityIntent);
6311 rti.origActivity = tr.origActivity;
6312 res.add(rti);
6313 maxNum--;
6314 }
6315 }
6316 return res;
6317 }
6318 }
6319
6320 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6321 int j;
6322 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6323 TaskRecord jt = startTask;
6324
6325 // First look backwards
6326 for (j=startIndex-1; j>=0; j--) {
6327 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6328 if (r.task != jt) {
6329 jt = r.task;
6330 if (affinity.equals(jt.affinity)) {
6331 return j;
6332 }
6333 }
6334 }
6335
6336 // Now look forwards
6337 final int N = mHistory.size();
6338 jt = startTask;
6339 for (j=startIndex+1; j<N; j++) {
6340 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6341 if (r.task != jt) {
6342 if (affinity.equals(jt.affinity)) {
6343 return j;
6344 }
6345 jt = r.task;
6346 }
6347 }
6348
6349 // Might it be at the top?
6350 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6351 return N-1;
6352 }
6353
6354 return -1;
6355 }
6356
6357 /**
6358 * Perform a reset of the given task, if needed as part of launching it.
6359 * Returns the new HistoryRecord at the top of the task.
6360 */
6361 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6362 HistoryRecord newActivity) {
6363 boolean forceReset = (newActivity.info.flags
6364 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6365 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6366 if ((newActivity.info.flags
6367 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6368 forceReset = true;
6369 }
6370 }
6371
6372 final TaskRecord task = taskTop.task;
6373
6374 // We are going to move through the history list so that we can look
6375 // at each activity 'target' with 'below' either the interesting
6376 // activity immediately below it in the stack or null.
6377 HistoryRecord target = null;
6378 int targetI = 0;
6379 int taskTopI = -1;
6380 int replyChainEnd = -1;
6381 int lastReparentPos = -1;
6382 for (int i=mHistory.size()-1; i>=-1; i--) {
6383 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6384
6385 if (below != null && below.finishing) {
6386 continue;
6387 }
6388 if (target == null) {
6389 target = below;
6390 targetI = i;
6391 // If we were in the middle of a reply chain before this
6392 // task, it doesn't appear like the root of the chain wants
6393 // anything interesting, so drop it.
6394 replyChainEnd = -1;
6395 continue;
6396 }
6397
6398 final int flags = target.info.flags;
6399
6400 final boolean finishOnTaskLaunch =
6401 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6402 final boolean allowTaskReparenting =
6403 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6404
6405 if (target.task == task) {
6406 // We are inside of the task being reset... we'll either
6407 // finish this activity, push it out for another task,
6408 // or leave it as-is. We only do this
6409 // for activities that are not the root of the task (since
6410 // if we finish the root, we may no longer have the task!).
6411 if (taskTopI < 0) {
6412 taskTopI = targetI;
6413 }
6414 if (below != null && below.task == task) {
6415 final boolean clearWhenTaskReset =
6416 (target.intent.getFlags()
6417 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006418 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006419 // If this activity is sending a reply to a previous
6420 // activity, we can't do anything with it now until
6421 // we reach the start of the reply chain.
6422 // XXX note that we are assuming the result is always
6423 // to the previous activity, which is almost always
6424 // the case but we really shouldn't count on.
6425 if (replyChainEnd < 0) {
6426 replyChainEnd = targetI;
6427 }
Ed Heyl73798232009-03-24 21:32:21 -07006428 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006429 && target.taskAffinity != null
6430 && !target.taskAffinity.equals(task.affinity)) {
6431 // If this activity has an affinity for another
6432 // task, then we need to move it out of here. We will
6433 // move it as far out of the way as possible, to the
6434 // bottom of the activity stack. This also keeps it
6435 // correctly ordered with any activities we previously
6436 // moved.
6437 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6438 if (target.taskAffinity != null
6439 && target.taskAffinity.equals(p.task.affinity)) {
6440 // If the activity currently at the bottom has the
6441 // same task affinity as the one we are moving,
6442 // then merge it into the same task.
6443 target.task = p.task;
6444 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6445 + " out to bottom task " + p.task);
6446 } else {
6447 mCurTask++;
6448 if (mCurTask <= 0) {
6449 mCurTask = 1;
6450 }
6451 target.task = new TaskRecord(mCurTask, target.info, null,
6452 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6453 target.task.affinityIntent = target.intent;
6454 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6455 + " out to new task " + target.task);
6456 }
6457 mWindowManager.setAppGroupId(target, task.taskId);
6458 if (replyChainEnd < 0) {
6459 replyChainEnd = targetI;
6460 }
6461 int dstPos = 0;
6462 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6463 p = (HistoryRecord)mHistory.get(srcPos);
6464 if (p.finishing) {
6465 continue;
6466 }
6467 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6468 + " out to target's task " + target.task);
6469 task.numActivities--;
6470 p.task = target.task;
6471 target.task.numActivities++;
6472 mHistory.remove(srcPos);
6473 mHistory.add(dstPos, p);
6474 mWindowManager.moveAppToken(dstPos, p);
6475 mWindowManager.setAppGroupId(p, p.task.taskId);
6476 dstPos++;
6477 if (VALIDATE_TOKENS) {
6478 mWindowManager.validateAppTokens(mHistory);
6479 }
6480 i++;
6481 }
6482 if (taskTop == p) {
6483 taskTop = below;
6484 }
6485 if (taskTopI == replyChainEnd) {
6486 taskTopI = -1;
6487 }
6488 replyChainEnd = -1;
6489 addRecentTask(target.task);
6490 } else if (forceReset || finishOnTaskLaunch
6491 || clearWhenTaskReset) {
6492 // If the activity should just be removed -- either
6493 // because it asks for it, or the task should be
6494 // cleared -- then finish it and anything that is
6495 // part of its reply chain.
6496 if (clearWhenTaskReset) {
6497 // In this case, we want to finish this activity
6498 // and everything above it, so be sneaky and pretend
6499 // like these are all in the reply chain.
6500 replyChainEnd = targetI+1;
6501 while (replyChainEnd < mHistory.size() &&
6502 ((HistoryRecord)mHistory.get(
6503 replyChainEnd)).task == task) {
6504 replyChainEnd++;
6505 }
6506 replyChainEnd--;
6507 } else if (replyChainEnd < 0) {
6508 replyChainEnd = targetI;
6509 }
6510 HistoryRecord p = null;
6511 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6512 p = (HistoryRecord)mHistory.get(srcPos);
6513 if (p.finishing) {
6514 continue;
6515 }
6516 if (finishActivityLocked(p, srcPos,
6517 Activity.RESULT_CANCELED, null, "reset")) {
6518 replyChainEnd--;
6519 srcPos--;
6520 }
6521 }
6522 if (taskTop == p) {
6523 taskTop = below;
6524 }
6525 if (taskTopI == replyChainEnd) {
6526 taskTopI = -1;
6527 }
6528 replyChainEnd = -1;
6529 } else {
6530 // If we were in the middle of a chain, well the
6531 // activity that started it all doesn't want anything
6532 // special, so leave it all as-is.
6533 replyChainEnd = -1;
6534 }
6535 } else {
6536 // Reached the bottom of the task -- any reply chain
6537 // should be left as-is.
6538 replyChainEnd = -1;
6539 }
6540
6541 } else if (target.resultTo != null) {
6542 // If this activity is sending a reply to a previous
6543 // activity, we can't do anything with it now until
6544 // we reach the start of the reply chain.
6545 // XXX note that we are assuming the result is always
6546 // to the previous activity, which is almost always
6547 // the case but we really shouldn't count on.
6548 if (replyChainEnd < 0) {
6549 replyChainEnd = targetI;
6550 }
6551
6552 } else if (taskTopI >= 0 && allowTaskReparenting
6553 && task.affinity != null
6554 && task.affinity.equals(target.taskAffinity)) {
6555 // We are inside of another task... if this activity has
6556 // an affinity for our task, then either remove it if we are
6557 // clearing or move it over to our task. Note that
6558 // we currently punt on the case where we are resetting a
6559 // task that is not at the top but who has activities above
6560 // with an affinity to it... this is really not a normal
6561 // case, and we will need to later pull that task to the front
6562 // and usually at that point we will do the reset and pick
6563 // up those remaining activities. (This only happens if
6564 // someone starts an activity in a new task from an activity
6565 // in a task that is not currently on top.)
6566 if (forceReset || finishOnTaskLaunch) {
6567 if (replyChainEnd < 0) {
6568 replyChainEnd = targetI;
6569 }
6570 HistoryRecord p = null;
6571 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6572 p = (HistoryRecord)mHistory.get(srcPos);
6573 if (p.finishing) {
6574 continue;
6575 }
6576 if (finishActivityLocked(p, srcPos,
6577 Activity.RESULT_CANCELED, null, "reset")) {
6578 taskTopI--;
6579 lastReparentPos--;
6580 replyChainEnd--;
6581 srcPos--;
6582 }
6583 }
6584 replyChainEnd = -1;
6585 } else {
6586 if (replyChainEnd < 0) {
6587 replyChainEnd = targetI;
6588 }
6589 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6590 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6591 if (p.finishing) {
6592 continue;
6593 }
6594 if (lastReparentPos < 0) {
6595 lastReparentPos = taskTopI;
6596 taskTop = p;
6597 } else {
6598 lastReparentPos--;
6599 }
6600 mHistory.remove(srcPos);
6601 p.task.numActivities--;
6602 p.task = task;
6603 mHistory.add(lastReparentPos, p);
6604 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6605 + " in to resetting task " + task);
6606 task.numActivities++;
6607 mWindowManager.moveAppToken(lastReparentPos, p);
6608 mWindowManager.setAppGroupId(p, p.task.taskId);
6609 if (VALIDATE_TOKENS) {
6610 mWindowManager.validateAppTokens(mHistory);
6611 }
6612 }
6613 replyChainEnd = -1;
6614
6615 // Now we've moved it in to place... but what if this is
6616 // a singleTop activity and we have put it on top of another
6617 // instance of the same activity? Then we drop the instance
6618 // below so it remains singleTop.
6619 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6620 for (int j=lastReparentPos-1; j>=0; j--) {
6621 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6622 if (p.finishing) {
6623 continue;
6624 }
6625 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6626 if (finishActivityLocked(p, j,
6627 Activity.RESULT_CANCELED, null, "replace")) {
6628 taskTopI--;
6629 lastReparentPos--;
6630 }
6631 }
6632 }
6633 }
6634 }
6635 }
6636
6637 target = below;
6638 targetI = i;
6639 }
6640
6641 return taskTop;
6642 }
6643
6644 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006645 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006646 */
6647 public void moveTaskToFront(int task) {
6648 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6649 "moveTaskToFront()");
6650
6651 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006652 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6653 Binder.getCallingUid(), "Task to front")) {
6654 return;
6655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006656 final long origId = Binder.clearCallingIdentity();
6657 try {
6658 int N = mRecentTasks.size();
6659 for (int i=0; i<N; i++) {
6660 TaskRecord tr = mRecentTasks.get(i);
6661 if (tr.taskId == task) {
6662 moveTaskToFrontLocked(tr);
6663 return;
6664 }
6665 }
6666 for (int i=mHistory.size()-1; i>=0; i--) {
6667 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6668 if (hr.task.taskId == task) {
6669 moveTaskToFrontLocked(hr.task);
6670 return;
6671 }
6672 }
6673 } finally {
6674 Binder.restoreCallingIdentity(origId);
6675 }
6676 }
6677 }
6678
6679 private final void moveTaskToFrontLocked(TaskRecord tr) {
6680 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6681
6682 final int task = tr.taskId;
6683 int top = mHistory.size()-1;
6684
6685 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6686 // nothing to do!
6687 return;
6688 }
6689
6690 if (DEBUG_TRANSITION) Log.v(TAG,
6691 "Prepare to front transition: task=" + tr);
6692 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6693
6694 ArrayList moved = new ArrayList();
6695
6696 // Applying the affinities may have removed entries from the history,
6697 // so get the size again.
6698 top = mHistory.size()-1;
6699 int pos = top;
6700
6701 // Shift all activities with this task up to the top
6702 // of the stack, keeping them in the same internal order.
6703 while (pos >= 0) {
6704 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6705 if (localLOGV) Log.v(
6706 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6707 boolean first = true;
6708 if (r.task.taskId == task) {
6709 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6710 mHistory.remove(pos);
6711 mHistory.add(top, r);
6712 moved.add(0, r);
6713 top--;
6714 if (first) {
6715 addRecentTask(r.task);
6716 first = false;
6717 }
6718 }
6719 pos--;
6720 }
6721
6722 mWindowManager.moveAppTokensToTop(moved);
6723 if (VALIDATE_TOKENS) {
6724 mWindowManager.validateAppTokens(mHistory);
6725 }
6726
6727 finishTaskMove(task);
6728 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6729 }
6730
6731 private final void finishTaskMove(int task) {
6732 resumeTopActivityLocked(null);
6733 }
6734
6735 public void moveTaskToBack(int task) {
6736 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6737 "moveTaskToBack()");
6738
6739 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006740 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6741 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6742 Binder.getCallingUid(), "Task to back")) {
6743 return;
6744 }
6745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006746 final long origId = Binder.clearCallingIdentity();
6747 moveTaskToBackLocked(task);
6748 Binder.restoreCallingIdentity(origId);
6749 }
6750 }
6751
6752 /**
6753 * Moves an activity, and all of the other activities within the same task, to the bottom
6754 * of the history stack. The activity's order within the task is unchanged.
6755 *
6756 * @param token A reference to the activity we wish to move
6757 * @param nonRoot If false then this only works if the activity is the root
6758 * of a task; if true it will work for any activity in a task.
6759 * @return Returns true if the move completed, false if not.
6760 */
6761 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6762 synchronized(this) {
6763 final long origId = Binder.clearCallingIdentity();
6764 int taskId = getTaskForActivityLocked(token, !nonRoot);
6765 if (taskId >= 0) {
6766 return moveTaskToBackLocked(taskId);
6767 }
6768 Binder.restoreCallingIdentity(origId);
6769 }
6770 return false;
6771 }
6772
6773 /**
6774 * Worker method for rearranging history stack. Implements the function of moving all
6775 * activities for a specific task (gathering them if disjoint) into a single group at the
6776 * bottom of the stack.
6777 *
6778 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6779 * to premeptively cancel the move.
6780 *
6781 * @param task The taskId to collect and move to the bottom.
6782 * @return Returns true if the move completed, false if not.
6783 */
6784 private final boolean moveTaskToBackLocked(int task) {
6785 Log.i(TAG, "moveTaskToBack: " + task);
6786
6787 // If we have a watcher, preflight the move before committing to it. First check
6788 // for *other* available tasks, but if none are available, then try again allowing the
6789 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006790 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006791 HistoryRecord next = topRunningActivityLocked(null, task);
6792 if (next == null) {
6793 next = topRunningActivityLocked(null, 0);
6794 }
6795 if (next != null) {
6796 // ask watcher if this is allowed
6797 boolean moveOK = true;
6798 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006799 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006800 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006801 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006802 }
6803 if (!moveOK) {
6804 return false;
6805 }
6806 }
6807 }
6808
6809 ArrayList moved = new ArrayList();
6810
6811 if (DEBUG_TRANSITION) Log.v(TAG,
6812 "Prepare to back transition: task=" + task);
6813 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6814
6815 final int N = mHistory.size();
6816 int bottom = 0;
6817 int pos = 0;
6818
6819 // Shift all activities with this task down to the bottom
6820 // of the stack, keeping them in the same internal order.
6821 while (pos < N) {
6822 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6823 if (localLOGV) Log.v(
6824 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6825 if (r.task.taskId == task) {
6826 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6827 mHistory.remove(pos);
6828 mHistory.add(bottom, r);
6829 moved.add(r);
6830 bottom++;
6831 }
6832 pos++;
6833 }
6834
6835 mWindowManager.moveAppTokensToBottom(moved);
6836 if (VALIDATE_TOKENS) {
6837 mWindowManager.validateAppTokens(mHistory);
6838 }
6839
6840 finishTaskMove(task);
6841 return true;
6842 }
6843
6844 public void moveTaskBackwards(int task) {
6845 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6846 "moveTaskBackwards()");
6847
6848 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006849 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6850 Binder.getCallingUid(), "Task backwards")) {
6851 return;
6852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006853 final long origId = Binder.clearCallingIdentity();
6854 moveTaskBackwardsLocked(task);
6855 Binder.restoreCallingIdentity(origId);
6856 }
6857 }
6858
6859 private final void moveTaskBackwardsLocked(int task) {
6860 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6861 }
6862
6863 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6864 synchronized(this) {
6865 return getTaskForActivityLocked(token, onlyRoot);
6866 }
6867 }
6868
6869 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6870 final int N = mHistory.size();
6871 TaskRecord lastTask = null;
6872 for (int i=0; i<N; i++) {
6873 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6874 if (r == token) {
6875 if (!onlyRoot || lastTask != r.task) {
6876 return r.task.taskId;
6877 }
6878 return -1;
6879 }
6880 lastTask = r.task;
6881 }
6882
6883 return -1;
6884 }
6885
6886 /**
6887 * Returns the top activity in any existing task matching the given
6888 * Intent. Returns null if no such task is found.
6889 */
6890 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6891 ComponentName cls = intent.getComponent();
6892 if (info.targetActivity != null) {
6893 cls = new ComponentName(info.packageName, info.targetActivity);
6894 }
6895
6896 TaskRecord cp = null;
6897
6898 final int N = mHistory.size();
6899 for (int i=(N-1); i>=0; i--) {
6900 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6901 if (!r.finishing && r.task != cp
6902 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6903 cp = r.task;
6904 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6905 // + "/aff=" + r.task.affinity + " to new cls="
6906 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6907 if (r.task.affinity != null) {
6908 if (r.task.affinity.equals(info.taskAffinity)) {
6909 //Log.i(TAG, "Found matching affinity!");
6910 return r;
6911 }
6912 } else if (r.task.intent != null
6913 && r.task.intent.getComponent().equals(cls)) {
6914 //Log.i(TAG, "Found matching class!");
6915 //dump();
6916 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6917 return r;
6918 } else if (r.task.affinityIntent != null
6919 && r.task.affinityIntent.getComponent().equals(cls)) {
6920 //Log.i(TAG, "Found matching class!");
6921 //dump();
6922 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6923 return r;
6924 }
6925 }
6926 }
6927
6928 return null;
6929 }
6930
6931 /**
6932 * Returns the first activity (starting from the top of the stack) that
6933 * is the same as the given activity. Returns null if no such activity
6934 * is found.
6935 */
6936 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6937 ComponentName cls = intent.getComponent();
6938 if (info.targetActivity != null) {
6939 cls = new ComponentName(info.packageName, info.targetActivity);
6940 }
6941
6942 final int N = mHistory.size();
6943 for (int i=(N-1); i>=0; i--) {
6944 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6945 if (!r.finishing) {
6946 if (r.intent.getComponent().equals(cls)) {
6947 //Log.i(TAG, "Found matching class!");
6948 //dump();
6949 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6950 return r;
6951 }
6952 }
6953 }
6954
6955 return null;
6956 }
6957
6958 public void finishOtherInstances(IBinder token, ComponentName className) {
6959 synchronized(this) {
6960 final long origId = Binder.clearCallingIdentity();
6961
6962 int N = mHistory.size();
6963 TaskRecord lastTask = null;
6964 for (int i=0; i<N; i++) {
6965 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6966 if (r.realActivity.equals(className)
6967 && r != token && lastTask != r.task) {
6968 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6969 null, "others")) {
6970 i--;
6971 N--;
6972 }
6973 }
6974 lastTask = r.task;
6975 }
6976
6977 Binder.restoreCallingIdentity(origId);
6978 }
6979 }
6980
6981 // =========================================================
6982 // THUMBNAILS
6983 // =========================================================
6984
6985 public void reportThumbnail(IBinder token,
6986 Bitmap thumbnail, CharSequence description) {
6987 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6988 final long origId = Binder.clearCallingIdentity();
6989 sendPendingThumbnail(null, token, thumbnail, description, true);
6990 Binder.restoreCallingIdentity(origId);
6991 }
6992
6993 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6994 Bitmap thumbnail, CharSequence description, boolean always) {
6995 TaskRecord task = null;
6996 ArrayList receivers = null;
6997
6998 //System.out.println("Send pending thumbnail: " + r);
6999
7000 synchronized(this) {
7001 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007002 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007003 if (index < 0) {
7004 return;
7005 }
7006 r = (HistoryRecord)mHistory.get(index);
7007 }
7008 if (thumbnail == null) {
7009 thumbnail = r.thumbnail;
7010 description = r.description;
7011 }
7012 if (thumbnail == null && !always) {
7013 // If there is no thumbnail, and this entry is not actually
7014 // going away, then abort for now and pick up the next
7015 // thumbnail we get.
7016 return;
7017 }
7018 task = r.task;
7019
7020 int N = mPendingThumbnails.size();
7021 int i=0;
7022 while (i<N) {
7023 PendingThumbnailsRecord pr =
7024 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7025 //System.out.println("Looking in " + pr.pendingRecords);
7026 if (pr.pendingRecords.remove(r)) {
7027 if (receivers == null) {
7028 receivers = new ArrayList();
7029 }
7030 receivers.add(pr);
7031 if (pr.pendingRecords.size() == 0) {
7032 pr.finished = true;
7033 mPendingThumbnails.remove(i);
7034 N--;
7035 continue;
7036 }
7037 }
7038 i++;
7039 }
7040 }
7041
7042 if (receivers != null) {
7043 final int N = receivers.size();
7044 for (int i=0; i<N; i++) {
7045 try {
7046 PendingThumbnailsRecord pr =
7047 (PendingThumbnailsRecord)receivers.get(i);
7048 pr.receiver.newThumbnail(
7049 task != null ? task.taskId : -1, thumbnail, description);
7050 if (pr.finished) {
7051 pr.receiver.finished();
7052 }
7053 } catch (Exception e) {
7054 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7055 }
7056 }
7057 }
7058 }
7059
7060 // =========================================================
7061 // CONTENT PROVIDERS
7062 // =========================================================
7063
7064 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7065 List providers = null;
7066 try {
7067 providers = ActivityThread.getPackageManager().
7068 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007069 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007070 } catch (RemoteException ex) {
7071 }
7072 if (providers != null) {
7073 final int N = providers.size();
7074 for (int i=0; i<N; i++) {
7075 ProviderInfo cpi =
7076 (ProviderInfo)providers.get(i);
7077 ContentProviderRecord cpr =
7078 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7079 if (cpr == null) {
7080 cpr = new ContentProviderRecord(cpi, app.info);
7081 mProvidersByClass.put(cpi.name, cpr);
7082 }
7083 app.pubProviders.put(cpi.name, cpr);
7084 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007085 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007086 }
7087 }
7088 return providers;
7089 }
7090
7091 private final String checkContentProviderPermissionLocked(
7092 ProviderInfo cpi, ProcessRecord r, int mode) {
7093 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7094 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7095 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7096 cpi.exported ? -1 : cpi.applicationInfo.uid)
7097 == PackageManager.PERMISSION_GRANTED
7098 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7099 return null;
7100 }
7101 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7102 cpi.exported ? -1 : cpi.applicationInfo.uid)
7103 == PackageManager.PERMISSION_GRANTED) {
7104 return null;
7105 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007106
7107 PathPermission[] pps = cpi.pathPermissions;
7108 if (pps != null) {
7109 int i = pps.length;
7110 while (i > 0) {
7111 i--;
7112 PathPermission pp = pps[i];
7113 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7114 cpi.exported ? -1 : cpi.applicationInfo.uid)
7115 == PackageManager.PERMISSION_GRANTED
7116 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7117 return null;
7118 }
7119 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7120 cpi.exported ? -1 : cpi.applicationInfo.uid)
7121 == PackageManager.PERMISSION_GRANTED) {
7122 return null;
7123 }
7124 }
7125 }
7126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 String msg = "Permission Denial: opening provider " + cpi.name
7128 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7129 + ", uid=" + callingUid + ") requires "
7130 + cpi.readPermission + " or " + cpi.writePermission;
7131 Log.w(TAG, msg);
7132 return msg;
7133 }
7134
7135 private final ContentProviderHolder getContentProviderImpl(
7136 IApplicationThread caller, String name) {
7137 ContentProviderRecord cpr;
7138 ProviderInfo cpi = null;
7139
7140 synchronized(this) {
7141 ProcessRecord r = null;
7142 if (caller != null) {
7143 r = getRecordForAppLocked(caller);
7144 if (r == null) {
7145 throw new SecurityException(
7146 "Unable to find app for caller " + caller
7147 + " (pid=" + Binder.getCallingPid()
7148 + ") when getting content provider " + name);
7149 }
7150 }
7151
7152 // First check if this content provider has been published...
7153 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7154 if (cpr != null) {
7155 cpi = cpr.info;
7156 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7157 return new ContentProviderHolder(cpi,
7158 cpi.readPermission != null
7159 ? cpi.readPermission : cpi.writePermission);
7160 }
7161
7162 if (r != null && cpr.canRunHere(r)) {
7163 // This provider has been published or is in the process
7164 // of being published... but it is also allowed to run
7165 // in the caller's process, so don't make a connection
7166 // and just let the caller instantiate its own instance.
7167 if (cpr.provider != null) {
7168 // don't give caller the provider object, it needs
7169 // to make its own.
7170 cpr = new ContentProviderRecord(cpr);
7171 }
7172 return cpr;
7173 }
7174
7175 final long origId = Binder.clearCallingIdentity();
7176
7177 // In this case the provider is a single instance, so we can
7178 // return it right away.
7179 if (r != null) {
7180 r.conProviders.add(cpr);
7181 cpr.clients.add(r);
7182 } else {
7183 cpr.externals++;
7184 }
7185
7186 if (cpr.app != null) {
7187 updateOomAdjLocked(cpr.app);
7188 }
7189
7190 Binder.restoreCallingIdentity(origId);
7191
7192 } else {
7193 try {
7194 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007195 resolveContentProvider(name,
7196 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007197 } catch (RemoteException ex) {
7198 }
7199 if (cpi == null) {
7200 return null;
7201 }
7202
7203 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7204 return new ContentProviderHolder(cpi,
7205 cpi.readPermission != null
7206 ? cpi.readPermission : cpi.writePermission);
7207 }
7208
7209 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7210 final boolean firstClass = cpr == null;
7211 if (firstClass) {
7212 try {
7213 ApplicationInfo ai =
7214 ActivityThread.getPackageManager().
7215 getApplicationInfo(
7216 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007217 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 if (ai == null) {
7219 Log.w(TAG, "No package info for content provider "
7220 + cpi.name);
7221 return null;
7222 }
7223 cpr = new ContentProviderRecord(cpi, ai);
7224 } catch (RemoteException ex) {
7225 // pm is in same process, this will never happen.
7226 }
7227 }
7228
7229 if (r != null && cpr.canRunHere(r)) {
7230 // If this is a multiprocess provider, then just return its
7231 // info and allow the caller to instantiate it. Only do
7232 // this if the provider is the same user as the caller's
7233 // process, or can run as root (so can be in any process).
7234 return cpr;
7235 }
7236
7237 if (false) {
7238 RuntimeException e = new RuntimeException("foo");
7239 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7240 // + " pruid " + ai.uid + "): " + cpi.className, e);
7241 }
7242
7243 // This is single process, and our app is now connecting to it.
7244 // See if we are already in the process of launching this
7245 // provider.
7246 final int N = mLaunchingProviders.size();
7247 int i;
7248 for (i=0; i<N; i++) {
7249 if (mLaunchingProviders.get(i) == cpr) {
7250 break;
7251 }
7252 if (false) {
7253 final ContentProviderRecord rec =
7254 (ContentProviderRecord)mLaunchingProviders.get(i);
7255 if (rec.info.name.equals(cpr.info.name)) {
7256 cpr = rec;
7257 break;
7258 }
7259 }
7260 }
7261
7262 // If the provider is not already being launched, then get it
7263 // started.
7264 if (i >= N) {
7265 final long origId = Binder.clearCallingIdentity();
7266 ProcessRecord proc = startProcessLocked(cpi.processName,
7267 cpr.appInfo, false, 0, "content provider",
7268 new ComponentName(cpi.applicationInfo.packageName,
7269 cpi.name));
7270 if (proc == null) {
7271 Log.w(TAG, "Unable to launch app "
7272 + cpi.applicationInfo.packageName + "/"
7273 + cpi.applicationInfo.uid + " for provider "
7274 + name + ": process is bad");
7275 return null;
7276 }
7277 cpr.launchingApp = proc;
7278 mLaunchingProviders.add(cpr);
7279 Binder.restoreCallingIdentity(origId);
7280 }
7281
7282 // Make sure the provider is published (the same provider class
7283 // may be published under multiple names).
7284 if (firstClass) {
7285 mProvidersByClass.put(cpi.name, cpr);
7286 }
7287 mProvidersByName.put(name, cpr);
7288
7289 if (r != null) {
7290 r.conProviders.add(cpr);
7291 cpr.clients.add(r);
7292 } else {
7293 cpr.externals++;
7294 }
7295 }
7296 }
7297
7298 // Wait for the provider to be published...
7299 synchronized (cpr) {
7300 while (cpr.provider == null) {
7301 if (cpr.launchingApp == null) {
7302 Log.w(TAG, "Unable to launch app "
7303 + cpi.applicationInfo.packageName + "/"
7304 + cpi.applicationInfo.uid + " for provider "
7305 + name + ": launching app became null");
7306 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7307 cpi.applicationInfo.packageName,
7308 cpi.applicationInfo.uid, name);
7309 return null;
7310 }
7311 try {
7312 cpr.wait();
7313 } catch (InterruptedException ex) {
7314 }
7315 }
7316 }
7317 return cpr;
7318 }
7319
7320 public final ContentProviderHolder getContentProvider(
7321 IApplicationThread caller, String name) {
7322 if (caller == null) {
7323 String msg = "null IApplicationThread when getting content provider "
7324 + name;
7325 Log.w(TAG, msg);
7326 throw new SecurityException(msg);
7327 }
7328
7329 return getContentProviderImpl(caller, name);
7330 }
7331
7332 private ContentProviderHolder getContentProviderExternal(String name) {
7333 return getContentProviderImpl(null, name);
7334 }
7335
7336 /**
7337 * Drop a content provider from a ProcessRecord's bookkeeping
7338 * @param cpr
7339 */
7340 public void removeContentProvider(IApplicationThread caller, String name) {
7341 synchronized (this) {
7342 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7343 if(cpr == null) {
7344 //remove from mProvidersByClass
7345 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7346 return;
7347 }
7348 final ProcessRecord r = getRecordForAppLocked(caller);
7349 if (r == null) {
7350 throw new SecurityException(
7351 "Unable to find app for caller " + caller +
7352 " when removing content provider " + name);
7353 }
7354 //update content provider record entry info
7355 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7356 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7357 r.info.processName+" from process "+localCpr.appInfo.processName);
7358 if(localCpr.appInfo.processName == r.info.processName) {
7359 //should not happen. taken care of as a local provider
7360 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7361 return;
7362 } else {
7363 localCpr.clients.remove(r);
7364 r.conProviders.remove(localCpr);
7365 }
7366 updateOomAdjLocked();
7367 }
7368 }
7369
7370 private void removeContentProviderExternal(String name) {
7371 synchronized (this) {
7372 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7373 if(cpr == null) {
7374 //remove from mProvidersByClass
7375 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7376 return;
7377 }
7378
7379 //update content provider record entry info
7380 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7381 localCpr.externals--;
7382 if (localCpr.externals < 0) {
7383 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7384 }
7385 updateOomAdjLocked();
7386 }
7387 }
7388
7389 public final void publishContentProviders(IApplicationThread caller,
7390 List<ContentProviderHolder> providers) {
7391 if (providers == null) {
7392 return;
7393 }
7394
7395 synchronized(this) {
7396 final ProcessRecord r = getRecordForAppLocked(caller);
7397 if (r == null) {
7398 throw new SecurityException(
7399 "Unable to find app for caller " + caller
7400 + " (pid=" + Binder.getCallingPid()
7401 + ") when publishing content providers");
7402 }
7403
7404 final long origId = Binder.clearCallingIdentity();
7405
7406 final int N = providers.size();
7407 for (int i=0; i<N; i++) {
7408 ContentProviderHolder src = providers.get(i);
7409 if (src == null || src.info == null || src.provider == null) {
7410 continue;
7411 }
7412 ContentProviderRecord dst =
7413 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7414 if (dst != null) {
7415 mProvidersByClass.put(dst.info.name, dst);
7416 String names[] = dst.info.authority.split(";");
7417 for (int j = 0; j < names.length; j++) {
7418 mProvidersByName.put(names[j], dst);
7419 }
7420
7421 int NL = mLaunchingProviders.size();
7422 int j;
7423 for (j=0; j<NL; j++) {
7424 if (mLaunchingProviders.get(j) == dst) {
7425 mLaunchingProviders.remove(j);
7426 j--;
7427 NL--;
7428 }
7429 }
7430 synchronized (dst) {
7431 dst.provider = src.provider;
7432 dst.app = r;
7433 dst.notifyAll();
7434 }
7435 updateOomAdjLocked(r);
7436 }
7437 }
7438
7439 Binder.restoreCallingIdentity(origId);
7440 }
7441 }
7442
7443 public static final void installSystemProviders() {
7444 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7445 List providers = mSelf.generateApplicationProvidersLocked(app);
7446 mSystemThread.installSystemProviders(providers);
7447 }
7448
7449 // =========================================================
7450 // GLOBAL MANAGEMENT
7451 // =========================================================
7452
7453 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7454 ApplicationInfo info, String customProcess) {
7455 String proc = customProcess != null ? customProcess : info.processName;
7456 BatteryStatsImpl.Uid.Proc ps = null;
7457 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7458 synchronized (stats) {
7459 ps = stats.getProcessStatsLocked(info.uid, proc);
7460 }
7461 return new ProcessRecord(ps, thread, info, proc);
7462 }
7463
7464 final ProcessRecord addAppLocked(ApplicationInfo info) {
7465 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7466
7467 if (app == null) {
7468 app = newProcessRecordLocked(null, info, null);
7469 mProcessNames.put(info.processName, info.uid, app);
7470 updateLRUListLocked(app, true);
7471 }
7472
7473 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7474 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7475 app.persistent = true;
7476 app.maxAdj = CORE_SERVER_ADJ;
7477 }
7478 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7479 mPersistentStartingProcesses.add(app);
7480 startProcessLocked(app, "added application", app.processName);
7481 }
7482
7483 return app;
7484 }
7485
7486 public void unhandledBack() {
7487 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7488 "unhandledBack()");
7489
7490 synchronized(this) {
7491 int count = mHistory.size();
7492 if (Config.LOGD) Log.d(
7493 TAG, "Performing unhandledBack(): stack size = " + count);
7494 if (count > 1) {
7495 final long origId = Binder.clearCallingIdentity();
7496 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7497 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7498 Binder.restoreCallingIdentity(origId);
7499 }
7500 }
7501 }
7502
7503 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7504 String name = uri.getAuthority();
7505 ContentProviderHolder cph = getContentProviderExternal(name);
7506 ParcelFileDescriptor pfd = null;
7507 if (cph != null) {
7508 // We record the binder invoker's uid in thread-local storage before
7509 // going to the content provider to open the file. Later, in the code
7510 // that handles all permissions checks, we look for this uid and use
7511 // that rather than the Activity Manager's own uid. The effect is that
7512 // we do the check against the caller's permissions even though it looks
7513 // to the content provider like the Activity Manager itself is making
7514 // the request.
7515 sCallerIdentity.set(new Identity(
7516 Binder.getCallingPid(), Binder.getCallingUid()));
7517 try {
7518 pfd = cph.provider.openFile(uri, "r");
7519 } catch (FileNotFoundException e) {
7520 // do nothing; pfd will be returned null
7521 } finally {
7522 // Ensure that whatever happens, we clean up the identity state
7523 sCallerIdentity.remove();
7524 }
7525
7526 // We've got the fd now, so we're done with the provider.
7527 removeContentProviderExternal(name);
7528 } else {
7529 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7530 }
7531 return pfd;
7532 }
7533
7534 public void goingToSleep() {
7535 synchronized(this) {
7536 mSleeping = true;
7537 mWindowManager.setEventDispatching(false);
7538
7539 if (mResumedActivity != null) {
7540 pauseIfSleepingLocked();
7541 } else {
7542 Log.w(TAG, "goingToSleep with no resumed activity!");
7543 }
7544 }
7545 }
7546
Dianne Hackborn55280a92009-05-07 15:53:46 -07007547 public boolean shutdown(int timeout) {
7548 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7549 != PackageManager.PERMISSION_GRANTED) {
7550 throw new SecurityException("Requires permission "
7551 + android.Manifest.permission.SHUTDOWN);
7552 }
7553
7554 boolean timedout = false;
7555
7556 synchronized(this) {
7557 mShuttingDown = true;
7558 mWindowManager.setEventDispatching(false);
7559
7560 if (mResumedActivity != null) {
7561 pauseIfSleepingLocked();
7562 final long endTime = System.currentTimeMillis() + timeout;
7563 while (mResumedActivity != null || mPausingActivity != null) {
7564 long delay = endTime - System.currentTimeMillis();
7565 if (delay <= 0) {
7566 Log.w(TAG, "Activity manager shutdown timed out");
7567 timedout = true;
7568 break;
7569 }
7570 try {
7571 this.wait();
7572 } catch (InterruptedException e) {
7573 }
7574 }
7575 }
7576 }
7577
7578 mUsageStatsService.shutdown();
7579 mBatteryStatsService.shutdown();
7580
7581 return timedout;
7582 }
7583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007584 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007585 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007586 if (!mGoingToSleep.isHeld()) {
7587 mGoingToSleep.acquire();
7588 if (mLaunchingActivity.isHeld()) {
7589 mLaunchingActivity.release();
7590 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7591 }
7592 }
7593
7594 // If we are not currently pausing an activity, get the current
7595 // one to pause. If we are pausing one, we will just let that stuff
7596 // run and release the wake lock when all done.
7597 if (mPausingActivity == null) {
7598 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7599 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7600 startPausingLocked(false, true);
7601 }
7602 }
7603 }
7604
7605 public void wakingUp() {
7606 synchronized(this) {
7607 if (mGoingToSleep.isHeld()) {
7608 mGoingToSleep.release();
7609 }
7610 mWindowManager.setEventDispatching(true);
7611 mSleeping = false;
7612 resumeTopActivityLocked(null);
7613 }
7614 }
7615
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007616 public void stopAppSwitches() {
7617 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7618 != PackageManager.PERMISSION_GRANTED) {
7619 throw new SecurityException("Requires permission "
7620 + android.Manifest.permission.STOP_APP_SWITCHES);
7621 }
7622
7623 synchronized(this) {
7624 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7625 + APP_SWITCH_DELAY_TIME;
7626 mDidAppSwitch = false;
7627 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7628 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7629 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7630 }
7631 }
7632
7633 public void resumeAppSwitches() {
7634 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7635 != PackageManager.PERMISSION_GRANTED) {
7636 throw new SecurityException("Requires permission "
7637 + android.Manifest.permission.STOP_APP_SWITCHES);
7638 }
7639
7640 synchronized(this) {
7641 // Note that we don't execute any pending app switches... we will
7642 // let those wait until either the timeout, or the next start
7643 // activity request.
7644 mAppSwitchesAllowedTime = 0;
7645 }
7646 }
7647
7648 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7649 String name) {
7650 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7651 return true;
7652 }
7653
7654 final int perm = checkComponentPermission(
7655 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7656 callingUid, -1);
7657 if (perm == PackageManager.PERMISSION_GRANTED) {
7658 return true;
7659 }
7660
7661 Log.w(TAG, name + " request from " + callingUid + " stopped");
7662 return false;
7663 }
7664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007665 public void setDebugApp(String packageName, boolean waitForDebugger,
7666 boolean persistent) {
7667 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7668 "setDebugApp()");
7669
7670 // Note that this is not really thread safe if there are multiple
7671 // callers into it at the same time, but that's not a situation we
7672 // care about.
7673 if (persistent) {
7674 final ContentResolver resolver = mContext.getContentResolver();
7675 Settings.System.putString(
7676 resolver, Settings.System.DEBUG_APP,
7677 packageName);
7678 Settings.System.putInt(
7679 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7680 waitForDebugger ? 1 : 0);
7681 }
7682
7683 synchronized (this) {
7684 if (!persistent) {
7685 mOrigDebugApp = mDebugApp;
7686 mOrigWaitForDebugger = mWaitForDebugger;
7687 }
7688 mDebugApp = packageName;
7689 mWaitForDebugger = waitForDebugger;
7690 mDebugTransient = !persistent;
7691 if (packageName != null) {
7692 final long origId = Binder.clearCallingIdentity();
7693 uninstallPackageLocked(packageName, -1, false);
7694 Binder.restoreCallingIdentity(origId);
7695 }
7696 }
7697 }
7698
7699 public void setAlwaysFinish(boolean enabled) {
7700 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7701 "setAlwaysFinish()");
7702
7703 Settings.System.putInt(
7704 mContext.getContentResolver(),
7705 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7706
7707 synchronized (this) {
7708 mAlwaysFinishActivities = enabled;
7709 }
7710 }
7711
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007712 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007713 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007714 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007715 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007716 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 }
7718 }
7719
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007720 public void registerActivityWatcher(IActivityWatcher watcher) {
7721 mWatchers.register(watcher);
7722 }
7723
7724 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7725 mWatchers.unregister(watcher);
7726 }
7727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007728 public final void enterSafeMode() {
7729 synchronized(this) {
7730 // It only makes sense to do this before the system is ready
7731 // and started launching other packages.
7732 if (!mSystemReady) {
7733 try {
7734 ActivityThread.getPackageManager().enterSafeMode();
7735 } catch (RemoteException e) {
7736 }
7737
7738 View v = LayoutInflater.from(mContext).inflate(
7739 com.android.internal.R.layout.safe_mode, null);
7740 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7741 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7742 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7743 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7744 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7745 lp.format = v.getBackground().getOpacity();
7746 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7747 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7748 ((WindowManager)mContext.getSystemService(
7749 Context.WINDOW_SERVICE)).addView(v, lp);
7750 }
7751 }
7752 }
7753
7754 public void noteWakeupAlarm(IIntentSender sender) {
7755 if (!(sender instanceof PendingIntentRecord)) {
7756 return;
7757 }
7758 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7759 synchronized (stats) {
7760 if (mBatteryStatsService.isOnBattery()) {
7761 mBatteryStatsService.enforceCallingPermission();
7762 PendingIntentRecord rec = (PendingIntentRecord)sender;
7763 int MY_UID = Binder.getCallingUid();
7764 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7765 BatteryStatsImpl.Uid.Pkg pkg =
7766 stats.getPackageStatsLocked(uid, rec.key.packageName);
7767 pkg.incWakeupsLocked();
7768 }
7769 }
7770 }
7771
7772 public boolean killPidsForMemory(int[] pids) {
7773 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7774 throw new SecurityException("killPidsForMemory only available to the system");
7775 }
7776
7777 // XXX Note: don't acquire main activity lock here, because the window
7778 // manager calls in with its locks held.
7779
7780 boolean killed = false;
7781 synchronized (mPidsSelfLocked) {
7782 int[] types = new int[pids.length];
7783 int worstType = 0;
7784 for (int i=0; i<pids.length; i++) {
7785 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7786 if (proc != null) {
7787 int type = proc.setAdj;
7788 types[i] = type;
7789 if (type > worstType) {
7790 worstType = type;
7791 }
7792 }
7793 }
7794
7795 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7796 // then constrain it so we will kill all hidden procs.
7797 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7798 worstType = HIDDEN_APP_MIN_ADJ;
7799 }
7800 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7801 for (int i=0; i<pids.length; i++) {
7802 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7803 if (proc == null) {
7804 continue;
7805 }
7806 int adj = proc.setAdj;
7807 if (adj >= worstType) {
7808 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7809 + adj + ")");
7810 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7811 proc.processName, adj);
7812 killed = true;
7813 Process.killProcess(pids[i]);
7814 }
7815 }
7816 }
7817 return killed;
7818 }
7819
7820 public void reportPss(IApplicationThread caller, int pss) {
7821 Watchdog.PssRequestor req;
7822 String name;
7823 ProcessRecord callerApp;
7824 synchronized (this) {
7825 if (caller == null) {
7826 return;
7827 }
7828 callerApp = getRecordForAppLocked(caller);
7829 if (callerApp == null) {
7830 return;
7831 }
7832 callerApp.lastPss = pss;
7833 req = callerApp;
7834 name = callerApp.processName;
7835 }
7836 Watchdog.getInstance().reportPss(req, name, pss);
7837 if (!callerApp.persistent) {
7838 removeRequestedPss(callerApp);
7839 }
7840 }
7841
7842 public void requestPss(Runnable completeCallback) {
7843 ArrayList<ProcessRecord> procs;
7844 synchronized (this) {
7845 mRequestPssCallback = completeCallback;
7846 mRequestPssList.clear();
7847 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7848 ProcessRecord proc = mLRUProcesses.get(i);
7849 if (!proc.persistent) {
7850 mRequestPssList.add(proc);
7851 }
7852 }
7853 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7854 }
7855
7856 int oldPri = Process.getThreadPriority(Process.myTid());
7857 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7858 for (int i=procs.size()-1; i>=0; i--) {
7859 ProcessRecord proc = procs.get(i);
7860 proc.lastPss = 0;
7861 proc.requestPss();
7862 }
7863 Process.setThreadPriority(oldPri);
7864 }
7865
7866 void removeRequestedPss(ProcessRecord proc) {
7867 Runnable callback = null;
7868 synchronized (this) {
7869 if (mRequestPssList.remove(proc)) {
7870 if (mRequestPssList.size() == 0) {
7871 callback = mRequestPssCallback;
7872 mRequestPssCallback = null;
7873 }
7874 }
7875 }
7876
7877 if (callback != null) {
7878 callback.run();
7879 }
7880 }
7881
7882 public void collectPss(Watchdog.PssStats stats) {
7883 stats.mEmptyPss = 0;
7884 stats.mEmptyCount = 0;
7885 stats.mBackgroundPss = 0;
7886 stats.mBackgroundCount = 0;
7887 stats.mServicePss = 0;
7888 stats.mServiceCount = 0;
7889 stats.mVisiblePss = 0;
7890 stats.mVisibleCount = 0;
7891 stats.mForegroundPss = 0;
7892 stats.mForegroundCount = 0;
7893 stats.mNoPssCount = 0;
7894 synchronized (this) {
7895 int i;
7896 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7897 ? mProcDeaths.length : stats.mProcDeaths.length;
7898 int aggr = 0;
7899 for (i=0; i<NPD; i++) {
7900 aggr += mProcDeaths[i];
7901 stats.mProcDeaths[i] = aggr;
7902 }
7903 while (i<stats.mProcDeaths.length) {
7904 stats.mProcDeaths[i] = 0;
7905 i++;
7906 }
7907
7908 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7909 ProcessRecord proc = mLRUProcesses.get(i);
7910 if (proc.persistent) {
7911 continue;
7912 }
7913 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7914 if (proc.lastPss == 0) {
7915 stats.mNoPssCount++;
7916 continue;
7917 }
7918 if (proc.setAdj == EMPTY_APP_ADJ) {
7919 stats.mEmptyPss += proc.lastPss;
7920 stats.mEmptyCount++;
7921 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7922 stats.mEmptyPss += proc.lastPss;
7923 stats.mEmptyCount++;
7924 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7925 stats.mBackgroundPss += proc.lastPss;
7926 stats.mBackgroundCount++;
7927 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7928 stats.mVisiblePss += proc.lastPss;
7929 stats.mVisibleCount++;
7930 } else {
7931 stats.mForegroundPss += proc.lastPss;
7932 stats.mForegroundCount++;
7933 }
7934 }
7935 }
7936 }
7937
7938 public final void startRunning(String pkg, String cls, String action,
7939 String data) {
7940 synchronized(this) {
7941 if (mStartRunning) {
7942 return;
7943 }
7944 mStartRunning = true;
7945 mTopComponent = pkg != null && cls != null
7946 ? new ComponentName(pkg, cls) : null;
7947 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7948 mTopData = data;
7949 if (!mSystemReady) {
7950 return;
7951 }
7952 }
7953
7954 systemReady();
7955 }
7956
7957 private void retrieveSettings() {
7958 final ContentResolver resolver = mContext.getContentResolver();
7959 String debugApp = Settings.System.getString(
7960 resolver, Settings.System.DEBUG_APP);
7961 boolean waitForDebugger = Settings.System.getInt(
7962 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7963 boolean alwaysFinishActivities = Settings.System.getInt(
7964 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7965
7966 Configuration configuration = new Configuration();
7967 Settings.System.getConfiguration(resolver, configuration);
7968
7969 synchronized (this) {
7970 mDebugApp = mOrigDebugApp = debugApp;
7971 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7972 mAlwaysFinishActivities = alwaysFinishActivities;
7973 // This happens before any activities are started, so we can
7974 // change mConfiguration in-place.
7975 mConfiguration.updateFrom(configuration);
7976 }
7977 }
7978
7979 public boolean testIsSystemReady() {
7980 // no need to synchronize(this) just to read & return the value
7981 return mSystemReady;
7982 }
7983
7984 public void systemReady() {
7985 // In the simulator, startRunning will never have been called, which
7986 // normally sets a few crucial variables. Do it here instead.
7987 if (!Process.supportsProcesses()) {
7988 mStartRunning = true;
7989 mTopAction = Intent.ACTION_MAIN;
7990 }
7991
7992 synchronized(this) {
7993 if (mSystemReady) {
7994 return;
7995 }
7996 mSystemReady = true;
7997 if (!mStartRunning) {
7998 return;
7999 }
8000 }
8001
8002 if (Config.LOGD) Log.d(TAG, "Start running!");
8003 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8004 SystemClock.uptimeMillis());
8005
8006 synchronized(this) {
8007 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8008 ResolveInfo ri = mContext.getPackageManager()
8009 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008010 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008011 CharSequence errorMsg = null;
8012 if (ri != null) {
8013 ActivityInfo ai = ri.activityInfo;
8014 ApplicationInfo app = ai.applicationInfo;
8015 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8016 mTopAction = Intent.ACTION_FACTORY_TEST;
8017 mTopData = null;
8018 mTopComponent = new ComponentName(app.packageName,
8019 ai.name);
8020 } else {
8021 errorMsg = mContext.getResources().getText(
8022 com.android.internal.R.string.factorytest_not_system);
8023 }
8024 } else {
8025 errorMsg = mContext.getResources().getText(
8026 com.android.internal.R.string.factorytest_no_action);
8027 }
8028 if (errorMsg != null) {
8029 mTopAction = null;
8030 mTopData = null;
8031 mTopComponent = null;
8032 Message msg = Message.obtain();
8033 msg.what = SHOW_FACTORY_ERROR_MSG;
8034 msg.getData().putCharSequence("msg", errorMsg);
8035 mHandler.sendMessage(msg);
8036 }
8037 }
8038 }
8039
8040 retrieveSettings();
8041
8042 synchronized (this) {
8043 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8044 try {
8045 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008046 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008047 if (apps != null) {
8048 int N = apps.size();
8049 int i;
8050 for (i=0; i<N; i++) {
8051 ApplicationInfo info
8052 = (ApplicationInfo)apps.get(i);
8053 if (info != null &&
8054 !info.packageName.equals("android")) {
8055 addAppLocked(info);
8056 }
8057 }
8058 }
8059 } catch (RemoteException ex) {
8060 // pm is in same process, this will never happen.
8061 }
8062 }
8063
8064 try {
8065 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8066 Message msg = Message.obtain();
8067 msg.what = SHOW_UID_ERROR_MSG;
8068 mHandler.sendMessage(msg);
8069 }
8070 } catch (RemoteException e) {
8071 }
8072
8073 // Start up initial activity.
8074 mBooting = true;
8075 resumeTopActivityLocked(null);
8076 }
8077 }
8078
8079 boolean makeAppCrashingLocked(ProcessRecord app,
8080 String tag, String shortMsg, String longMsg, byte[] crashData) {
8081 app.crashing = true;
8082 app.crashingReport = generateProcessError(app,
8083 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8084 startAppProblemLocked(app);
8085 app.stopFreezingAllLocked();
8086 return handleAppCrashLocked(app);
8087 }
8088
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008089 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8090 IPackageManager pm = ActivityThread.getPackageManager();
8091 try {
8092 // was an installer package name specified when this app was
8093 // installed?
8094 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8095 if (installerPackageName == null) {
8096 return null;
8097 }
8098
8099 // is there an Activity in this package that handles ACTION_APP_ERROR?
8100 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008101 intent.setPackage(installerPackageName);
8102 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008103 if (info == null || info.activityInfo == null) {
8104 return null;
8105 }
8106
8107 return new ComponentName(installerPackageName, info.activityInfo.name);
8108 } catch (RemoteException e) {
8109 // will return null and no error report will be delivered
8110 }
8111 return null;
8112 }
8113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008114 void makeAppNotRespondingLocked(ProcessRecord app,
8115 String tag, String shortMsg, String longMsg, byte[] crashData) {
8116 app.notResponding = true;
8117 app.notRespondingReport = generateProcessError(app,
8118 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8119 crashData);
8120 startAppProblemLocked(app);
8121 app.stopFreezingAllLocked();
8122 }
8123
8124 /**
8125 * Generate a process error record, suitable for attachment to a ProcessRecord.
8126 *
8127 * @param app The ProcessRecord in which the error occurred.
8128 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8129 * ActivityManager.AppErrorStateInfo
8130 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8131 * @param shortMsg Short message describing the crash.
8132 * @param longMsg Long message describing the crash.
8133 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8134 *
8135 * @return Returns a fully-formed AppErrorStateInfo record.
8136 */
8137 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8138 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8139 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8140
8141 report.condition = condition;
8142 report.processName = app.processName;
8143 report.pid = app.pid;
8144 report.uid = app.info.uid;
8145 report.tag = tag;
8146 report.shortMsg = shortMsg;
8147 report.longMsg = longMsg;
8148 report.crashData = crashData;
8149
8150 return report;
8151 }
8152
8153 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8154 boolean crashed) {
8155 synchronized (this) {
8156 app.crashing = false;
8157 app.crashingReport = null;
8158 app.notResponding = false;
8159 app.notRespondingReport = null;
8160 if (app.anrDialog == fromDialog) {
8161 app.anrDialog = null;
8162 }
8163 if (app.waitDialog == fromDialog) {
8164 app.waitDialog = null;
8165 }
8166 if (app.pid > 0 && app.pid != MY_PID) {
8167 if (crashed) {
8168 handleAppCrashLocked(app);
8169 }
8170 Log.i(ActivityManagerService.TAG, "Killing process "
8171 + app.processName
8172 + " (pid=" + app.pid + ") at user's request");
8173 Process.killProcess(app.pid);
8174 }
8175
8176 }
8177 }
8178
8179 boolean handleAppCrashLocked(ProcessRecord app) {
8180 long now = SystemClock.uptimeMillis();
8181
8182 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8183 app.info.uid);
8184 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8185 // This process loses!
8186 Log.w(TAG, "Process " + app.info.processName
8187 + " has crashed too many times: killing!");
8188 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8189 app.info.processName, app.info.uid);
8190 killServicesLocked(app, false);
8191 for (int i=mHistory.size()-1; i>=0; i--) {
8192 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8193 if (r.app == app) {
8194 if (Config.LOGD) Log.d(
8195 TAG, " Force finishing activity "
8196 + r.intent.getComponent().flattenToShortString());
8197 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8198 }
8199 }
8200 if (!app.persistent) {
8201 // We don't want to start this process again until the user
8202 // explicitly does so... but for persistent process, we really
8203 // need to keep it running. If a persistent process is actually
8204 // repeatedly crashing, then badness for everyone.
8205 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8206 app.info.processName);
8207 mBadProcesses.put(app.info.processName, app.info.uid, now);
8208 app.bad = true;
8209 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8210 app.removed = true;
8211 removeProcessLocked(app, false);
8212 return false;
8213 }
8214 }
8215
8216 // Bump up the crash count of any services currently running in the proc.
8217 if (app.services.size() != 0) {
8218 // Any services running in the application need to be placed
8219 // back in the pending list.
8220 Iterator it = app.services.iterator();
8221 while (it.hasNext()) {
8222 ServiceRecord sr = (ServiceRecord)it.next();
8223 sr.crashCount++;
8224 }
8225 }
8226
8227 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8228 return true;
8229 }
8230
8231 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008232 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008233 skipCurrentReceiverLocked(app);
8234 }
8235
8236 void skipCurrentReceiverLocked(ProcessRecord app) {
8237 boolean reschedule = false;
8238 BroadcastRecord r = app.curReceiver;
8239 if (r != null) {
8240 // The current broadcast is waiting for this app's receiver
8241 // to be finished. Looks like that's not going to happen, so
8242 // let the broadcast continue.
8243 logBroadcastReceiverDiscard(r);
8244 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8245 r.resultExtras, r.resultAbort, true);
8246 reschedule = true;
8247 }
8248 r = mPendingBroadcast;
8249 if (r != null && r.curApp == app) {
8250 if (DEBUG_BROADCAST) Log.v(TAG,
8251 "skip & discard pending app " + r);
8252 logBroadcastReceiverDiscard(r);
8253 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8254 r.resultExtras, r.resultAbort, true);
8255 reschedule = true;
8256 }
8257 if (reschedule) {
8258 scheduleBroadcastsLocked();
8259 }
8260 }
8261
8262 public int handleApplicationError(IBinder app, int flags,
8263 String tag, String shortMsg, String longMsg, byte[] crashData) {
8264 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008265 ProcessRecord r = null;
8266 synchronized (this) {
8267 if (app != null) {
8268 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8269 final int NA = apps.size();
8270 for (int ia=0; ia<NA; ia++) {
8271 ProcessRecord p = apps.valueAt(ia);
8272 if (p.thread != null && p.thread.asBinder() == app) {
8273 r = p;
8274 break;
8275 }
8276 }
8277 }
8278 }
8279
8280 if (r != null) {
8281 // The application has crashed. Send the SIGQUIT to the process so
8282 // that it can dump its state.
8283 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8284 //Log.i(TAG, "Current system threads:");
8285 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8286 }
8287
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008288 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008289 try {
8290 String name = r != null ? r.processName : null;
8291 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008292 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008293 shortMsg, longMsg, crashData)) {
8294 Log.w(TAG, "Force-killing crashed app " + name
8295 + " at watcher's request");
8296 Process.killProcess(pid);
8297 return 0;
8298 }
8299 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008300 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008301 }
8302 }
8303
8304 final long origId = Binder.clearCallingIdentity();
8305
8306 // If this process is running instrumentation, finish it.
8307 if (r != null && r.instrumentationClass != null) {
8308 Log.w(TAG, "Error in app " + r.processName
8309 + " running instrumentation " + r.instrumentationClass + ":");
8310 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8311 if (longMsg != null) Log.w(TAG, " " + longMsg);
8312 Bundle info = new Bundle();
8313 info.putString("shortMsg", shortMsg);
8314 info.putString("longMsg", longMsg);
8315 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8316 Binder.restoreCallingIdentity(origId);
8317 return 0;
8318 }
8319
8320 if (r != null) {
8321 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8322 return 0;
8323 }
8324 } else {
8325 Log.w(TAG, "Some application object " + app + " tag " + tag
8326 + " has crashed, but I don't know who it is.");
8327 Log.w(TAG, "ShortMsg:" + shortMsg);
8328 Log.w(TAG, "LongMsg:" + longMsg);
8329 Binder.restoreCallingIdentity(origId);
8330 return 0;
8331 }
8332
8333 Message msg = Message.obtain();
8334 msg.what = SHOW_ERROR_MSG;
8335 HashMap data = new HashMap();
8336 data.put("result", result);
8337 data.put("app", r);
8338 data.put("flags", flags);
8339 data.put("shortMsg", shortMsg);
8340 data.put("longMsg", longMsg);
8341 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8342 // For system processes, submit crash data to the server.
8343 data.put("crashData", crashData);
8344 }
8345 msg.obj = data;
8346 mHandler.sendMessage(msg);
8347
8348 Binder.restoreCallingIdentity(origId);
8349 }
8350
8351 int res = result.get();
8352
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008353 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008354 synchronized (this) {
8355 if (r != null) {
8356 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8357 SystemClock.uptimeMillis());
8358 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008359 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8360 appErrorIntent = createAppErrorIntentLocked(r);
8361 res = AppErrorDialog.FORCE_QUIT;
8362 }
8363 }
8364
8365 if (appErrorIntent != null) {
8366 try {
8367 mContext.startActivity(appErrorIntent);
8368 } catch (ActivityNotFoundException e) {
8369 Log.w(TAG, "bug report receiver dissappeared", e);
8370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008371 }
8372
8373 return res;
8374 }
8375
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008376 Intent createAppErrorIntentLocked(ProcessRecord r) {
8377 ApplicationErrorReport report = createAppErrorReportLocked(r);
8378 if (report == null) {
8379 return null;
8380 }
8381 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8382 result.setComponent(r.errorReportReceiver);
8383 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8384 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8385 return result;
8386 }
8387
8388 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8389 if (r.errorReportReceiver == null) {
8390 return null;
8391 }
8392
8393 if (!r.crashing && !r.notResponding) {
8394 return null;
8395 }
8396
8397 try {
8398 ApplicationErrorReport report = new ApplicationErrorReport();
8399 report.packageName = r.info.packageName;
8400 report.installerPackageName = r.errorReportReceiver.getPackageName();
8401 report.processName = r.processName;
8402
8403 if (r.crashing) {
8404 report.type = ApplicationErrorReport.TYPE_CRASH;
8405 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8406
8407 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8408 r.crashingReport.crashData);
8409 DataInputStream dataStream = new DataInputStream(byteStream);
8410 CrashData crashData = new CrashData(dataStream);
8411 ThrowableData throwData = crashData.getThrowableData();
8412
8413 report.time = crashData.getTime();
8414 report.crashInfo.stackTrace = throwData.toString();
8415
Jacek Surazskif829a782009-06-11 22:47:02 +02008416 // Extract the source of the exception, useful for report
8417 // clustering. Also extract the "deepest" non-null exception
8418 // message.
8419 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008420 while (throwData.getCause() != null) {
8421 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008422 String msg = throwData.getMessage();
8423 if (msg != null && msg.length() > 0) {
8424 exceptionMessage = msg;
8425 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008426 }
8427 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008428 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008429 report.crashInfo.exceptionClassName = throwData.getType();
8430 report.crashInfo.throwFileName = trace.getFileName();
8431 report.crashInfo.throwClassName = trace.getClassName();
8432 report.crashInfo.throwMethodName = trace.getMethodName();
8433 } else if (r.notResponding) {
8434 report.type = ApplicationErrorReport.TYPE_ANR;
8435 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8436
8437 report.anrInfo.activity = r.notRespondingReport.tag;
8438 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8439 report.anrInfo.info = r.notRespondingReport.longMsg;
8440 }
8441
8442 return report;
8443 } catch (IOException e) {
8444 // we don't send it
8445 }
8446
8447 return null;
8448 }
8449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008450 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8451 // assume our apps are happy - lazy create the list
8452 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8453
8454 synchronized (this) {
8455
8456 // iterate across all processes
8457 final int N = mLRUProcesses.size();
8458 for (int i = 0; i < N; i++) {
8459 ProcessRecord app = mLRUProcesses.get(i);
8460 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8461 // This one's in trouble, so we'll generate a report for it
8462 // crashes are higher priority (in case there's a crash *and* an anr)
8463 ActivityManager.ProcessErrorStateInfo report = null;
8464 if (app.crashing) {
8465 report = app.crashingReport;
8466 } else if (app.notResponding) {
8467 report = app.notRespondingReport;
8468 }
8469
8470 if (report != null) {
8471 if (errList == null) {
8472 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8473 }
8474 errList.add(report);
8475 } else {
8476 Log.w(TAG, "Missing app error report, app = " + app.processName +
8477 " crashing = " + app.crashing +
8478 " notResponding = " + app.notResponding);
8479 }
8480 }
8481 }
8482 }
8483
8484 return errList;
8485 }
8486
8487 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8488 // Lazy instantiation of list
8489 List<ActivityManager.RunningAppProcessInfo> runList = null;
8490 synchronized (this) {
8491 // Iterate across all processes
8492 final int N = mLRUProcesses.size();
8493 for (int i = 0; i < N; i++) {
8494 ProcessRecord app = mLRUProcesses.get(i);
8495 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8496 // Generate process state info for running application
8497 ActivityManager.RunningAppProcessInfo currApp =
8498 new ActivityManager.RunningAppProcessInfo(app.processName,
8499 app.pid, app.getPackageList());
8500 int adj = app.curAdj;
8501 if (adj >= CONTENT_PROVIDER_ADJ) {
8502 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8503 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8504 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008505 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8506 } else if (adj >= HOME_APP_ADJ) {
8507 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8508 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 } else if (adj >= SECONDARY_SERVER_ADJ) {
8510 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8511 } else if (adj >= VISIBLE_APP_ADJ) {
8512 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8513 } else {
8514 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8515 }
8516 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8517 // + " lru=" + currApp.lru);
8518 if (runList == null) {
8519 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8520 }
8521 runList.add(currApp);
8522 }
8523 }
8524 }
8525 return runList;
8526 }
8527
8528 @Override
8529 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8530 synchronized (this) {
8531 if (checkCallingPermission(android.Manifest.permission.DUMP)
8532 != PackageManager.PERMISSION_GRANTED) {
8533 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8534 + Binder.getCallingPid()
8535 + ", uid=" + Binder.getCallingUid()
8536 + " without permission "
8537 + android.Manifest.permission.DUMP);
8538 return;
8539 }
8540 if (args.length != 0 && "service".equals(args[0])) {
8541 dumpService(fd, pw, args);
8542 return;
8543 }
8544 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008545 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008546 pw.println(" ");
8547 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008548 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008549 if (mWaitingVisibleActivities.size() > 0) {
8550 pw.println(" ");
8551 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008552 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008553 }
8554 if (mStoppingActivities.size() > 0) {
8555 pw.println(" ");
8556 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008557 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008558 }
8559 if (mFinishingActivities.size() > 0) {
8560 pw.println(" ");
8561 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008562 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008563 }
8564
8565 pw.println(" ");
8566 pw.println(" mPausingActivity: " + mPausingActivity);
8567 pw.println(" mResumedActivity: " + mResumedActivity);
8568 pw.println(" mFocusedActivity: " + mFocusedActivity);
8569 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8570
8571 if (mRecentTasks.size() > 0) {
8572 pw.println(" ");
8573 pw.println("Recent tasks in Current Activity Manager State:");
8574
8575 final int N = mRecentTasks.size();
8576 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008577 TaskRecord tr = mRecentTasks.get(i);
8578 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8579 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008580 mRecentTasks.get(i).dump(pw, " ");
8581 }
8582 }
8583
8584 pw.println(" ");
8585 pw.println(" mCurTask: " + mCurTask);
8586
8587 pw.println(" ");
8588 pw.println("Processes in Current Activity Manager State:");
8589
8590 boolean needSep = false;
8591 int numPers = 0;
8592
8593 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8594 final int NA = procs.size();
8595 for (int ia=0; ia<NA; ia++) {
8596 if (!needSep) {
8597 pw.println(" All known processes:");
8598 needSep = true;
8599 }
8600 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008601 pw.print(r.persistent ? " *PERS*" : " *APP*");
8602 pw.print(" UID "); pw.print(procs.keyAt(ia));
8603 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008604 r.dump(pw, " ");
8605 if (r.persistent) {
8606 numPers++;
8607 }
8608 }
8609 }
8610
8611 if (mLRUProcesses.size() > 0) {
8612 if (needSep) pw.println(" ");
8613 needSep = true;
8614 pw.println(" Running processes (most recent first):");
8615 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008616 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 needSep = true;
8618 }
8619
8620 synchronized (mPidsSelfLocked) {
8621 if (mPidsSelfLocked.size() > 0) {
8622 if (needSep) pw.println(" ");
8623 needSep = true;
8624 pw.println(" PID mappings:");
8625 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008626 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8627 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008628 }
8629 }
8630 }
8631
8632 if (mForegroundProcesses.size() > 0) {
8633 if (needSep) pw.println(" ");
8634 needSep = true;
8635 pw.println(" Foreground Processes:");
8636 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008637 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8638 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008639 }
8640 }
8641
8642 if (mPersistentStartingProcesses.size() > 0) {
8643 if (needSep) pw.println(" ");
8644 needSep = true;
8645 pw.println(" Persisent processes that are starting:");
8646 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008647 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648 }
8649
8650 if (mStartingProcesses.size() > 0) {
8651 if (needSep) pw.println(" ");
8652 needSep = true;
8653 pw.println(" Processes that are starting:");
8654 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008655 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008656 }
8657
8658 if (mRemovedProcesses.size() > 0) {
8659 if (needSep) pw.println(" ");
8660 needSep = true;
8661 pw.println(" Processes that are being removed:");
8662 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008663 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008664 }
8665
8666 if (mProcessesOnHold.size() > 0) {
8667 if (needSep) pw.println(" ");
8668 needSep = true;
8669 pw.println(" Processes that are on old until the system is ready:");
8670 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008671 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008672 }
8673
8674 if (mProcessCrashTimes.getMap().size() > 0) {
8675 if (needSep) pw.println(" ");
8676 needSep = true;
8677 pw.println(" Time since processes crashed:");
8678 long now = SystemClock.uptimeMillis();
8679 for (Map.Entry<String, SparseArray<Long>> procs
8680 : mProcessCrashTimes.getMap().entrySet()) {
8681 SparseArray<Long> uids = procs.getValue();
8682 final int N = uids.size();
8683 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008684 pw.print(" Process "); pw.print(procs.getKey());
8685 pw.print(" uid "); pw.print(uids.keyAt(i));
8686 pw.print(": last crashed ");
8687 pw.print((now-uids.valueAt(i)));
8688 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008689 }
8690 }
8691 }
8692
8693 if (mBadProcesses.getMap().size() > 0) {
8694 if (needSep) pw.println(" ");
8695 needSep = true;
8696 pw.println(" Bad processes:");
8697 for (Map.Entry<String, SparseArray<Long>> procs
8698 : mBadProcesses.getMap().entrySet()) {
8699 SparseArray<Long> uids = procs.getValue();
8700 final int N = uids.size();
8701 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008702 pw.print(" Bad process "); pw.print(procs.getKey());
8703 pw.print(" uid "); pw.print(uids.keyAt(i));
8704 pw.print(": crashed at time ");
8705 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008706 }
8707 }
8708 }
8709
8710 pw.println(" ");
8711 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008712 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008713 pw.println(" mConfiguration: " + mConfiguration);
8714 pw.println(" mStartRunning=" + mStartRunning
8715 + " mSystemReady=" + mSystemReady
8716 + " mBooting=" + mBooting
8717 + " mBooted=" + mBooted
8718 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008719 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008720 pw.println(" mGoingToSleep=" + mGoingToSleep);
8721 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8722 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8723 + " mDebugTransient=" + mDebugTransient
8724 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8725 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008726 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008727 }
8728 }
8729
8730 /**
8731 * There are three ways to call this:
8732 * - no service specified: dump all the services
8733 * - a flattened component name that matched an existing service was specified as the
8734 * first arg: dump that one service
8735 * - the first arg isn't the flattened component name of an existing service:
8736 * dump all services whose component contains the first arg as a substring
8737 */
8738 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8739 String[] newArgs;
8740 String componentNameString;
8741 ServiceRecord r;
8742 if (args.length == 1) {
8743 componentNameString = null;
8744 newArgs = EMPTY_STRING_ARRAY;
8745 r = null;
8746 } else {
8747 componentNameString = args[1];
8748 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8749 r = componentName != null ? mServices.get(componentName) : null;
8750 newArgs = new String[args.length - 2];
8751 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8752 }
8753
8754 if (r != null) {
8755 dumpService(fd, pw, r, newArgs);
8756 } else {
8757 for (ServiceRecord r1 : mServices.values()) {
8758 if (componentNameString == null
8759 || r1.name.flattenToString().contains(componentNameString)) {
8760 dumpService(fd, pw, r1, newArgs);
8761 }
8762 }
8763 }
8764 }
8765
8766 /**
8767 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8768 * there is a thread associated with the service.
8769 */
8770 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8771 pw.println(" Service " + r.name.flattenToString());
8772 if (r.app != null && r.app.thread != null) {
8773 try {
8774 // flush anything that is already in the PrintWriter since the thread is going
8775 // to write to the file descriptor directly
8776 pw.flush();
8777 r.app.thread.dumpService(fd, r, args);
8778 pw.print("\n");
8779 } catch (RemoteException e) {
8780 pw.println("got a RemoteException while dumping the service");
8781 }
8782 }
8783 }
8784
8785 void dumpBroadcasts(PrintWriter pw) {
8786 synchronized (this) {
8787 if (checkCallingPermission(android.Manifest.permission.DUMP)
8788 != PackageManager.PERMISSION_GRANTED) {
8789 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8790 + Binder.getCallingPid()
8791 + ", uid=" + Binder.getCallingUid()
8792 + " without permission "
8793 + android.Manifest.permission.DUMP);
8794 return;
8795 }
8796 pw.println("Broadcasts in Current Activity Manager State:");
8797
8798 if (mRegisteredReceivers.size() > 0) {
8799 pw.println(" ");
8800 pw.println(" Registered Receivers:");
8801 Iterator it = mRegisteredReceivers.values().iterator();
8802 while (it.hasNext()) {
8803 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008804 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008805 r.dump(pw, " ");
8806 }
8807 }
8808
8809 pw.println(" ");
8810 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008811 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008812
8813 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8814 || mPendingBroadcast != null) {
8815 if (mParallelBroadcasts.size() > 0) {
8816 pw.println(" ");
8817 pw.println(" Active broadcasts:");
8818 }
8819 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8820 pw.println(" Broadcast #" + i + ":");
8821 mParallelBroadcasts.get(i).dump(pw, " ");
8822 }
8823 if (mOrderedBroadcasts.size() > 0) {
8824 pw.println(" ");
8825 pw.println(" Active serialized broadcasts:");
8826 }
8827 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8828 pw.println(" Serialized Broadcast #" + i + ":");
8829 mOrderedBroadcasts.get(i).dump(pw, " ");
8830 }
8831 pw.println(" ");
8832 pw.println(" Pending broadcast:");
8833 if (mPendingBroadcast != null) {
8834 mPendingBroadcast.dump(pw, " ");
8835 } else {
8836 pw.println(" (null)");
8837 }
8838 }
8839
8840 pw.println(" ");
8841 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8842 if (mStickyBroadcasts != null) {
8843 pw.println(" ");
8844 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008845 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008846 for (Map.Entry<String, ArrayList<Intent>> ent
8847 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008848 pw.print(" * Sticky action "); pw.print(ent.getKey());
8849 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008850 ArrayList<Intent> intents = ent.getValue();
8851 final int N = intents.size();
8852 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008853 sb.setLength(0);
8854 sb.append(" Intent: ");
8855 intents.get(i).toShortString(sb, true, false);
8856 pw.println(sb.toString());
8857 Bundle bundle = intents.get(i).getExtras();
8858 if (bundle != null) {
8859 pw.print(" ");
8860 pw.println(bundle.toString());
8861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008862 }
8863 }
8864 }
8865
8866 pw.println(" ");
8867 pw.println(" mHandler:");
8868 mHandler.dump(new PrintWriterPrinter(pw), " ");
8869 }
8870 }
8871
8872 void dumpServices(PrintWriter pw) {
8873 synchronized (this) {
8874 if (checkCallingPermission(android.Manifest.permission.DUMP)
8875 != PackageManager.PERMISSION_GRANTED) {
8876 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8877 + Binder.getCallingPid()
8878 + ", uid=" + Binder.getCallingUid()
8879 + " without permission "
8880 + android.Manifest.permission.DUMP);
8881 return;
8882 }
8883 pw.println("Services in Current Activity Manager State:");
8884
8885 boolean needSep = false;
8886
8887 if (mServices.size() > 0) {
8888 pw.println(" Active services:");
8889 Iterator<ServiceRecord> it = mServices.values().iterator();
8890 while (it.hasNext()) {
8891 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008892 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008893 r.dump(pw, " ");
8894 }
8895 needSep = true;
8896 }
8897
8898 if (mPendingServices.size() > 0) {
8899 if (needSep) pw.println(" ");
8900 pw.println(" Pending services:");
8901 for (int i=0; i<mPendingServices.size(); i++) {
8902 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008903 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008904 r.dump(pw, " ");
8905 }
8906 needSep = true;
8907 }
8908
8909 if (mRestartingServices.size() > 0) {
8910 if (needSep) pw.println(" ");
8911 pw.println(" Restarting services:");
8912 for (int i=0; i<mRestartingServices.size(); i++) {
8913 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008914 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008915 r.dump(pw, " ");
8916 }
8917 needSep = true;
8918 }
8919
8920 if (mStoppingServices.size() > 0) {
8921 if (needSep) pw.println(" ");
8922 pw.println(" Stopping services:");
8923 for (int i=0; i<mStoppingServices.size(); i++) {
8924 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008925 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008926 r.dump(pw, " ");
8927 }
8928 needSep = true;
8929 }
8930
8931 if (mServiceConnections.size() > 0) {
8932 if (needSep) pw.println(" ");
8933 pw.println(" Connection bindings to services:");
8934 Iterator<ConnectionRecord> it
8935 = mServiceConnections.values().iterator();
8936 while (it.hasNext()) {
8937 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008938 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008939 r.dump(pw, " ");
8940 }
8941 }
8942 }
8943 }
8944
8945 void dumpProviders(PrintWriter pw) {
8946 synchronized (this) {
8947 if (checkCallingPermission(android.Manifest.permission.DUMP)
8948 != PackageManager.PERMISSION_GRANTED) {
8949 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8950 + Binder.getCallingPid()
8951 + ", uid=" + Binder.getCallingUid()
8952 + " without permission "
8953 + android.Manifest.permission.DUMP);
8954 return;
8955 }
8956
8957 pw.println("Content Providers in Current Activity Manager State:");
8958
8959 boolean needSep = false;
8960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008961 if (mProvidersByClass.size() > 0) {
8962 if (needSep) pw.println(" ");
8963 pw.println(" Published content providers (by class):");
8964 Iterator it = mProvidersByClass.entrySet().iterator();
8965 while (it.hasNext()) {
8966 Map.Entry e = (Map.Entry)it.next();
8967 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008968 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008969 r.dump(pw, " ");
8970 }
8971 needSep = true;
8972 }
8973
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008974 if (mProvidersByName.size() > 0) {
8975 pw.println(" ");
8976 pw.println(" Authority to provider mappings:");
8977 Iterator it = mProvidersByName.entrySet().iterator();
8978 while (it.hasNext()) {
8979 Map.Entry e = (Map.Entry)it.next();
8980 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8981 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8982 pw.println(r);
8983 }
8984 needSep = true;
8985 }
8986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008987 if (mLaunchingProviders.size() > 0) {
8988 if (needSep) pw.println(" ");
8989 pw.println(" Launching content providers:");
8990 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008991 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8992 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008993 }
8994 needSep = true;
8995 }
8996
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008997 if (mGrantedUriPermissions.size() > 0) {
8998 pw.println();
8999 pw.println("Granted Uri Permissions:");
9000 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9001 int uid = mGrantedUriPermissions.keyAt(i);
9002 HashMap<Uri, UriPermission> perms
9003 = mGrantedUriPermissions.valueAt(i);
9004 pw.print(" * UID "); pw.print(uid);
9005 pw.println(" holds:");
9006 for (UriPermission perm : perms.values()) {
9007 pw.print(" "); pw.println(perm);
9008 perm.dump(pw, " ");
9009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009010 }
9011 }
9012 }
9013 }
9014
9015 void dumpSenders(PrintWriter pw) {
9016 synchronized (this) {
9017 if (checkCallingPermission(android.Manifest.permission.DUMP)
9018 != PackageManager.PERMISSION_GRANTED) {
9019 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9020 + Binder.getCallingPid()
9021 + ", uid=" + Binder.getCallingUid()
9022 + " without permission "
9023 + android.Manifest.permission.DUMP);
9024 return;
9025 }
9026
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009027 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009028
9029 if (this.mIntentSenderRecords.size() > 0) {
9030 Iterator<WeakReference<PendingIntentRecord>> it
9031 = mIntentSenderRecords.values().iterator();
9032 while (it.hasNext()) {
9033 WeakReference<PendingIntentRecord> ref = it.next();
9034 PendingIntentRecord rec = ref != null ? ref.get(): null;
9035 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009036 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009037 rec.dump(pw, " ");
9038 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009039 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 }
9041 }
9042 }
9043 }
9044 }
9045
9046 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009047 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009048 TaskRecord lastTask = null;
9049 for (int i=list.size()-1; i>=0; i--) {
9050 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009051 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009052 if (lastTask != r.task) {
9053 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009054 pw.print(prefix);
9055 pw.print(full ? "* " : " ");
9056 pw.println(lastTask);
9057 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009058 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009059 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009060 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009061 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9062 pw.print(" #"); pw.print(i); pw.print(": ");
9063 pw.println(r);
9064 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009065 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009067 }
9068 }
9069
9070 private static final int dumpProcessList(PrintWriter pw, List list,
9071 String prefix, String normalLabel, String persistentLabel,
9072 boolean inclOomAdj) {
9073 int numPers = 0;
9074 for (int i=list.size()-1; i>=0; i--) {
9075 ProcessRecord r = (ProcessRecord)list.get(i);
9076 if (false) {
9077 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9078 + " #" + i + ":");
9079 r.dump(pw, prefix + " ");
9080 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009081 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009082 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009083 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009084 } else {
9085 pw.println(String.format("%s%s #%2d: %s",
9086 prefix, (r.persistent ? persistentLabel : normalLabel),
9087 i, r.toString()));
9088 }
9089 if (r.persistent) {
9090 numPers++;
9091 }
9092 }
9093 return numPers;
9094 }
9095
9096 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9097 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009098 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009099 long uptime = SystemClock.uptimeMillis();
9100 long realtime = SystemClock.elapsedRealtime();
9101
9102 if (isCheckinRequest) {
9103 // short checkin version
9104 pw.println(uptime + "," + realtime);
9105 pw.flush();
9106 } else {
9107 pw.println("Applications Memory Usage (kB):");
9108 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9109 }
9110 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9111 ProcessRecord r = (ProcessRecord)list.get(i);
9112 if (r.thread != null) {
9113 if (!isCheckinRequest) {
9114 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9115 pw.flush();
9116 }
9117 try {
9118 r.thread.asBinder().dump(fd, args);
9119 } catch (RemoteException e) {
9120 if (!isCheckinRequest) {
9121 pw.println("Got RemoteException!");
9122 pw.flush();
9123 }
9124 }
9125 }
9126 }
9127 }
9128
9129 /**
9130 * Searches array of arguments for the specified string
9131 * @param args array of argument strings
9132 * @param value value to search for
9133 * @return true if the value is contained in the array
9134 */
9135 private static boolean scanArgs(String[] args, String value) {
9136 if (args != null) {
9137 for (String arg : args) {
9138 if (value.equals(arg)) {
9139 return true;
9140 }
9141 }
9142 }
9143 return false;
9144 }
9145
Dianne Hackborn75b03852009-06-12 15:43:26 -07009146 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 int count = mHistory.size();
9148
9149 // convert the token to an entry in the history.
9150 HistoryRecord r = null;
9151 int index = -1;
9152 for (int i=count-1; i>=0; i--) {
9153 Object o = mHistory.get(i);
9154 if (o == token) {
9155 r = (HistoryRecord)o;
9156 index = i;
9157 break;
9158 }
9159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009160
9161 return index;
9162 }
9163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009164 private final void killServicesLocked(ProcessRecord app,
9165 boolean allowRestart) {
9166 // Report disconnected services.
9167 if (false) {
9168 // XXX we are letting the client link to the service for
9169 // death notifications.
9170 if (app.services.size() > 0) {
9171 Iterator it = app.services.iterator();
9172 while (it.hasNext()) {
9173 ServiceRecord r = (ServiceRecord)it.next();
9174 if (r.connections.size() > 0) {
9175 Iterator<ConnectionRecord> jt
9176 = r.connections.values().iterator();
9177 while (jt.hasNext()) {
9178 ConnectionRecord c = jt.next();
9179 if (c.binding.client != app) {
9180 try {
9181 //c.conn.connected(r.className, null);
9182 } catch (Exception e) {
9183 // todo: this should be asynchronous!
9184 Log.w(TAG, "Exception thrown disconnected servce "
9185 + r.shortName
9186 + " from app " + app.processName, e);
9187 }
9188 }
9189 }
9190 }
9191 }
9192 }
9193 }
9194
9195 // Clean up any connections this application has to other services.
9196 if (app.connections.size() > 0) {
9197 Iterator<ConnectionRecord> it = app.connections.iterator();
9198 while (it.hasNext()) {
9199 ConnectionRecord r = it.next();
9200 removeConnectionLocked(r, app, null);
9201 }
9202 }
9203 app.connections.clear();
9204
9205 if (app.services.size() != 0) {
9206 // Any services running in the application need to be placed
9207 // back in the pending list.
9208 Iterator it = app.services.iterator();
9209 while (it.hasNext()) {
9210 ServiceRecord sr = (ServiceRecord)it.next();
9211 synchronized (sr.stats.getBatteryStats()) {
9212 sr.stats.stopLaunchedLocked();
9213 }
9214 sr.app = null;
9215 sr.executeNesting = 0;
9216 mStoppingServices.remove(sr);
9217 if (sr.bindings.size() > 0) {
9218 Iterator<IntentBindRecord> bindings
9219 = sr.bindings.values().iterator();
9220 while (bindings.hasNext()) {
9221 IntentBindRecord b = bindings.next();
9222 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9223 + ": shouldUnbind=" + b.hasBound);
9224 b.binder = null;
9225 b.requested = b.received = b.hasBound = false;
9226 }
9227 }
9228
9229 if (sr.crashCount >= 2) {
9230 Log.w(TAG, "Service crashed " + sr.crashCount
9231 + " times, stopping: " + sr);
9232 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9233 sr.crashCount, sr.shortName, app.pid);
9234 bringDownServiceLocked(sr, true);
9235 } else if (!allowRestart) {
9236 bringDownServiceLocked(sr, true);
9237 } else {
9238 scheduleServiceRestartLocked(sr);
9239 }
9240 }
9241
9242 if (!allowRestart) {
9243 app.services.clear();
9244 }
9245 }
9246
9247 app.executingServices.clear();
9248 }
9249
9250 private final void removeDyingProviderLocked(ProcessRecord proc,
9251 ContentProviderRecord cpr) {
9252 synchronized (cpr) {
9253 cpr.launchingApp = null;
9254 cpr.notifyAll();
9255 }
9256
9257 mProvidersByClass.remove(cpr.info.name);
9258 String names[] = cpr.info.authority.split(";");
9259 for (int j = 0; j < names.length; j++) {
9260 mProvidersByName.remove(names[j]);
9261 }
9262
9263 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9264 while (cit.hasNext()) {
9265 ProcessRecord capp = cit.next();
9266 if (!capp.persistent && capp.thread != null
9267 && capp.pid != 0
9268 && capp.pid != MY_PID) {
9269 Log.i(TAG, "Killing app " + capp.processName
9270 + " (pid " + capp.pid
9271 + ") because provider " + cpr.info.name
9272 + " is in dying process " + proc.processName);
9273 Process.killProcess(capp.pid);
9274 }
9275 }
9276
9277 mLaunchingProviders.remove(cpr);
9278 }
9279
9280 /**
9281 * Main code for cleaning up a process when it has gone away. This is
9282 * called both as a result of the process dying, or directly when stopping
9283 * a process when running in single process mode.
9284 */
9285 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9286 boolean restarting, int index) {
9287 if (index >= 0) {
9288 mLRUProcesses.remove(index);
9289 }
9290
9291 // Dismiss any open dialogs.
9292 if (app.crashDialog != null) {
9293 app.crashDialog.dismiss();
9294 app.crashDialog = null;
9295 }
9296 if (app.anrDialog != null) {
9297 app.anrDialog.dismiss();
9298 app.anrDialog = null;
9299 }
9300 if (app.waitDialog != null) {
9301 app.waitDialog.dismiss();
9302 app.waitDialog = null;
9303 }
9304
9305 app.crashing = false;
9306 app.notResponding = false;
9307
9308 app.resetPackageList();
9309 app.thread = null;
9310 app.forcingToForeground = null;
9311 app.foregroundServices = false;
9312
9313 killServicesLocked(app, true);
9314
9315 boolean restart = false;
9316
9317 int NL = mLaunchingProviders.size();
9318
9319 // Remove published content providers.
9320 if (!app.pubProviders.isEmpty()) {
9321 Iterator it = app.pubProviders.values().iterator();
9322 while (it.hasNext()) {
9323 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9324 cpr.provider = null;
9325 cpr.app = null;
9326
9327 // See if someone is waiting for this provider... in which
9328 // case we don't remove it, but just let it restart.
9329 int i = 0;
9330 if (!app.bad) {
9331 for (; i<NL; i++) {
9332 if (mLaunchingProviders.get(i) == cpr) {
9333 restart = true;
9334 break;
9335 }
9336 }
9337 } else {
9338 i = NL;
9339 }
9340
9341 if (i >= NL) {
9342 removeDyingProviderLocked(app, cpr);
9343 NL = mLaunchingProviders.size();
9344 }
9345 }
9346 app.pubProviders.clear();
9347 }
9348
9349 // Look through the content providers we are waiting to have launched,
9350 // and if any run in this process then either schedule a restart of
9351 // the process or kill the client waiting for it if this process has
9352 // gone bad.
9353 for (int i=0; i<NL; i++) {
9354 ContentProviderRecord cpr = (ContentProviderRecord)
9355 mLaunchingProviders.get(i);
9356 if (cpr.launchingApp == app) {
9357 if (!app.bad) {
9358 restart = true;
9359 } else {
9360 removeDyingProviderLocked(app, cpr);
9361 NL = mLaunchingProviders.size();
9362 }
9363 }
9364 }
9365
9366 // Unregister from connected content providers.
9367 if (!app.conProviders.isEmpty()) {
9368 Iterator it = app.conProviders.iterator();
9369 while (it.hasNext()) {
9370 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9371 cpr.clients.remove(app);
9372 }
9373 app.conProviders.clear();
9374 }
9375
9376 skipCurrentReceiverLocked(app);
9377
9378 // Unregister any receivers.
9379 if (app.receivers.size() > 0) {
9380 Iterator<ReceiverList> it = app.receivers.iterator();
9381 while (it.hasNext()) {
9382 removeReceiverLocked(it.next());
9383 }
9384 app.receivers.clear();
9385 }
9386
Christopher Tate181fafa2009-05-14 11:12:14 -07009387 // If the app is undergoing backup, tell the backup manager about it
9388 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9389 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9390 try {
9391 IBackupManager bm = IBackupManager.Stub.asInterface(
9392 ServiceManager.getService(Context.BACKUP_SERVICE));
9393 bm.agentDisconnected(app.info.packageName);
9394 } catch (RemoteException e) {
9395 // can't happen; backup manager is local
9396 }
9397 }
9398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009399 // If the caller is restarting this app, then leave it in its
9400 // current lists and let the caller take care of it.
9401 if (restarting) {
9402 return;
9403 }
9404
9405 if (!app.persistent) {
9406 if (DEBUG_PROCESSES) Log.v(TAG,
9407 "Removing non-persistent process during cleanup: " + app);
9408 mProcessNames.remove(app.processName, app.info.uid);
9409 } else if (!app.removed) {
9410 // This app is persistent, so we need to keep its record around.
9411 // If it is not already on the pending app list, add it there
9412 // and start a new process for it.
9413 app.thread = null;
9414 app.forcingToForeground = null;
9415 app.foregroundServices = false;
9416 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9417 mPersistentStartingProcesses.add(app);
9418 restart = true;
9419 }
9420 }
9421 mProcessesOnHold.remove(app);
9422
The Android Open Source Project4df24232009-03-05 14:34:35 -08009423 if (app == mHomeProcess) {
9424 mHomeProcess = null;
9425 }
9426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009427 if (restart) {
9428 // We have components that still need to be running in the
9429 // process, so re-launch it.
9430 mProcessNames.put(app.processName, app.info.uid, app);
9431 startProcessLocked(app, "restart", app.processName);
9432 } else if (app.pid > 0 && app.pid != MY_PID) {
9433 // Goodbye!
9434 synchronized (mPidsSelfLocked) {
9435 mPidsSelfLocked.remove(app.pid);
9436 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9437 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009438 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009439 }
9440 }
9441
9442 // =========================================================
9443 // SERVICES
9444 // =========================================================
9445
9446 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9447 ActivityManager.RunningServiceInfo info =
9448 new ActivityManager.RunningServiceInfo();
9449 info.service = r.name;
9450 if (r.app != null) {
9451 info.pid = r.app.pid;
9452 }
9453 info.process = r.processName;
9454 info.foreground = r.isForeground;
9455 info.activeSince = r.createTime;
9456 info.started = r.startRequested;
9457 info.clientCount = r.connections.size();
9458 info.crashCount = r.crashCount;
9459 info.lastActivityTime = r.lastActivity;
9460 return info;
9461 }
9462
9463 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9464 int flags) {
9465 synchronized (this) {
9466 ArrayList<ActivityManager.RunningServiceInfo> res
9467 = new ArrayList<ActivityManager.RunningServiceInfo>();
9468
9469 if (mServices.size() > 0) {
9470 Iterator<ServiceRecord> it = mServices.values().iterator();
9471 while (it.hasNext() && res.size() < maxNum) {
9472 res.add(makeRunningServiceInfoLocked(it.next()));
9473 }
9474 }
9475
9476 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9477 ServiceRecord r = mRestartingServices.get(i);
9478 ActivityManager.RunningServiceInfo info =
9479 makeRunningServiceInfoLocked(r);
9480 info.restarting = r.nextRestartTime;
9481 res.add(info);
9482 }
9483
9484 return res;
9485 }
9486 }
9487
9488 private final ServiceRecord findServiceLocked(ComponentName name,
9489 IBinder token) {
9490 ServiceRecord r = mServices.get(name);
9491 return r == token ? r : null;
9492 }
9493
9494 private final class ServiceLookupResult {
9495 final ServiceRecord record;
9496 final String permission;
9497
9498 ServiceLookupResult(ServiceRecord _record, String _permission) {
9499 record = _record;
9500 permission = _permission;
9501 }
9502 };
9503
9504 private ServiceLookupResult findServiceLocked(Intent service,
9505 String resolvedType) {
9506 ServiceRecord r = null;
9507 if (service.getComponent() != null) {
9508 r = mServices.get(service.getComponent());
9509 }
9510 if (r == null) {
9511 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9512 r = mServicesByIntent.get(filter);
9513 }
9514
9515 if (r == null) {
9516 try {
9517 ResolveInfo rInfo =
9518 ActivityThread.getPackageManager().resolveService(
9519 service, resolvedType, 0);
9520 ServiceInfo sInfo =
9521 rInfo != null ? rInfo.serviceInfo : null;
9522 if (sInfo == null) {
9523 return null;
9524 }
9525
9526 ComponentName name = new ComponentName(
9527 sInfo.applicationInfo.packageName, sInfo.name);
9528 r = mServices.get(name);
9529 } catch (RemoteException ex) {
9530 // pm is in same process, this will never happen.
9531 }
9532 }
9533 if (r != null) {
9534 int callingPid = Binder.getCallingPid();
9535 int callingUid = Binder.getCallingUid();
9536 if (checkComponentPermission(r.permission,
9537 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9538 != PackageManager.PERMISSION_GRANTED) {
9539 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9540 + " from pid=" + callingPid
9541 + ", uid=" + callingUid
9542 + " requires " + r.permission);
9543 return new ServiceLookupResult(null, r.permission);
9544 }
9545 return new ServiceLookupResult(r, null);
9546 }
9547 return null;
9548 }
9549
9550 private class ServiceRestarter implements Runnable {
9551 private ServiceRecord mService;
9552
9553 void setService(ServiceRecord service) {
9554 mService = service;
9555 }
9556
9557 public void run() {
9558 synchronized(ActivityManagerService.this) {
9559 performServiceRestartLocked(mService);
9560 }
9561 }
9562 }
9563
9564 private ServiceLookupResult retrieveServiceLocked(Intent service,
9565 String resolvedType, int callingPid, int callingUid) {
9566 ServiceRecord r = null;
9567 if (service.getComponent() != null) {
9568 r = mServices.get(service.getComponent());
9569 }
9570 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9571 r = mServicesByIntent.get(filter);
9572 if (r == null) {
9573 try {
9574 ResolveInfo rInfo =
9575 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009576 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009577 ServiceInfo sInfo =
9578 rInfo != null ? rInfo.serviceInfo : null;
9579 if (sInfo == null) {
9580 Log.w(TAG, "Unable to start service " + service +
9581 ": not found");
9582 return null;
9583 }
9584
9585 ComponentName name = new ComponentName(
9586 sInfo.applicationInfo.packageName, sInfo.name);
9587 r = mServices.get(name);
9588 if (r == null) {
9589 filter = new Intent.FilterComparison(service.cloneFilter());
9590 ServiceRestarter res = new ServiceRestarter();
9591 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9592 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9593 synchronized (stats) {
9594 ss = stats.getServiceStatsLocked(
9595 sInfo.applicationInfo.uid, sInfo.packageName,
9596 sInfo.name);
9597 }
9598 r = new ServiceRecord(ss, name, filter, sInfo, res);
9599 res.setService(r);
9600 mServices.put(name, r);
9601 mServicesByIntent.put(filter, r);
9602
9603 // Make sure this component isn't in the pending list.
9604 int N = mPendingServices.size();
9605 for (int i=0; i<N; i++) {
9606 ServiceRecord pr = mPendingServices.get(i);
9607 if (pr.name.equals(name)) {
9608 mPendingServices.remove(i);
9609 i--;
9610 N--;
9611 }
9612 }
9613 }
9614 } catch (RemoteException ex) {
9615 // pm is in same process, this will never happen.
9616 }
9617 }
9618 if (r != null) {
9619 if (checkComponentPermission(r.permission,
9620 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9621 != PackageManager.PERMISSION_GRANTED) {
9622 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9623 + " from pid=" + Binder.getCallingPid()
9624 + ", uid=" + Binder.getCallingUid()
9625 + " requires " + r.permission);
9626 return new ServiceLookupResult(null, r.permission);
9627 }
9628 return new ServiceLookupResult(r, null);
9629 }
9630 return null;
9631 }
9632
9633 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9634 long now = SystemClock.uptimeMillis();
9635 if (r.executeNesting == 0 && r.app != null) {
9636 if (r.app.executingServices.size() == 0) {
9637 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9638 msg.obj = r.app;
9639 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9640 }
9641 r.app.executingServices.add(r);
9642 }
9643 r.executeNesting++;
9644 r.executingStart = now;
9645 }
9646
9647 private final void sendServiceArgsLocked(ServiceRecord r,
9648 boolean oomAdjusted) {
9649 final int N = r.startArgs.size();
9650 if (N == 0) {
9651 return;
9652 }
9653
9654 final int BASEID = r.lastStartId - N + 1;
9655 int i = 0;
9656 while (i < N) {
9657 try {
9658 Intent args = r.startArgs.get(i);
9659 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9660 + r.name + " " + r.intent + " args=" + args);
9661 bumpServiceExecutingLocked(r);
9662 if (!oomAdjusted) {
9663 oomAdjusted = true;
9664 updateOomAdjLocked(r.app);
9665 }
9666 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9667 i++;
9668 } catch (Exception e) {
9669 break;
9670 }
9671 }
9672 if (i == N) {
9673 r.startArgs.clear();
9674 } else {
9675 while (i > 0) {
9676 r.startArgs.remove(0);
9677 i--;
9678 }
9679 }
9680 }
9681
9682 private final boolean requestServiceBindingLocked(ServiceRecord r,
9683 IntentBindRecord i, boolean rebind) {
9684 if (r.app == null || r.app.thread == null) {
9685 // If service is not currently running, can't yet bind.
9686 return false;
9687 }
9688 if ((!i.requested || rebind) && i.apps.size() > 0) {
9689 try {
9690 bumpServiceExecutingLocked(r);
9691 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9692 + ": shouldUnbind=" + i.hasBound);
9693 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9694 if (!rebind) {
9695 i.requested = true;
9696 }
9697 i.hasBound = true;
9698 i.doRebind = false;
9699 } catch (RemoteException e) {
9700 return false;
9701 }
9702 }
9703 return true;
9704 }
9705
9706 private final void requestServiceBindingsLocked(ServiceRecord r) {
9707 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9708 while (bindings.hasNext()) {
9709 IntentBindRecord i = bindings.next();
9710 if (!requestServiceBindingLocked(r, i, false)) {
9711 break;
9712 }
9713 }
9714 }
9715
9716 private final void realStartServiceLocked(ServiceRecord r,
9717 ProcessRecord app) throws RemoteException {
9718 if (app.thread == null) {
9719 throw new RemoteException();
9720 }
9721
9722 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009723 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009724
9725 app.services.add(r);
9726 bumpServiceExecutingLocked(r);
9727 updateLRUListLocked(app, true);
9728
9729 boolean created = false;
9730 try {
9731 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9732 + r.name + " " + r.intent);
9733 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9734 System.identityHashCode(r), r.shortName,
9735 r.intent.getIntent().toString(), r.app.pid);
9736 synchronized (r.stats.getBatteryStats()) {
9737 r.stats.startLaunchedLocked();
9738 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009739 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009740 app.thread.scheduleCreateService(r, r.serviceInfo);
9741 created = true;
9742 } finally {
9743 if (!created) {
9744 app.services.remove(r);
9745 scheduleServiceRestartLocked(r);
9746 }
9747 }
9748
9749 requestServiceBindingsLocked(r);
9750 sendServiceArgsLocked(r, true);
9751 }
9752
9753 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9754 r.totalRestartCount++;
9755 if (r.restartDelay == 0) {
9756 r.restartCount++;
9757 r.restartDelay = SERVICE_RESTART_DURATION;
9758 } else {
9759 // If it has been a "reasonably long time" since the service
9760 // was started, then reset our restart duration back to
9761 // the beginning, so we don't infinitely increase the duration
9762 // on a service that just occasionally gets killed (which is
9763 // a normal case, due to process being killed to reclaim memory).
9764 long now = SystemClock.uptimeMillis();
9765 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9766 r.restartCount = 1;
9767 r.restartDelay = SERVICE_RESTART_DURATION;
9768 } else {
9769 r.restartDelay *= 2;
9770 }
9771 }
9772 if (!mRestartingServices.contains(r)) {
9773 mRestartingServices.add(r);
9774 }
9775 mHandler.removeCallbacks(r.restarter);
9776 mHandler.postDelayed(r.restarter, r.restartDelay);
9777 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9778 Log.w(TAG, "Scheduling restart of crashed service "
9779 + r.shortName + " in " + r.restartDelay + "ms");
9780 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9781 r.shortName, r.restartDelay);
9782
9783 Message msg = Message.obtain();
9784 msg.what = SERVICE_ERROR_MSG;
9785 msg.obj = r;
9786 mHandler.sendMessage(msg);
9787 }
9788
9789 final void performServiceRestartLocked(ServiceRecord r) {
9790 if (!mRestartingServices.contains(r)) {
9791 return;
9792 }
9793 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9794 }
9795
9796 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9797 if (r.restartDelay == 0) {
9798 return false;
9799 }
9800 r.resetRestartCounter();
9801 mRestartingServices.remove(r);
9802 mHandler.removeCallbacks(r.restarter);
9803 return true;
9804 }
9805
9806 private final boolean bringUpServiceLocked(ServiceRecord r,
9807 int intentFlags, boolean whileRestarting) {
9808 //Log.i(TAG, "Bring up service:");
9809 //r.dump(" ");
9810
9811 if (r.app != null) {
9812 sendServiceArgsLocked(r, false);
9813 return true;
9814 }
9815
9816 if (!whileRestarting && r.restartDelay > 0) {
9817 // If waiting for a restart, then do nothing.
9818 return true;
9819 }
9820
9821 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9822 + " " + r.intent);
9823
9824 final String appName = r.processName;
9825 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9826 if (app != null && app.thread != null) {
9827 try {
9828 realStartServiceLocked(r, app);
9829 return true;
9830 } catch (RemoteException e) {
9831 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9832 }
9833
9834 // If a dead object exception was thrown -- fall through to
9835 // restart the application.
9836 }
9837
9838 if (!mPendingServices.contains(r)) {
9839 // Not running -- get it started, and enqueue this service record
9840 // to be executed when the app comes up.
9841 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9842 "service", r.name) == null) {
9843 Log.w(TAG, "Unable to launch app "
9844 + r.appInfo.packageName + "/"
9845 + r.appInfo.uid + " for service "
9846 + r.intent.getIntent() + ": process is bad");
9847 bringDownServiceLocked(r, true);
9848 return false;
9849 }
9850 mPendingServices.add(r);
9851 }
9852 return true;
9853 }
9854
9855 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9856 //Log.i(TAG, "Bring down service:");
9857 //r.dump(" ");
9858
9859 // Does it still need to run?
9860 if (!force && r.startRequested) {
9861 return;
9862 }
9863 if (r.connections.size() > 0) {
9864 if (!force) {
9865 // XXX should probably keep a count of the number of auto-create
9866 // connections directly in the service.
9867 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9868 while (it.hasNext()) {
9869 ConnectionRecord cr = it.next();
9870 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9871 return;
9872 }
9873 }
9874 }
9875
9876 // Report to all of the connections that the service is no longer
9877 // available.
9878 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9879 while (it.hasNext()) {
9880 ConnectionRecord c = it.next();
9881 try {
9882 // todo: shouldn't be a synchronous call!
9883 c.conn.connected(r.name, null);
9884 } catch (Exception e) {
9885 Log.w(TAG, "Failure disconnecting service " + r.name +
9886 " to connection " + c.conn.asBinder() +
9887 " (in " + c.binding.client.processName + ")", e);
9888 }
9889 }
9890 }
9891
9892 // Tell the service that it has been unbound.
9893 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9894 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9895 while (it.hasNext()) {
9896 IntentBindRecord ibr = it.next();
9897 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9898 + ": hasBound=" + ibr.hasBound);
9899 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9900 try {
9901 bumpServiceExecutingLocked(r);
9902 updateOomAdjLocked(r.app);
9903 ibr.hasBound = false;
9904 r.app.thread.scheduleUnbindService(r,
9905 ibr.intent.getIntent());
9906 } catch (Exception e) {
9907 Log.w(TAG, "Exception when unbinding service "
9908 + r.shortName, e);
9909 serviceDoneExecutingLocked(r, true);
9910 }
9911 }
9912 }
9913 }
9914
9915 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9916 + " " + r.intent);
9917 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9918 System.identityHashCode(r), r.shortName,
9919 (r.app != null) ? r.app.pid : -1);
9920
9921 mServices.remove(r.name);
9922 mServicesByIntent.remove(r.intent);
9923 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9924 r.totalRestartCount = 0;
9925 unscheduleServiceRestartLocked(r);
9926
9927 // Also make sure it is not on the pending list.
9928 int N = mPendingServices.size();
9929 for (int i=0; i<N; i++) {
9930 if (mPendingServices.get(i) == r) {
9931 mPendingServices.remove(i);
9932 if (DEBUG_SERVICE) Log.v(
9933 TAG, "Removed pending service: " + r.shortName);
9934 i--;
9935 N--;
9936 }
9937 }
9938
9939 if (r.app != null) {
9940 synchronized (r.stats.getBatteryStats()) {
9941 r.stats.stopLaunchedLocked();
9942 }
9943 r.app.services.remove(r);
9944 if (r.app.thread != null) {
9945 updateServiceForegroundLocked(r.app, false);
9946 try {
9947 Log.i(TAG, "Stopping service: " + r.shortName);
9948 bumpServiceExecutingLocked(r);
9949 mStoppingServices.add(r);
9950 updateOomAdjLocked(r.app);
9951 r.app.thread.scheduleStopService(r);
9952 } catch (Exception e) {
9953 Log.w(TAG, "Exception when stopping service "
9954 + r.shortName, e);
9955 serviceDoneExecutingLocked(r, true);
9956 }
9957 } else {
9958 if (DEBUG_SERVICE) Log.v(
9959 TAG, "Removed service that has no process: " + r.shortName);
9960 }
9961 } else {
9962 if (DEBUG_SERVICE) Log.v(
9963 TAG, "Removed service that is not running: " + r.shortName);
9964 }
9965 }
9966
9967 ComponentName startServiceLocked(IApplicationThread caller,
9968 Intent service, String resolvedType,
9969 int callingPid, int callingUid) {
9970 synchronized(this) {
9971 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9972 + " type=" + resolvedType + " args=" + service.getExtras());
9973
9974 if (caller != null) {
9975 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9976 if (callerApp == null) {
9977 throw new SecurityException(
9978 "Unable to find app for caller " + caller
9979 + " (pid=" + Binder.getCallingPid()
9980 + ") when starting service " + service);
9981 }
9982 }
9983
9984 ServiceLookupResult res =
9985 retrieveServiceLocked(service, resolvedType,
9986 callingPid, callingUid);
9987 if (res == null) {
9988 return null;
9989 }
9990 if (res.record == null) {
9991 return new ComponentName("!", res.permission != null
9992 ? res.permission : "private to package");
9993 }
9994 ServiceRecord r = res.record;
9995 if (unscheduleServiceRestartLocked(r)) {
9996 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9997 + r.shortName);
9998 }
9999 r.startRequested = true;
10000 r.startArgs.add(service);
10001 r.lastStartId++;
10002 if (r.lastStartId < 1) {
10003 r.lastStartId = 1;
10004 }
10005 r.lastActivity = SystemClock.uptimeMillis();
10006 synchronized (r.stats.getBatteryStats()) {
10007 r.stats.startRunningLocked();
10008 }
10009 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10010 return new ComponentName("!", "Service process is bad");
10011 }
10012 return r.name;
10013 }
10014 }
10015
10016 public ComponentName startService(IApplicationThread caller, Intent service,
10017 String resolvedType) {
10018 // Refuse possible leaked file descriptors
10019 if (service != null && service.hasFileDescriptors() == true) {
10020 throw new IllegalArgumentException("File descriptors passed in Intent");
10021 }
10022
10023 synchronized(this) {
10024 final int callingPid = Binder.getCallingPid();
10025 final int callingUid = Binder.getCallingUid();
10026 final long origId = Binder.clearCallingIdentity();
10027 ComponentName res = startServiceLocked(caller, service,
10028 resolvedType, callingPid, callingUid);
10029 Binder.restoreCallingIdentity(origId);
10030 return res;
10031 }
10032 }
10033
10034 ComponentName startServiceInPackage(int uid,
10035 Intent service, String resolvedType) {
10036 synchronized(this) {
10037 final long origId = Binder.clearCallingIdentity();
10038 ComponentName res = startServiceLocked(null, service,
10039 resolvedType, -1, uid);
10040 Binder.restoreCallingIdentity(origId);
10041 return res;
10042 }
10043 }
10044
10045 public int stopService(IApplicationThread caller, Intent service,
10046 String resolvedType) {
10047 // Refuse possible leaked file descriptors
10048 if (service != null && service.hasFileDescriptors() == true) {
10049 throw new IllegalArgumentException("File descriptors passed in Intent");
10050 }
10051
10052 synchronized(this) {
10053 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10054 + " type=" + resolvedType);
10055
10056 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10057 if (caller != null && callerApp == null) {
10058 throw new SecurityException(
10059 "Unable to find app for caller " + caller
10060 + " (pid=" + Binder.getCallingPid()
10061 + ") when stopping service " + service);
10062 }
10063
10064 // If this service is active, make sure it is stopped.
10065 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10066 if (r != null) {
10067 if (r.record != null) {
10068 synchronized (r.record.stats.getBatteryStats()) {
10069 r.record.stats.stopRunningLocked();
10070 }
10071 r.record.startRequested = false;
10072 final long origId = Binder.clearCallingIdentity();
10073 bringDownServiceLocked(r.record, false);
10074 Binder.restoreCallingIdentity(origId);
10075 return 1;
10076 }
10077 return -1;
10078 }
10079 }
10080
10081 return 0;
10082 }
10083
10084 public IBinder peekService(Intent service, String resolvedType) {
10085 // Refuse possible leaked file descriptors
10086 if (service != null && service.hasFileDescriptors() == true) {
10087 throw new IllegalArgumentException("File descriptors passed in Intent");
10088 }
10089
10090 IBinder ret = null;
10091
10092 synchronized(this) {
10093 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10094
10095 if (r != null) {
10096 // r.record is null if findServiceLocked() failed the caller permission check
10097 if (r.record == null) {
10098 throw new SecurityException(
10099 "Permission Denial: Accessing service " + r.record.name
10100 + " from pid=" + Binder.getCallingPid()
10101 + ", uid=" + Binder.getCallingUid()
10102 + " requires " + r.permission);
10103 }
10104 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10105 if (ib != null) {
10106 ret = ib.binder;
10107 }
10108 }
10109 }
10110
10111 return ret;
10112 }
10113
10114 public boolean stopServiceToken(ComponentName className, IBinder token,
10115 int startId) {
10116 synchronized(this) {
10117 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10118 + " " + token + " startId=" + startId);
10119 ServiceRecord r = findServiceLocked(className, token);
10120 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10121 synchronized (r.stats.getBatteryStats()) {
10122 r.stats.stopRunningLocked();
10123 r.startRequested = false;
10124 }
10125 final long origId = Binder.clearCallingIdentity();
10126 bringDownServiceLocked(r, false);
10127 Binder.restoreCallingIdentity(origId);
10128 return true;
10129 }
10130 }
10131 return false;
10132 }
10133
10134 public void setServiceForeground(ComponentName className, IBinder token,
10135 boolean isForeground) {
10136 synchronized(this) {
10137 ServiceRecord r = findServiceLocked(className, token);
10138 if (r != null) {
10139 if (r.isForeground != isForeground) {
10140 final long origId = Binder.clearCallingIdentity();
10141 r.isForeground = isForeground;
10142 if (r.app != null) {
10143 updateServiceForegroundLocked(r.app, true);
10144 }
10145 Binder.restoreCallingIdentity(origId);
10146 }
10147 }
10148 }
10149 }
10150
10151 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10152 boolean anyForeground = false;
10153 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10154 if (sr.isForeground) {
10155 anyForeground = true;
10156 break;
10157 }
10158 }
10159 if (anyForeground != proc.foregroundServices) {
10160 proc.foregroundServices = anyForeground;
10161 if (oomAdj) {
10162 updateOomAdjLocked();
10163 }
10164 }
10165 }
10166
10167 public int bindService(IApplicationThread caller, IBinder token,
10168 Intent service, String resolvedType,
10169 IServiceConnection connection, int flags) {
10170 // Refuse possible leaked file descriptors
10171 if (service != null && service.hasFileDescriptors() == true) {
10172 throw new IllegalArgumentException("File descriptors passed in Intent");
10173 }
10174
10175 synchronized(this) {
10176 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10177 + " type=" + resolvedType + " conn=" + connection.asBinder()
10178 + " flags=0x" + Integer.toHexString(flags));
10179 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10180 if (callerApp == null) {
10181 throw new SecurityException(
10182 "Unable to find app for caller " + caller
10183 + " (pid=" + Binder.getCallingPid()
10184 + ") when binding service " + service);
10185 }
10186
10187 HistoryRecord activity = null;
10188 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010189 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010190 if (aindex < 0) {
10191 Log.w(TAG, "Binding with unknown activity: " + token);
10192 return 0;
10193 }
10194 activity = (HistoryRecord)mHistory.get(aindex);
10195 }
10196
10197 ServiceLookupResult res =
10198 retrieveServiceLocked(service, resolvedType,
10199 Binder.getCallingPid(), Binder.getCallingUid());
10200 if (res == null) {
10201 return 0;
10202 }
10203 if (res.record == null) {
10204 return -1;
10205 }
10206 ServiceRecord s = res.record;
10207
10208 final long origId = Binder.clearCallingIdentity();
10209
10210 if (unscheduleServiceRestartLocked(s)) {
10211 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10212 + s.shortName);
10213 }
10214
10215 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10216 ConnectionRecord c = new ConnectionRecord(b, activity,
10217 connection, flags);
10218
10219 IBinder binder = connection.asBinder();
10220 s.connections.put(binder, c);
10221 b.connections.add(c);
10222 if (activity != null) {
10223 if (activity.connections == null) {
10224 activity.connections = new HashSet<ConnectionRecord>();
10225 }
10226 activity.connections.add(c);
10227 }
10228 b.client.connections.add(c);
10229 mServiceConnections.put(binder, c);
10230
10231 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10232 s.lastActivity = SystemClock.uptimeMillis();
10233 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10234 return 0;
10235 }
10236 }
10237
10238 if (s.app != null) {
10239 // This could have made the service more important.
10240 updateOomAdjLocked(s.app);
10241 }
10242
10243 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10244 + ": received=" + b.intent.received
10245 + " apps=" + b.intent.apps.size()
10246 + " doRebind=" + b.intent.doRebind);
10247
10248 if (s.app != null && b.intent.received) {
10249 // Service is already running, so we can immediately
10250 // publish the connection.
10251 try {
10252 c.conn.connected(s.name, b.intent.binder);
10253 } catch (Exception e) {
10254 Log.w(TAG, "Failure sending service " + s.shortName
10255 + " to connection " + c.conn.asBinder()
10256 + " (in " + c.binding.client.processName + ")", e);
10257 }
10258
10259 // If this is the first app connected back to this binding,
10260 // and the service had previously asked to be told when
10261 // rebound, then do so.
10262 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10263 requestServiceBindingLocked(s, b.intent, true);
10264 }
10265 } else if (!b.intent.requested) {
10266 requestServiceBindingLocked(s, b.intent, false);
10267 }
10268
10269 Binder.restoreCallingIdentity(origId);
10270 }
10271
10272 return 1;
10273 }
10274
10275 private void removeConnectionLocked(
10276 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10277 IBinder binder = c.conn.asBinder();
10278 AppBindRecord b = c.binding;
10279 ServiceRecord s = b.service;
10280 s.connections.remove(binder);
10281 b.connections.remove(c);
10282 if (c.activity != null && c.activity != skipAct) {
10283 if (c.activity.connections != null) {
10284 c.activity.connections.remove(c);
10285 }
10286 }
10287 if (b.client != skipApp) {
10288 b.client.connections.remove(c);
10289 }
10290 mServiceConnections.remove(binder);
10291
10292 if (b.connections.size() == 0) {
10293 b.intent.apps.remove(b.client);
10294 }
10295
10296 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10297 + ": shouldUnbind=" + b.intent.hasBound);
10298 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10299 && b.intent.hasBound) {
10300 try {
10301 bumpServiceExecutingLocked(s);
10302 updateOomAdjLocked(s.app);
10303 b.intent.hasBound = false;
10304 // Assume the client doesn't want to know about a rebind;
10305 // we will deal with that later if it asks for one.
10306 b.intent.doRebind = false;
10307 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10308 } catch (Exception e) {
10309 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10310 serviceDoneExecutingLocked(s, true);
10311 }
10312 }
10313
10314 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10315 bringDownServiceLocked(s, false);
10316 }
10317 }
10318
10319 public boolean unbindService(IServiceConnection connection) {
10320 synchronized (this) {
10321 IBinder binder = connection.asBinder();
10322 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10323 ConnectionRecord r = mServiceConnections.get(binder);
10324 if (r == null) {
10325 Log.w(TAG, "Unbind failed: could not find connection for "
10326 + connection.asBinder());
10327 return false;
10328 }
10329
10330 final long origId = Binder.clearCallingIdentity();
10331
10332 removeConnectionLocked(r, null, null);
10333
10334 if (r.binding.service.app != null) {
10335 // This could have made the service less important.
10336 updateOomAdjLocked(r.binding.service.app);
10337 }
10338
10339 Binder.restoreCallingIdentity(origId);
10340 }
10341
10342 return true;
10343 }
10344
10345 public void publishService(IBinder token, Intent intent, IBinder service) {
10346 // Refuse possible leaked file descriptors
10347 if (intent != null && intent.hasFileDescriptors() == true) {
10348 throw new IllegalArgumentException("File descriptors passed in Intent");
10349 }
10350
10351 synchronized(this) {
10352 if (!(token instanceof ServiceRecord)) {
10353 throw new IllegalArgumentException("Invalid service token");
10354 }
10355 ServiceRecord r = (ServiceRecord)token;
10356
10357 final long origId = Binder.clearCallingIdentity();
10358
10359 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10360 + " " + intent + ": " + service);
10361 if (r != null) {
10362 Intent.FilterComparison filter
10363 = new Intent.FilterComparison(intent);
10364 IntentBindRecord b = r.bindings.get(filter);
10365 if (b != null && !b.received) {
10366 b.binder = service;
10367 b.requested = true;
10368 b.received = true;
10369 if (r.connections.size() > 0) {
10370 Iterator<ConnectionRecord> it
10371 = r.connections.values().iterator();
10372 while (it.hasNext()) {
10373 ConnectionRecord c = it.next();
10374 if (!filter.equals(c.binding.intent.intent)) {
10375 if (DEBUG_SERVICE) Log.v(
10376 TAG, "Not publishing to: " + c);
10377 if (DEBUG_SERVICE) Log.v(
10378 TAG, "Bound intent: " + c.binding.intent.intent);
10379 if (DEBUG_SERVICE) Log.v(
10380 TAG, "Published intent: " + intent);
10381 continue;
10382 }
10383 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10384 try {
10385 c.conn.connected(r.name, service);
10386 } catch (Exception e) {
10387 Log.w(TAG, "Failure sending service " + r.name +
10388 " to connection " + c.conn.asBinder() +
10389 " (in " + c.binding.client.processName + ")", e);
10390 }
10391 }
10392 }
10393 }
10394
10395 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10396
10397 Binder.restoreCallingIdentity(origId);
10398 }
10399 }
10400 }
10401
10402 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10403 // Refuse possible leaked file descriptors
10404 if (intent != null && intent.hasFileDescriptors() == true) {
10405 throw new IllegalArgumentException("File descriptors passed in Intent");
10406 }
10407
10408 synchronized(this) {
10409 if (!(token instanceof ServiceRecord)) {
10410 throw new IllegalArgumentException("Invalid service token");
10411 }
10412 ServiceRecord r = (ServiceRecord)token;
10413
10414 final long origId = Binder.clearCallingIdentity();
10415
10416 if (r != null) {
10417 Intent.FilterComparison filter
10418 = new Intent.FilterComparison(intent);
10419 IntentBindRecord b = r.bindings.get(filter);
10420 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10421 + " at " + b + ": apps="
10422 + (b != null ? b.apps.size() : 0));
10423 if (b != null) {
10424 if (b.apps.size() > 0) {
10425 // Applications have already bound since the last
10426 // unbind, so just rebind right here.
10427 requestServiceBindingLocked(r, b, true);
10428 } else {
10429 // Note to tell the service the next time there is
10430 // a new client.
10431 b.doRebind = true;
10432 }
10433 }
10434
10435 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10436
10437 Binder.restoreCallingIdentity(origId);
10438 }
10439 }
10440 }
10441
10442 public void serviceDoneExecuting(IBinder token) {
10443 synchronized(this) {
10444 if (!(token instanceof ServiceRecord)) {
10445 throw new IllegalArgumentException("Invalid service token");
10446 }
10447 ServiceRecord r = (ServiceRecord)token;
10448 boolean inStopping = mStoppingServices.contains(token);
10449 if (r != null) {
10450 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10451 + ": nesting=" + r.executeNesting
10452 + ", inStopping=" + inStopping);
10453 if (r != token) {
10454 Log.w(TAG, "Done executing service " + r.name
10455 + " with incorrect token: given " + token
10456 + ", expected " + r);
10457 return;
10458 }
10459
10460 final long origId = Binder.clearCallingIdentity();
10461 serviceDoneExecutingLocked(r, inStopping);
10462 Binder.restoreCallingIdentity(origId);
10463 } else {
10464 Log.w(TAG, "Done executing unknown service " + r.name
10465 + " with token " + token);
10466 }
10467 }
10468 }
10469
10470 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10471 r.executeNesting--;
10472 if (r.executeNesting <= 0 && r.app != null) {
10473 r.app.executingServices.remove(r);
10474 if (r.app.executingServices.size() == 0) {
10475 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10476 }
10477 if (inStopping) {
10478 mStoppingServices.remove(r);
10479 }
10480 updateOomAdjLocked(r.app);
10481 }
10482 }
10483
10484 void serviceTimeout(ProcessRecord proc) {
10485 synchronized(this) {
10486 if (proc.executingServices.size() == 0 || proc.thread == null) {
10487 return;
10488 }
10489 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10490 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10491 ServiceRecord timeout = null;
10492 long nextTime = 0;
10493 while (it.hasNext()) {
10494 ServiceRecord sr = it.next();
10495 if (sr.executingStart < maxTime) {
10496 timeout = sr;
10497 break;
10498 }
10499 if (sr.executingStart > nextTime) {
10500 nextTime = sr.executingStart;
10501 }
10502 }
10503 if (timeout != null && mLRUProcesses.contains(proc)) {
10504 Log.w(TAG, "Timeout executing service: " + timeout);
10505 appNotRespondingLocked(proc, null, "Executing service "
10506 + timeout.name);
10507 } else {
10508 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10509 msg.obj = proc;
10510 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10511 }
10512 }
10513 }
10514
10515 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010516 // BACKUP AND RESTORE
10517 // =========================================================
10518
10519 // Cause the target app to be launched if necessary and its backup agent
10520 // instantiated. The backup agent will invoke backupAgentCreated() on the
10521 // activity manager to announce its creation.
10522 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10523 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10524 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10525
10526 synchronized(this) {
10527 // !!! TODO: currently no check here that we're already bound
10528 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10529 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10530 synchronized (stats) {
10531 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10532 }
10533
10534 BackupRecord r = new BackupRecord(ss, app, backupMode);
10535 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10536 // startProcessLocked() returns existing proc's record if it's already running
10537 ProcessRecord proc = startProcessLocked(app.processName, app,
10538 false, 0, "backup", hostingName);
10539 if (proc == null) {
10540 Log.e(TAG, "Unable to start backup agent process " + r);
10541 return false;
10542 }
10543
10544 r.app = proc;
10545 mBackupTarget = r;
10546 mBackupAppName = app.packageName;
10547
Christopher Tate6fa95972009-06-05 18:43:55 -070010548 // Try not to kill the process during backup
10549 updateOomAdjLocked(proc);
10550
Christopher Tate181fafa2009-05-14 11:12:14 -070010551 // If the process is already attached, schedule the creation of the backup agent now.
10552 // If it is not yet live, this will be done when it attaches to the framework.
10553 if (proc.thread != null) {
10554 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10555 try {
10556 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10557 } catch (RemoteException e) {
10558 // !!! TODO: notify the backup manager that we crashed, or rely on
10559 // death notices, or...?
10560 }
10561 } else {
10562 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10563 }
10564 // Invariants: at this point, the target app process exists and the application
10565 // is either already running or in the process of coming up. mBackupTarget and
10566 // mBackupAppName describe the app, so that when it binds back to the AM we
10567 // know that it's scheduled for a backup-agent operation.
10568 }
10569
10570 return true;
10571 }
10572
10573 // A backup agent has just come up
10574 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10575 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10576 + " = " + agent);
10577
10578 synchronized(this) {
10579 if (!agentPackageName.equals(mBackupAppName)) {
10580 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10581 return;
10582 }
10583
Christopher Tate043dadc2009-06-02 16:11:00 -070010584 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010585 try {
10586 IBackupManager bm = IBackupManager.Stub.asInterface(
10587 ServiceManager.getService(Context.BACKUP_SERVICE));
10588 bm.agentConnected(agentPackageName, agent);
10589 } catch (RemoteException e) {
10590 // can't happen; the backup manager service is local
10591 } catch (Exception e) {
10592 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10593 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010594 } finally {
10595 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010596 }
10597 }
10598 }
10599
10600 // done with this agent
10601 public void unbindBackupAgent(ApplicationInfo appInfo) {
10602 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010603 if (appInfo == null) {
10604 Log.w(TAG, "unbind backup agent for null app");
10605 return;
10606 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010607
10608 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010609 if (mBackupAppName == null) {
10610 Log.w(TAG, "Unbinding backup agent with no active backup");
10611 return;
10612 }
10613
Christopher Tate181fafa2009-05-14 11:12:14 -070010614 if (!mBackupAppName.equals(appInfo.packageName)) {
10615 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10616 return;
10617 }
10618
Christopher Tate6fa95972009-06-05 18:43:55 -070010619 ProcessRecord proc = mBackupTarget.app;
10620 mBackupTarget = null;
10621 mBackupAppName = null;
10622
10623 // Not backing this app up any more; reset its OOM adjustment
10624 updateOomAdjLocked(proc);
10625
Christopher Tatec7b31e32009-06-10 15:49:30 -070010626 // If the app crashed during backup, 'thread' will be null here
10627 if (proc.thread != null) {
10628 try {
10629 proc.thread.scheduleDestroyBackupAgent(appInfo);
10630 } catch (Exception e) {
10631 Log.e(TAG, "Exception when unbinding backup agent:");
10632 e.printStackTrace();
10633 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010634 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010635 }
10636 }
10637 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010638 // BROADCASTS
10639 // =========================================================
10640
10641 private final List getStickies(String action, IntentFilter filter,
10642 List cur) {
10643 final ContentResolver resolver = mContext.getContentResolver();
10644 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10645 if (list == null) {
10646 return cur;
10647 }
10648 int N = list.size();
10649 for (int i=0; i<N; i++) {
10650 Intent intent = list.get(i);
10651 if (filter.match(resolver, intent, true, TAG) >= 0) {
10652 if (cur == null) {
10653 cur = new ArrayList<Intent>();
10654 }
10655 cur.add(intent);
10656 }
10657 }
10658 return cur;
10659 }
10660
10661 private final void scheduleBroadcastsLocked() {
10662 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10663 + mBroadcastsScheduled);
10664
10665 if (mBroadcastsScheduled) {
10666 return;
10667 }
10668 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10669 mBroadcastsScheduled = true;
10670 }
10671
10672 public Intent registerReceiver(IApplicationThread caller,
10673 IIntentReceiver receiver, IntentFilter filter, String permission) {
10674 synchronized(this) {
10675 ProcessRecord callerApp = null;
10676 if (caller != null) {
10677 callerApp = getRecordForAppLocked(caller);
10678 if (callerApp == null) {
10679 throw new SecurityException(
10680 "Unable to find app for caller " + caller
10681 + " (pid=" + Binder.getCallingPid()
10682 + ") when registering receiver " + receiver);
10683 }
10684 }
10685
10686 List allSticky = null;
10687
10688 // Look for any matching sticky broadcasts...
10689 Iterator actions = filter.actionsIterator();
10690 if (actions != null) {
10691 while (actions.hasNext()) {
10692 String action = (String)actions.next();
10693 allSticky = getStickies(action, filter, allSticky);
10694 }
10695 } else {
10696 allSticky = getStickies(null, filter, allSticky);
10697 }
10698
10699 // The first sticky in the list is returned directly back to
10700 // the client.
10701 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10702
10703 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10704 + ": " + sticky);
10705
10706 if (receiver == null) {
10707 return sticky;
10708 }
10709
10710 ReceiverList rl
10711 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10712 if (rl == null) {
10713 rl = new ReceiverList(this, callerApp,
10714 Binder.getCallingPid(),
10715 Binder.getCallingUid(), receiver);
10716 if (rl.app != null) {
10717 rl.app.receivers.add(rl);
10718 } else {
10719 try {
10720 receiver.asBinder().linkToDeath(rl, 0);
10721 } catch (RemoteException e) {
10722 return sticky;
10723 }
10724 rl.linkedToDeath = true;
10725 }
10726 mRegisteredReceivers.put(receiver.asBinder(), rl);
10727 }
10728 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10729 rl.add(bf);
10730 if (!bf.debugCheck()) {
10731 Log.w(TAG, "==> For Dynamic broadast");
10732 }
10733 mReceiverResolver.addFilter(bf);
10734
10735 // Enqueue broadcasts for all existing stickies that match
10736 // this filter.
10737 if (allSticky != null) {
10738 ArrayList receivers = new ArrayList();
10739 receivers.add(bf);
10740
10741 int N = allSticky.size();
10742 for (int i=0; i<N; i++) {
10743 Intent intent = (Intent)allSticky.get(i);
10744 BroadcastRecord r = new BroadcastRecord(intent, null,
10745 null, -1, -1, null, receivers, null, 0, null, null,
10746 false);
10747 if (mParallelBroadcasts.size() == 0) {
10748 scheduleBroadcastsLocked();
10749 }
10750 mParallelBroadcasts.add(r);
10751 }
10752 }
10753
10754 return sticky;
10755 }
10756 }
10757
10758 public void unregisterReceiver(IIntentReceiver receiver) {
10759 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10760
10761 boolean doNext = false;
10762
10763 synchronized(this) {
10764 ReceiverList rl
10765 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10766 if (rl != null) {
10767 if (rl.curBroadcast != null) {
10768 BroadcastRecord r = rl.curBroadcast;
10769 doNext = finishReceiverLocked(
10770 receiver.asBinder(), r.resultCode, r.resultData,
10771 r.resultExtras, r.resultAbort, true);
10772 }
10773
10774 if (rl.app != null) {
10775 rl.app.receivers.remove(rl);
10776 }
10777 removeReceiverLocked(rl);
10778 if (rl.linkedToDeath) {
10779 rl.linkedToDeath = false;
10780 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10781 }
10782 }
10783 }
10784
10785 if (!doNext) {
10786 return;
10787 }
10788
10789 final long origId = Binder.clearCallingIdentity();
10790 processNextBroadcast(false);
10791 trimApplications();
10792 Binder.restoreCallingIdentity(origId);
10793 }
10794
10795 void removeReceiverLocked(ReceiverList rl) {
10796 mRegisteredReceivers.remove(rl.receiver.asBinder());
10797 int N = rl.size();
10798 for (int i=0; i<N; i++) {
10799 mReceiverResolver.removeFilter(rl.get(i));
10800 }
10801 }
10802
10803 private final int broadcastIntentLocked(ProcessRecord callerApp,
10804 String callerPackage, Intent intent, String resolvedType,
10805 IIntentReceiver resultTo, int resultCode, String resultData,
10806 Bundle map, String requiredPermission,
10807 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10808 intent = new Intent(intent);
10809
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010810 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010811 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10812 + " ordered=" + ordered);
10813 if ((resultTo != null) && !ordered) {
10814 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10815 }
10816
10817 // Handle special intents: if this broadcast is from the package
10818 // manager about a package being removed, we need to remove all of
10819 // its activities from the history stack.
10820 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10821 intent.getAction());
10822 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10823 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10824 || uidRemoved) {
10825 if (checkComponentPermission(
10826 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10827 callingPid, callingUid, -1)
10828 == PackageManager.PERMISSION_GRANTED) {
10829 if (uidRemoved) {
10830 final Bundle intentExtras = intent.getExtras();
10831 final int uid = intentExtras != null
10832 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10833 if (uid >= 0) {
10834 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10835 synchronized (bs) {
10836 bs.removeUidStatsLocked(uid);
10837 }
10838 }
10839 } else {
10840 Uri data = intent.getData();
10841 String ssp;
10842 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10843 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10844 uninstallPackageLocked(ssp,
10845 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010846 AttributeCache ac = AttributeCache.instance();
10847 if (ac != null) {
10848 ac.removePackage(ssp);
10849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010850 }
10851 }
10852 }
10853 } else {
10854 String msg = "Permission Denial: " + intent.getAction()
10855 + " broadcast from " + callerPackage + " (pid=" + callingPid
10856 + ", uid=" + callingUid + ")"
10857 + " requires "
10858 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10859 Log.w(TAG, msg);
10860 throw new SecurityException(msg);
10861 }
10862 }
10863
10864 /*
10865 * If this is the time zone changed action, queue up a message that will reset the timezone
10866 * of all currently running processes. This message will get queued up before the broadcast
10867 * happens.
10868 */
10869 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10870 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10871 }
10872
Dianne Hackborn854060af2009-07-09 18:14:31 -070010873 /*
10874 * Prevent non-system code (defined here to be non-persistent
10875 * processes) from sending protected broadcasts.
10876 */
10877 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10878 || callingUid == Process.SHELL_UID || callingUid == 0) {
10879 // Always okay.
10880 } else if (callerApp == null || !callerApp.persistent) {
10881 try {
10882 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10883 intent.getAction())) {
10884 String msg = "Permission Denial: not allowed to send broadcast "
10885 + intent.getAction() + " from pid="
10886 + callingPid + ", uid=" + callingUid;
10887 Log.w(TAG, msg);
10888 throw new SecurityException(msg);
10889 }
10890 } catch (RemoteException e) {
10891 Log.w(TAG, "Remote exception", e);
10892 return BROADCAST_SUCCESS;
10893 }
10894 }
10895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010896 // Add to the sticky list if requested.
10897 if (sticky) {
10898 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10899 callingPid, callingUid)
10900 != PackageManager.PERMISSION_GRANTED) {
10901 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10902 + callingPid + ", uid=" + callingUid
10903 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10904 Log.w(TAG, msg);
10905 throw new SecurityException(msg);
10906 }
10907 if (requiredPermission != null) {
10908 Log.w(TAG, "Can't broadcast sticky intent " + intent
10909 + " and enforce permission " + requiredPermission);
10910 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10911 }
10912 if (intent.getComponent() != null) {
10913 throw new SecurityException(
10914 "Sticky broadcasts can't target a specific component");
10915 }
10916 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10917 if (list == null) {
10918 list = new ArrayList<Intent>();
10919 mStickyBroadcasts.put(intent.getAction(), list);
10920 }
10921 int N = list.size();
10922 int i;
10923 for (i=0; i<N; i++) {
10924 if (intent.filterEquals(list.get(i))) {
10925 // This sticky already exists, replace it.
10926 list.set(i, new Intent(intent));
10927 break;
10928 }
10929 }
10930 if (i >= N) {
10931 list.add(new Intent(intent));
10932 }
10933 }
10934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010935 // Figure out who all will receive this broadcast.
10936 List receivers = null;
10937 List<BroadcastFilter> registeredReceivers = null;
10938 try {
10939 if (intent.getComponent() != null) {
10940 // Broadcast is going to one specific receiver class...
10941 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010942 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010943 if (ai != null) {
10944 receivers = new ArrayList();
10945 ResolveInfo ri = new ResolveInfo();
10946 ri.activityInfo = ai;
10947 receivers.add(ri);
10948 }
10949 } else {
10950 // Need to resolve the intent to interested receivers...
10951 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10952 == 0) {
10953 receivers =
10954 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010955 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010956 }
Mihai Preda074edef2009-05-18 17:13:31 +020010957 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010958 }
10959 } catch (RemoteException ex) {
10960 // pm is in same process, this will never happen.
10961 }
10962
10963 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10964 if (!ordered && NR > 0) {
10965 // If we are not serializing this broadcast, then send the
10966 // registered receivers separately so they don't wait for the
10967 // components to be launched.
10968 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10969 callerPackage, callingPid, callingUid, requiredPermission,
10970 registeredReceivers, resultTo, resultCode, resultData, map,
10971 ordered);
10972 if (DEBUG_BROADCAST) Log.v(
10973 TAG, "Enqueueing parallel broadcast " + r
10974 + ": prev had " + mParallelBroadcasts.size());
10975 mParallelBroadcasts.add(r);
10976 scheduleBroadcastsLocked();
10977 registeredReceivers = null;
10978 NR = 0;
10979 }
10980
10981 // Merge into one list.
10982 int ir = 0;
10983 if (receivers != null) {
10984 // A special case for PACKAGE_ADDED: do not allow the package
10985 // being added to see this broadcast. This prevents them from
10986 // using this as a back door to get run as soon as they are
10987 // installed. Maybe in the future we want to have a special install
10988 // broadcast or such for apps, but we'd like to deliberately make
10989 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010990 boolean skip = false;
10991 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010992 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010993 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10994 skip = true;
10995 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10996 skip = true;
10997 }
10998 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010999 ? intent.getData().getSchemeSpecificPart()
11000 : null;
11001 if (skipPackage != null && receivers != null) {
11002 int NT = receivers.size();
11003 for (int it=0; it<NT; it++) {
11004 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11005 if (curt.activityInfo.packageName.equals(skipPackage)) {
11006 receivers.remove(it);
11007 it--;
11008 NT--;
11009 }
11010 }
11011 }
11012
11013 int NT = receivers != null ? receivers.size() : 0;
11014 int it = 0;
11015 ResolveInfo curt = null;
11016 BroadcastFilter curr = null;
11017 while (it < NT && ir < NR) {
11018 if (curt == null) {
11019 curt = (ResolveInfo)receivers.get(it);
11020 }
11021 if (curr == null) {
11022 curr = registeredReceivers.get(ir);
11023 }
11024 if (curr.getPriority() >= curt.priority) {
11025 // Insert this broadcast record into the final list.
11026 receivers.add(it, curr);
11027 ir++;
11028 curr = null;
11029 it++;
11030 NT++;
11031 } else {
11032 // Skip to the next ResolveInfo in the final list.
11033 it++;
11034 curt = null;
11035 }
11036 }
11037 }
11038 while (ir < NR) {
11039 if (receivers == null) {
11040 receivers = new ArrayList();
11041 }
11042 receivers.add(registeredReceivers.get(ir));
11043 ir++;
11044 }
11045
11046 if ((receivers != null && receivers.size() > 0)
11047 || resultTo != null) {
11048 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11049 callerPackage, callingPid, callingUid, requiredPermission,
11050 receivers, resultTo, resultCode, resultData, map, ordered);
11051 if (DEBUG_BROADCAST) Log.v(
11052 TAG, "Enqueueing ordered broadcast " + r
11053 + ": prev had " + mOrderedBroadcasts.size());
11054 if (DEBUG_BROADCAST) {
11055 int seq = r.intent.getIntExtra("seq", -1);
11056 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11057 }
11058 mOrderedBroadcasts.add(r);
11059 scheduleBroadcastsLocked();
11060 }
11061
11062 return BROADCAST_SUCCESS;
11063 }
11064
11065 public final int broadcastIntent(IApplicationThread caller,
11066 Intent intent, String resolvedType, IIntentReceiver resultTo,
11067 int resultCode, String resultData, Bundle map,
11068 String requiredPermission, boolean serialized, boolean sticky) {
11069 // Refuse possible leaked file descriptors
11070 if (intent != null && intent.hasFileDescriptors() == true) {
11071 throw new IllegalArgumentException("File descriptors passed in Intent");
11072 }
11073
11074 synchronized(this) {
11075 if (!mSystemReady) {
11076 // if the caller really truly claims to know what they're doing, go
11077 // ahead and allow the broadcast without launching any receivers
11078 int flags = intent.getFlags();
11079 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11080 intent = new Intent(intent);
11081 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11082 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11083 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11084 + " before boot completion");
11085 throw new IllegalStateException("Cannot broadcast before boot completed");
11086 }
11087 }
11088
11089 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11090 final int callingPid = Binder.getCallingPid();
11091 final int callingUid = Binder.getCallingUid();
11092 final long origId = Binder.clearCallingIdentity();
11093 int res = broadcastIntentLocked(callerApp,
11094 callerApp != null ? callerApp.info.packageName : null,
11095 intent, resolvedType, resultTo,
11096 resultCode, resultData, map, requiredPermission, serialized,
11097 sticky, callingPid, callingUid);
11098 Binder.restoreCallingIdentity(origId);
11099 return res;
11100 }
11101 }
11102
11103 int broadcastIntentInPackage(String packageName, int uid,
11104 Intent intent, String resolvedType, IIntentReceiver resultTo,
11105 int resultCode, String resultData, Bundle map,
11106 String requiredPermission, boolean serialized, boolean sticky) {
11107 synchronized(this) {
11108 final long origId = Binder.clearCallingIdentity();
11109 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11110 resultTo, resultCode, resultData, map, requiredPermission,
11111 serialized, sticky, -1, uid);
11112 Binder.restoreCallingIdentity(origId);
11113 return res;
11114 }
11115 }
11116
11117 public final void unbroadcastIntent(IApplicationThread caller,
11118 Intent intent) {
11119 // Refuse possible leaked file descriptors
11120 if (intent != null && intent.hasFileDescriptors() == true) {
11121 throw new IllegalArgumentException("File descriptors passed in Intent");
11122 }
11123
11124 synchronized(this) {
11125 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11126 != PackageManager.PERMISSION_GRANTED) {
11127 String msg = "Permission Denial: unbroadcastIntent() from pid="
11128 + Binder.getCallingPid()
11129 + ", uid=" + Binder.getCallingUid()
11130 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11131 Log.w(TAG, msg);
11132 throw new SecurityException(msg);
11133 }
11134 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11135 if (list != null) {
11136 int N = list.size();
11137 int i;
11138 for (i=0; i<N; i++) {
11139 if (intent.filterEquals(list.get(i))) {
11140 list.remove(i);
11141 break;
11142 }
11143 }
11144 }
11145 }
11146 }
11147
11148 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11149 String resultData, Bundle resultExtras, boolean resultAbort,
11150 boolean explicit) {
11151 if (mOrderedBroadcasts.size() == 0) {
11152 if (explicit) {
11153 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11154 }
11155 return false;
11156 }
11157 BroadcastRecord r = mOrderedBroadcasts.get(0);
11158 if (r.receiver == null) {
11159 if (explicit) {
11160 Log.w(TAG, "finishReceiver called but none active");
11161 }
11162 return false;
11163 }
11164 if (r.receiver != receiver) {
11165 Log.w(TAG, "finishReceiver called but active receiver is different");
11166 return false;
11167 }
11168 int state = r.state;
11169 r.state = r.IDLE;
11170 if (state == r.IDLE) {
11171 if (explicit) {
11172 Log.w(TAG, "finishReceiver called but state is IDLE");
11173 }
11174 }
11175 r.receiver = null;
11176 r.intent.setComponent(null);
11177 if (r.curApp != null) {
11178 r.curApp.curReceiver = null;
11179 }
11180 if (r.curFilter != null) {
11181 r.curFilter.receiverList.curBroadcast = null;
11182 }
11183 r.curFilter = null;
11184 r.curApp = null;
11185 r.curComponent = null;
11186 r.curReceiver = null;
11187 mPendingBroadcast = null;
11188
11189 r.resultCode = resultCode;
11190 r.resultData = resultData;
11191 r.resultExtras = resultExtras;
11192 r.resultAbort = resultAbort;
11193
11194 // We will process the next receiver right now if this is finishing
11195 // an app receiver (which is always asynchronous) or after we have
11196 // come back from calling a receiver.
11197 return state == BroadcastRecord.APP_RECEIVE
11198 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11199 }
11200
11201 public void finishReceiver(IBinder who, int resultCode, String resultData,
11202 Bundle resultExtras, boolean resultAbort) {
11203 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11204
11205 // Refuse possible leaked file descriptors
11206 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11207 throw new IllegalArgumentException("File descriptors passed in Bundle");
11208 }
11209
11210 boolean doNext;
11211
11212 final long origId = Binder.clearCallingIdentity();
11213
11214 synchronized(this) {
11215 doNext = finishReceiverLocked(
11216 who, resultCode, resultData, resultExtras, resultAbort, true);
11217 }
11218
11219 if (doNext) {
11220 processNextBroadcast(false);
11221 }
11222 trimApplications();
11223
11224 Binder.restoreCallingIdentity(origId);
11225 }
11226
11227 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11228 if (r.nextReceiver > 0) {
11229 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11230 if (curReceiver instanceof BroadcastFilter) {
11231 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11232 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11233 System.identityHashCode(r),
11234 r.intent.getAction(),
11235 r.nextReceiver - 1,
11236 System.identityHashCode(bf));
11237 } else {
11238 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11239 System.identityHashCode(r),
11240 r.intent.getAction(),
11241 r.nextReceiver - 1,
11242 ((ResolveInfo)curReceiver).toString());
11243 }
11244 } else {
11245 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11246 + r);
11247 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11248 System.identityHashCode(r),
11249 r.intent.getAction(),
11250 r.nextReceiver,
11251 "NONE");
11252 }
11253 }
11254
11255 private final void broadcastTimeout() {
11256 synchronized (this) {
11257 if (mOrderedBroadcasts.size() == 0) {
11258 return;
11259 }
11260 long now = SystemClock.uptimeMillis();
11261 BroadcastRecord r = mOrderedBroadcasts.get(0);
11262 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11263 if (DEBUG_BROADCAST) Log.v(TAG,
11264 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11265 + (r.startTime + BROADCAST_TIMEOUT));
11266 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11267 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11268 return;
11269 }
11270
11271 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11272 r.startTime = now;
11273 r.anrCount++;
11274
11275 // Current receiver has passed its expiration date.
11276 if (r.nextReceiver <= 0) {
11277 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11278 return;
11279 }
11280
11281 ProcessRecord app = null;
11282
11283 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11284 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11285 logBroadcastReceiverDiscard(r);
11286 if (curReceiver instanceof BroadcastFilter) {
11287 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11288 if (bf.receiverList.pid != 0
11289 && bf.receiverList.pid != MY_PID) {
11290 synchronized (this.mPidsSelfLocked) {
11291 app = this.mPidsSelfLocked.get(
11292 bf.receiverList.pid);
11293 }
11294 }
11295 } else {
11296 app = r.curApp;
11297 }
11298
11299 if (app != null) {
11300 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11301 }
11302
11303 if (mPendingBroadcast == r) {
11304 mPendingBroadcast = null;
11305 }
11306
11307 // Move on to the next receiver.
11308 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11309 r.resultExtras, r.resultAbort, true);
11310 scheduleBroadcastsLocked();
11311 }
11312 }
11313
11314 private final void processCurBroadcastLocked(BroadcastRecord r,
11315 ProcessRecord app) throws RemoteException {
11316 if (app.thread == null) {
11317 throw new RemoteException();
11318 }
11319 r.receiver = app.thread.asBinder();
11320 r.curApp = app;
11321 app.curReceiver = r;
11322 updateLRUListLocked(app, true);
11323
11324 // Tell the application to launch this receiver.
11325 r.intent.setComponent(r.curComponent);
11326
11327 boolean started = false;
11328 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011329 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011330 "Delivering to component " + r.curComponent
11331 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011332 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011333 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11334 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11335 started = true;
11336 } finally {
11337 if (!started) {
11338 r.receiver = null;
11339 r.curApp = null;
11340 app.curReceiver = null;
11341 }
11342 }
11343
11344 }
11345
11346 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11347 Intent intent, int resultCode, String data,
11348 Bundle extras, boolean ordered) throws RemoteException {
11349 if (app != null && app.thread != null) {
11350 // If we have an app thread, do the call through that so it is
11351 // correctly ordered with other one-way calls.
11352 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11353 data, extras, ordered);
11354 } else {
11355 receiver.performReceive(intent, resultCode, data, extras, ordered);
11356 }
11357 }
11358
11359 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11360 BroadcastFilter filter, boolean ordered) {
11361 boolean skip = false;
11362 if (filter.requiredPermission != null) {
11363 int perm = checkComponentPermission(filter.requiredPermission,
11364 r.callingPid, r.callingUid, -1);
11365 if (perm != PackageManager.PERMISSION_GRANTED) {
11366 Log.w(TAG, "Permission Denial: broadcasting "
11367 + r.intent.toString()
11368 + " from " + r.callerPackage + " (pid="
11369 + r.callingPid + ", uid=" + r.callingUid + ")"
11370 + " requires " + filter.requiredPermission
11371 + " due to registered receiver " + filter);
11372 skip = true;
11373 }
11374 }
11375 if (r.requiredPermission != null) {
11376 int perm = checkComponentPermission(r.requiredPermission,
11377 filter.receiverList.pid, filter.receiverList.uid, -1);
11378 if (perm != PackageManager.PERMISSION_GRANTED) {
11379 Log.w(TAG, "Permission Denial: receiving "
11380 + r.intent.toString()
11381 + " to " + filter.receiverList.app
11382 + " (pid=" + filter.receiverList.pid
11383 + ", uid=" + filter.receiverList.uid + ")"
11384 + " requires " + r.requiredPermission
11385 + " due to sender " + r.callerPackage
11386 + " (uid " + r.callingUid + ")");
11387 skip = true;
11388 }
11389 }
11390
11391 if (!skip) {
11392 // If this is not being sent as an ordered broadcast, then we
11393 // don't want to touch the fields that keep track of the current
11394 // state of ordered broadcasts.
11395 if (ordered) {
11396 r.receiver = filter.receiverList.receiver.asBinder();
11397 r.curFilter = filter;
11398 filter.receiverList.curBroadcast = r;
11399 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011400 if (filter.receiverList.app != null) {
11401 // Bump hosting application to no longer be in background
11402 // scheduling class. Note that we can't do that if there
11403 // isn't an app... but we can only be in that case for
11404 // things that directly call the IActivityManager API, which
11405 // are already core system stuff so don't matter for this.
11406 r.curApp = filter.receiverList.app;
11407 filter.receiverList.app.curReceiver = r;
11408 updateOomAdjLocked();
11409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011410 }
11411 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011412 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011413 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011414 Log.i(TAG, "Delivering to " + filter.receiverList.app
11415 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011416 }
11417 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11418 new Intent(r.intent), r.resultCode,
11419 r.resultData, r.resultExtras, r.ordered);
11420 if (ordered) {
11421 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11422 }
11423 } catch (RemoteException e) {
11424 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11425 if (ordered) {
11426 r.receiver = null;
11427 r.curFilter = null;
11428 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011429 if (filter.receiverList.app != null) {
11430 filter.receiverList.app.curReceiver = null;
11431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011432 }
11433 }
11434 }
11435 }
11436
11437 private final void processNextBroadcast(boolean fromMsg) {
11438 synchronized(this) {
11439 BroadcastRecord r;
11440
11441 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11442 + mParallelBroadcasts.size() + " broadcasts, "
11443 + mOrderedBroadcasts.size() + " serialized broadcasts");
11444
11445 updateCpuStats();
11446
11447 if (fromMsg) {
11448 mBroadcastsScheduled = false;
11449 }
11450
11451 // First, deliver any non-serialized broadcasts right away.
11452 while (mParallelBroadcasts.size() > 0) {
11453 r = mParallelBroadcasts.remove(0);
11454 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011455 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11456 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011457 for (int i=0; i<N; i++) {
11458 Object target = r.receivers.get(i);
11459 if (DEBUG_BROADCAST) Log.v(TAG,
11460 "Delivering non-serialized to registered "
11461 + target + ": " + r);
11462 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11463 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011464 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11465 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011466 }
11467
11468 // Now take care of the next serialized one...
11469
11470 // If we are waiting for a process to come up to handle the next
11471 // broadcast, then do nothing at this point. Just in case, we
11472 // check that the process we're waiting for still exists.
11473 if (mPendingBroadcast != null) {
11474 Log.i(TAG, "processNextBroadcast: waiting for "
11475 + mPendingBroadcast.curApp);
11476
11477 boolean isDead;
11478 synchronized (mPidsSelfLocked) {
11479 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11480 }
11481 if (!isDead) {
11482 // It's still alive, so keep waiting
11483 return;
11484 } else {
11485 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11486 + " died before responding to broadcast");
11487 mPendingBroadcast = null;
11488 }
11489 }
11490
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011491 boolean looped = false;
11492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011493 do {
11494 if (mOrderedBroadcasts.size() == 0) {
11495 // No more broadcasts pending, so all done!
11496 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011497 if (looped) {
11498 // If we had finished the last ordered broadcast, then
11499 // make sure all processes have correct oom and sched
11500 // adjustments.
11501 updateOomAdjLocked();
11502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011503 return;
11504 }
11505 r = mOrderedBroadcasts.get(0);
11506 boolean forceReceive = false;
11507
11508 // Ensure that even if something goes awry with the timeout
11509 // detection, we catch "hung" broadcasts here, discard them,
11510 // and continue to make progress.
11511 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11512 long now = SystemClock.uptimeMillis();
11513 if (r.dispatchTime > 0) {
11514 if ((numReceivers > 0) &&
11515 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11516 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11517 + " now=" + now
11518 + " dispatchTime=" + r.dispatchTime
11519 + " startTime=" + r.startTime
11520 + " intent=" + r.intent
11521 + " numReceivers=" + numReceivers
11522 + " nextReceiver=" + r.nextReceiver
11523 + " state=" + r.state);
11524 broadcastTimeout(); // forcibly finish this broadcast
11525 forceReceive = true;
11526 r.state = BroadcastRecord.IDLE;
11527 }
11528 }
11529
11530 if (r.state != BroadcastRecord.IDLE) {
11531 if (DEBUG_BROADCAST) Log.d(TAG,
11532 "processNextBroadcast() called when not idle (state="
11533 + r.state + ")");
11534 return;
11535 }
11536
11537 if (r.receivers == null || r.nextReceiver >= numReceivers
11538 || r.resultAbort || forceReceive) {
11539 // No more receivers for this broadcast! Send the final
11540 // result if requested...
11541 if (r.resultTo != null) {
11542 try {
11543 if (DEBUG_BROADCAST) {
11544 int seq = r.intent.getIntExtra("seq", -1);
11545 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11546 + " seq=" + seq + " app=" + r.callerApp);
11547 }
11548 performReceive(r.callerApp, r.resultTo,
11549 new Intent(r.intent), r.resultCode,
11550 r.resultData, r.resultExtras, false);
11551 } catch (RemoteException e) {
11552 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11553 }
11554 }
11555
11556 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11557 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11558
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011559 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11560 + r);
11561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011562 // ... and on to the next...
11563 mOrderedBroadcasts.remove(0);
11564 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011565 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011566 continue;
11567 }
11568 } while (r == null);
11569
11570 // Get the next receiver...
11571 int recIdx = r.nextReceiver++;
11572
11573 // Keep track of when this receiver started, and make sure there
11574 // is a timeout message pending to kill it if need be.
11575 r.startTime = SystemClock.uptimeMillis();
11576 if (recIdx == 0) {
11577 r.dispatchTime = r.startTime;
11578
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011579 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11580 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011581 if (DEBUG_BROADCAST) Log.v(TAG,
11582 "Submitting BROADCAST_TIMEOUT_MSG for "
11583 + (r.startTime + BROADCAST_TIMEOUT));
11584 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11585 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11586 }
11587
11588 Object nextReceiver = r.receivers.get(recIdx);
11589 if (nextReceiver instanceof BroadcastFilter) {
11590 // Simple case: this is a registered receiver who gets
11591 // a direct call.
11592 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11593 if (DEBUG_BROADCAST) Log.v(TAG,
11594 "Delivering serialized to registered "
11595 + filter + ": " + r);
11596 deliverToRegisteredReceiver(r, filter, r.ordered);
11597 if (r.receiver == null || !r.ordered) {
11598 // The receiver has already finished, so schedule to
11599 // process the next one.
11600 r.state = BroadcastRecord.IDLE;
11601 scheduleBroadcastsLocked();
11602 }
11603 return;
11604 }
11605
11606 // Hard case: need to instantiate the receiver, possibly
11607 // starting its application process to host it.
11608
11609 ResolveInfo info =
11610 (ResolveInfo)nextReceiver;
11611
11612 boolean skip = false;
11613 int perm = checkComponentPermission(info.activityInfo.permission,
11614 r.callingPid, r.callingUid,
11615 info.activityInfo.exported
11616 ? -1 : info.activityInfo.applicationInfo.uid);
11617 if (perm != PackageManager.PERMISSION_GRANTED) {
11618 Log.w(TAG, "Permission Denial: broadcasting "
11619 + r.intent.toString()
11620 + " from " + r.callerPackage + " (pid=" + r.callingPid
11621 + ", uid=" + r.callingUid + ")"
11622 + " requires " + info.activityInfo.permission
11623 + " due to receiver " + info.activityInfo.packageName
11624 + "/" + info.activityInfo.name);
11625 skip = true;
11626 }
11627 if (r.callingUid != Process.SYSTEM_UID &&
11628 r.requiredPermission != null) {
11629 try {
11630 perm = ActivityThread.getPackageManager().
11631 checkPermission(r.requiredPermission,
11632 info.activityInfo.applicationInfo.packageName);
11633 } catch (RemoteException e) {
11634 perm = PackageManager.PERMISSION_DENIED;
11635 }
11636 if (perm != PackageManager.PERMISSION_GRANTED) {
11637 Log.w(TAG, "Permission Denial: receiving "
11638 + r.intent + " to "
11639 + info.activityInfo.applicationInfo.packageName
11640 + " requires " + r.requiredPermission
11641 + " due to sender " + r.callerPackage
11642 + " (uid " + r.callingUid + ")");
11643 skip = true;
11644 }
11645 }
11646 if (r.curApp != null && r.curApp.crashing) {
11647 // If the target process is crashing, just skip it.
11648 skip = true;
11649 }
11650
11651 if (skip) {
11652 r.receiver = null;
11653 r.curFilter = null;
11654 r.state = BroadcastRecord.IDLE;
11655 scheduleBroadcastsLocked();
11656 return;
11657 }
11658
11659 r.state = BroadcastRecord.APP_RECEIVE;
11660 String targetProcess = info.activityInfo.processName;
11661 r.curComponent = new ComponentName(
11662 info.activityInfo.applicationInfo.packageName,
11663 info.activityInfo.name);
11664 r.curReceiver = info.activityInfo;
11665
11666 // Is this receiver's application already running?
11667 ProcessRecord app = getProcessRecordLocked(targetProcess,
11668 info.activityInfo.applicationInfo.uid);
11669 if (app != null && app.thread != null) {
11670 try {
11671 processCurBroadcastLocked(r, app);
11672 return;
11673 } catch (RemoteException e) {
11674 Log.w(TAG, "Exception when sending broadcast to "
11675 + r.curComponent, e);
11676 }
11677
11678 // If a dead object exception was thrown -- fall through to
11679 // restart the application.
11680 }
11681
11682 // Not running -- get it started, and enqueue this history record
11683 // to be executed when the app comes up.
11684 if ((r.curApp=startProcessLocked(targetProcess,
11685 info.activityInfo.applicationInfo, true,
11686 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11687 "broadcast", r.curComponent)) == null) {
11688 // Ah, this recipient is unavailable. Finish it if necessary,
11689 // and mark the broadcast record as ready for the next.
11690 Log.w(TAG, "Unable to launch app "
11691 + info.activityInfo.applicationInfo.packageName + "/"
11692 + info.activityInfo.applicationInfo.uid + " for broadcast "
11693 + r.intent + ": process is bad");
11694 logBroadcastReceiverDiscard(r);
11695 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11696 r.resultExtras, r.resultAbort, true);
11697 scheduleBroadcastsLocked();
11698 r.state = BroadcastRecord.IDLE;
11699 return;
11700 }
11701
11702 mPendingBroadcast = r;
11703 }
11704 }
11705
11706 // =========================================================
11707 // INSTRUMENTATION
11708 // =========================================================
11709
11710 public boolean startInstrumentation(ComponentName className,
11711 String profileFile, int flags, Bundle arguments,
11712 IInstrumentationWatcher watcher) {
11713 // Refuse possible leaked file descriptors
11714 if (arguments != null && arguments.hasFileDescriptors()) {
11715 throw new IllegalArgumentException("File descriptors passed in Bundle");
11716 }
11717
11718 synchronized(this) {
11719 InstrumentationInfo ii = null;
11720 ApplicationInfo ai = null;
11721 try {
11722 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011723 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011724 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011725 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011726 } catch (PackageManager.NameNotFoundException e) {
11727 }
11728 if (ii == null) {
11729 reportStartInstrumentationFailure(watcher, className,
11730 "Unable to find instrumentation info for: " + className);
11731 return false;
11732 }
11733 if (ai == null) {
11734 reportStartInstrumentationFailure(watcher, className,
11735 "Unable to find instrumentation target package: " + ii.targetPackage);
11736 return false;
11737 }
11738
11739 int match = mContext.getPackageManager().checkSignatures(
11740 ii.targetPackage, ii.packageName);
11741 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11742 String msg = "Permission Denial: starting instrumentation "
11743 + className + " from pid="
11744 + Binder.getCallingPid()
11745 + ", uid=" + Binder.getCallingPid()
11746 + " not allowed because package " + ii.packageName
11747 + " does not have a signature matching the target "
11748 + ii.targetPackage;
11749 reportStartInstrumentationFailure(watcher, className, msg);
11750 throw new SecurityException(msg);
11751 }
11752
11753 final long origId = Binder.clearCallingIdentity();
11754 uninstallPackageLocked(ii.targetPackage, -1, true);
11755 ProcessRecord app = addAppLocked(ai);
11756 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011757 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011758 app.instrumentationProfileFile = profileFile;
11759 app.instrumentationArguments = arguments;
11760 app.instrumentationWatcher = watcher;
11761 app.instrumentationResultClass = className;
11762 Binder.restoreCallingIdentity(origId);
11763 }
11764
11765 return true;
11766 }
11767
11768 /**
11769 * Report errors that occur while attempting to start Instrumentation. Always writes the
11770 * error to the logs, but if somebody is watching, send the report there too. This enables
11771 * the "am" command to report errors with more information.
11772 *
11773 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11774 * @param cn The component name of the instrumentation.
11775 * @param report The error report.
11776 */
11777 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11778 ComponentName cn, String report) {
11779 Log.w(TAG, report);
11780 try {
11781 if (watcher != null) {
11782 Bundle results = new Bundle();
11783 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11784 results.putString("Error", report);
11785 watcher.instrumentationStatus(cn, -1, results);
11786 }
11787 } catch (RemoteException e) {
11788 Log.w(TAG, e);
11789 }
11790 }
11791
11792 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11793 if (app.instrumentationWatcher != null) {
11794 try {
11795 // NOTE: IInstrumentationWatcher *must* be oneway here
11796 app.instrumentationWatcher.instrumentationFinished(
11797 app.instrumentationClass,
11798 resultCode,
11799 results);
11800 } catch (RemoteException e) {
11801 }
11802 }
11803 app.instrumentationWatcher = null;
11804 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011805 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011806 app.instrumentationProfileFile = null;
11807 app.instrumentationArguments = null;
11808
11809 uninstallPackageLocked(app.processName, -1, false);
11810 }
11811
11812 public void finishInstrumentation(IApplicationThread target,
11813 int resultCode, Bundle results) {
11814 // Refuse possible leaked file descriptors
11815 if (results != null && results.hasFileDescriptors()) {
11816 throw new IllegalArgumentException("File descriptors passed in Intent");
11817 }
11818
11819 synchronized(this) {
11820 ProcessRecord app = getRecordForAppLocked(target);
11821 if (app == null) {
11822 Log.w(TAG, "finishInstrumentation: no app for " + target);
11823 return;
11824 }
11825 final long origId = Binder.clearCallingIdentity();
11826 finishInstrumentationLocked(app, resultCode, results);
11827 Binder.restoreCallingIdentity(origId);
11828 }
11829 }
11830
11831 // =========================================================
11832 // CONFIGURATION
11833 // =========================================================
11834
11835 public ConfigurationInfo getDeviceConfigurationInfo() {
11836 ConfigurationInfo config = new ConfigurationInfo();
11837 synchronized (this) {
11838 config.reqTouchScreen = mConfiguration.touchscreen;
11839 config.reqKeyboardType = mConfiguration.keyboard;
11840 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011841 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11842 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011843 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11844 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011845 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11846 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011847 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11848 }
11849 }
11850 return config;
11851 }
11852
11853 public Configuration getConfiguration() {
11854 Configuration ci;
11855 synchronized(this) {
11856 ci = new Configuration(mConfiguration);
11857 }
11858 return ci;
11859 }
11860
11861 public void updateConfiguration(Configuration values) {
11862 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11863 "updateConfiguration()");
11864
11865 synchronized(this) {
11866 if (values == null && mWindowManager != null) {
11867 // sentinel: fetch the current configuration from the window manager
11868 values = mWindowManager.computeNewConfiguration();
11869 }
11870
11871 final long origId = Binder.clearCallingIdentity();
11872 updateConfigurationLocked(values, null);
11873 Binder.restoreCallingIdentity(origId);
11874 }
11875 }
11876
11877 /**
11878 * Do either or both things: (1) change the current configuration, and (2)
11879 * make sure the given activity is running with the (now) current
11880 * configuration. Returns true if the activity has been left running, or
11881 * false if <var>starting</var> is being destroyed to match the new
11882 * configuration.
11883 */
11884 public boolean updateConfigurationLocked(Configuration values,
11885 HistoryRecord starting) {
11886 int changes = 0;
11887
11888 boolean kept = true;
11889
11890 if (values != null) {
11891 Configuration newConfig = new Configuration(mConfiguration);
11892 changes = newConfig.updateFrom(values);
11893 if (changes != 0) {
11894 if (DEBUG_SWITCH) {
11895 Log.i(TAG, "Updating configuration to: " + values);
11896 }
11897
11898 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11899
11900 if (values.locale != null) {
11901 saveLocaleLocked(values.locale,
11902 !values.locale.equals(mConfiguration.locale),
11903 values.userSetLocale);
11904 }
11905
11906 mConfiguration = newConfig;
11907
11908 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11909 msg.obj = new Configuration(mConfiguration);
11910 mHandler.sendMessage(msg);
11911
11912 final int N = mLRUProcesses.size();
11913 for (int i=0; i<N; i++) {
11914 ProcessRecord app = mLRUProcesses.get(i);
11915 try {
11916 if (app.thread != null) {
11917 app.thread.scheduleConfigurationChanged(mConfiguration);
11918 }
11919 } catch (Exception e) {
11920 }
11921 }
11922 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11923 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11924 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011925
11926 AttributeCache ac = AttributeCache.instance();
11927 if (ac != null) {
11928 ac.updateConfiguration(mConfiguration);
11929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011930 }
11931 }
11932
11933 if (changes != 0 && starting == null) {
11934 // If the configuration changed, and the caller is not already
11935 // in the process of starting an activity, then find the top
11936 // activity to check if its configuration needs to change.
11937 starting = topRunningActivityLocked(null);
11938 }
11939
11940 if (starting != null) {
11941 kept = ensureActivityConfigurationLocked(starting, changes);
11942 if (kept) {
11943 // If this didn't result in the starting activity being
11944 // destroyed, then we need to make sure at this point that all
11945 // other activities are made visible.
11946 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11947 + ", ensuring others are correct.");
11948 ensureActivitiesVisibleLocked(starting, changes);
11949 }
11950 }
11951
11952 return kept;
11953 }
11954
11955 private final boolean relaunchActivityLocked(HistoryRecord r,
11956 int changes, boolean andResume) {
11957 List<ResultInfo> results = null;
11958 List<Intent> newIntents = null;
11959 if (andResume) {
11960 results = r.results;
11961 newIntents = r.newIntents;
11962 }
11963 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11964 + " with results=" + results + " newIntents=" + newIntents
11965 + " andResume=" + andResume);
11966 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11967 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11968 r.task.taskId, r.shortComponentName);
11969
11970 r.startFreezingScreenLocked(r.app, 0);
11971
11972 try {
11973 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11974 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11975 changes, !andResume);
11976 // Note: don't need to call pauseIfSleepingLocked() here, because
11977 // the caller will only pass in 'andResume' if this activity is
11978 // currently resumed, which implies we aren't sleeping.
11979 } catch (RemoteException e) {
11980 return false;
11981 }
11982
11983 if (andResume) {
11984 r.results = null;
11985 r.newIntents = null;
11986 }
11987
11988 return true;
11989 }
11990
11991 /**
11992 * Make sure the given activity matches the current configuration. Returns
11993 * false if the activity had to be destroyed. Returns true if the
11994 * configuration is the same, or the activity will remain running as-is
11995 * for whatever reason. Ensures the HistoryRecord is updated with the
11996 * correct configuration and all other bookkeeping is handled.
11997 */
11998 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11999 int globalChanges) {
12000 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12001
12002 // Short circuit: if the two configurations are the exact same
12003 // object (the common case), then there is nothing to do.
12004 Configuration newConfig = mConfiguration;
12005 if (r.configuration == newConfig) {
12006 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12007 return true;
12008 }
12009
12010 // We don't worry about activities that are finishing.
12011 if (r.finishing) {
12012 if (DEBUG_SWITCH) Log.i(TAG,
12013 "Configuration doesn't matter in finishing " + r);
12014 r.stopFreezingScreenLocked(false);
12015 return true;
12016 }
12017
12018 // Okay we now are going to make this activity have the new config.
12019 // But then we need to figure out how it needs to deal with that.
12020 Configuration oldConfig = r.configuration;
12021 r.configuration = newConfig;
12022
12023 // If the activity isn't currently running, just leave the new
12024 // configuration and it will pick that up next time it starts.
12025 if (r.app == null || r.app.thread == null) {
12026 if (DEBUG_SWITCH) Log.i(TAG,
12027 "Configuration doesn't matter not running " + r);
12028 r.stopFreezingScreenLocked(false);
12029 return true;
12030 }
12031
12032 // If the activity isn't persistent, there is a chance we will
12033 // need to restart it.
12034 if (!r.persistent) {
12035
12036 // Figure out what has changed between the two configurations.
12037 int changes = oldConfig.diff(newConfig);
12038 if (DEBUG_SWITCH) {
12039 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12040 + Integer.toHexString(changes) + ", handles=0x"
12041 + Integer.toHexString(r.info.configChanges));
12042 }
12043 if ((changes&(~r.info.configChanges)) != 0) {
12044 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12045 r.configChangeFlags |= changes;
12046 r.startFreezingScreenLocked(r.app, globalChanges);
12047 if (r.app == null || r.app.thread == null) {
12048 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12049 destroyActivityLocked(r, true);
12050 } else if (r.state == ActivityState.PAUSING) {
12051 // A little annoying: we are waiting for this activity to
12052 // finish pausing. Let's not do anything now, but just
12053 // flag that it needs to be restarted when done pausing.
12054 r.configDestroy = true;
12055 return true;
12056 } else if (r.state == ActivityState.RESUMED) {
12057 // Try to optimize this case: the configuration is changing
12058 // and we need to restart the top, resumed activity.
12059 // Instead of doing the normal handshaking, just say
12060 // "restart!".
12061 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12062 relaunchActivityLocked(r, r.configChangeFlags, true);
12063 r.configChangeFlags = 0;
12064 } else {
12065 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12066 relaunchActivityLocked(r, r.configChangeFlags, false);
12067 r.configChangeFlags = 0;
12068 }
12069
12070 // All done... tell the caller we weren't able to keep this
12071 // activity around.
12072 return false;
12073 }
12074 }
12075
12076 // Default case: the activity can handle this new configuration, so
12077 // hand it over. Note that we don't need to give it the new
12078 // configuration, since we always send configuration changes to all
12079 // process when they happen so it can just use whatever configuration
12080 // it last got.
12081 if (r.app != null && r.app.thread != null) {
12082 try {
12083 r.app.thread.scheduleActivityConfigurationChanged(r);
12084 } catch (RemoteException e) {
12085 // If process died, whatever.
12086 }
12087 }
12088 r.stopFreezingScreenLocked(false);
12089
12090 return true;
12091 }
12092
12093 /**
12094 * Save the locale. You must be inside a synchronized (this) block.
12095 */
12096 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12097 if(isDiff) {
12098 SystemProperties.set("user.language", l.getLanguage());
12099 SystemProperties.set("user.region", l.getCountry());
12100 }
12101
12102 if(isPersist) {
12103 SystemProperties.set("persist.sys.language", l.getLanguage());
12104 SystemProperties.set("persist.sys.country", l.getCountry());
12105 SystemProperties.set("persist.sys.localevar", l.getVariant());
12106 }
12107 }
12108
12109 // =========================================================
12110 // LIFETIME MANAGEMENT
12111 // =========================================================
12112
12113 private final int computeOomAdjLocked(
12114 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12115 if (mAdjSeq == app.adjSeq) {
12116 // This adjustment has already been computed.
12117 return app.curAdj;
12118 }
12119
12120 if (app.thread == null) {
12121 app.adjSeq = mAdjSeq;
12122 return (app.curAdj=EMPTY_APP_ADJ);
12123 }
12124
12125 app.isForeground = false;
12126
The Android Open Source Project4df24232009-03-05 14:34:35 -080012127 // Determine the importance of the process, starting with most
12128 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012129 int adj;
12130 int N;
12131 if (app == TOP_APP || app.instrumentationClass != null
12132 || app.persistentActivities > 0) {
12133 // The last app on the list is the foreground app.
12134 adj = FOREGROUND_APP_ADJ;
12135 app.isForeground = true;
12136 } else if (app.curReceiver != null ||
12137 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12138 // An app that is currently receiving a broadcast also
12139 // counts as being in the foreground.
12140 adj = FOREGROUND_APP_ADJ;
12141 } else if (app.executingServices.size() > 0) {
12142 // An app that is currently executing a service callback also
12143 // counts as being in the foreground.
12144 adj = FOREGROUND_APP_ADJ;
12145 } else if (app.foregroundServices || app.forcingToForeground != null) {
12146 // The user is aware of this app, so make it visible.
12147 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012148 } else if (app == mHomeProcess) {
12149 // This process is hosting what we currently consider to be the
12150 // home app, so we don't want to let it go into the background.
12151 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012152 } else if ((N=app.activities.size()) != 0) {
12153 // This app is in the background with paused activities.
12154 adj = hiddenAdj;
12155 for (int j=0; j<N; j++) {
12156 if (((HistoryRecord)app.activities.get(j)).visible) {
12157 // This app has a visible activity!
12158 adj = VISIBLE_APP_ADJ;
12159 break;
12160 }
12161 }
12162 } else {
12163 // A very not-needed process.
12164 adj = EMPTY_APP_ADJ;
12165 }
12166
The Android Open Source Project4df24232009-03-05 14:34:35 -080012167 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012168 // there are applications dependent on our services or providers, but
12169 // this gives us a baseline and makes sure we don't get into an
12170 // infinite recursion.
12171 app.adjSeq = mAdjSeq;
12172 app.curRawAdj = adj;
12173 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12174
Christopher Tate6fa95972009-06-05 18:43:55 -070012175 if (mBackupTarget != null && app == mBackupTarget.app) {
12176 // If possible we want to avoid killing apps while they're being backed up
12177 if (adj > BACKUP_APP_ADJ) {
12178 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12179 adj = BACKUP_APP_ADJ;
12180 }
12181 }
12182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012183 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12184 // If this process has active services running in it, we would
12185 // like to avoid killing it unless it would prevent the current
12186 // application from running.
12187 if (adj > hiddenAdj) {
12188 adj = hiddenAdj;
12189 }
12190 final long now = SystemClock.uptimeMillis();
12191 // This process is more important if the top activity is
12192 // bound to the service.
12193 Iterator jt = app.services.iterator();
12194 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12195 ServiceRecord s = (ServiceRecord)jt.next();
12196 if (s.startRequested) {
12197 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12198 // This service has seen some activity within
12199 // recent memory, so we will keep its process ahead
12200 // of the background processes.
12201 if (adj > SECONDARY_SERVER_ADJ) {
12202 adj = SECONDARY_SERVER_ADJ;
12203 }
12204 } else {
12205 // This service has been inactive for too long, just
12206 // put it with the rest of the background processes.
12207 if (adj > hiddenAdj) {
12208 adj = hiddenAdj;
12209 }
12210 }
12211 }
12212 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12213 Iterator<ConnectionRecord> kt
12214 = s.connections.values().iterator();
12215 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12216 // XXX should compute this based on the max of
12217 // all connected clients.
12218 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012219 if (cr.binding.client == app) {
12220 // Binding to ourself is not interesting.
12221 continue;
12222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012223 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12224 ProcessRecord client = cr.binding.client;
12225 int myHiddenAdj = hiddenAdj;
12226 if (myHiddenAdj > client.hiddenAdj) {
12227 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12228 myHiddenAdj = client.hiddenAdj;
12229 } else {
12230 myHiddenAdj = VISIBLE_APP_ADJ;
12231 }
12232 }
12233 int clientAdj = computeOomAdjLocked(
12234 client, myHiddenAdj, TOP_APP);
12235 if (adj > clientAdj) {
12236 adj = clientAdj > VISIBLE_APP_ADJ
12237 ? clientAdj : VISIBLE_APP_ADJ;
12238 }
12239 }
12240 HistoryRecord a = cr.activity;
12241 //if (a != null) {
12242 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12243 //}
12244 if (a != null && adj > FOREGROUND_APP_ADJ &&
12245 (a.state == ActivityState.RESUMED
12246 || a.state == ActivityState.PAUSING)) {
12247 adj = FOREGROUND_APP_ADJ;
12248 }
12249 }
12250 }
12251 }
12252 }
12253
12254 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12255 // If this process has published any content providers, then
12256 // its adjustment makes it at least as important as any of the
12257 // processes using those providers, and no less important than
12258 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12259 if (adj > CONTENT_PROVIDER_ADJ) {
12260 adj = CONTENT_PROVIDER_ADJ;
12261 }
12262 Iterator jt = app.pubProviders.values().iterator();
12263 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12264 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12265 if (cpr.clients.size() != 0) {
12266 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12267 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12268 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012269 if (client == app) {
12270 // Being our own client is not interesting.
12271 continue;
12272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012273 int myHiddenAdj = hiddenAdj;
12274 if (myHiddenAdj > client.hiddenAdj) {
12275 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12276 myHiddenAdj = client.hiddenAdj;
12277 } else {
12278 myHiddenAdj = FOREGROUND_APP_ADJ;
12279 }
12280 }
12281 int clientAdj = computeOomAdjLocked(
12282 client, myHiddenAdj, TOP_APP);
12283 if (adj > clientAdj) {
12284 adj = clientAdj > FOREGROUND_APP_ADJ
12285 ? clientAdj : FOREGROUND_APP_ADJ;
12286 }
12287 }
12288 }
12289 // If the provider has external (non-framework) process
12290 // dependencies, ensure that its adjustment is at least
12291 // FOREGROUND_APP_ADJ.
12292 if (cpr.externals != 0) {
12293 if (adj > FOREGROUND_APP_ADJ) {
12294 adj = FOREGROUND_APP_ADJ;
12295 }
12296 }
12297 }
12298 }
12299
12300 app.curRawAdj = adj;
12301
12302 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12303 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12304 if (adj > app.maxAdj) {
12305 adj = app.maxAdj;
12306 }
12307
12308 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012309 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12310 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12311 : Process.THREAD_GROUP_DEFAULT;
12312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012313 return adj;
12314 }
12315
12316 /**
12317 * Ask a given process to GC right now.
12318 */
12319 final void performAppGcLocked(ProcessRecord app) {
12320 try {
12321 app.lastRequestedGc = SystemClock.uptimeMillis();
12322 if (app.thread != null) {
12323 app.thread.processInBackground();
12324 }
12325 } catch (Exception e) {
12326 // whatever.
12327 }
12328 }
12329
12330 /**
12331 * Returns true if things are idle enough to perform GCs.
12332 */
12333 private final boolean canGcNow() {
12334 return mParallelBroadcasts.size() == 0
12335 && mOrderedBroadcasts.size() == 0
12336 && (mSleeping || (mResumedActivity != null &&
12337 mResumedActivity.idle));
12338 }
12339
12340 /**
12341 * Perform GCs on all processes that are waiting for it, but only
12342 * if things are idle.
12343 */
12344 final void performAppGcsLocked() {
12345 final int N = mProcessesToGc.size();
12346 if (N <= 0) {
12347 return;
12348 }
12349 if (canGcNow()) {
12350 while (mProcessesToGc.size() > 0) {
12351 ProcessRecord proc = mProcessesToGc.remove(0);
12352 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12353 // To avoid spamming the system, we will GC processes one
12354 // at a time, waiting a few seconds between each.
12355 performAppGcLocked(proc);
12356 scheduleAppGcsLocked();
12357 return;
12358 }
12359 }
12360 }
12361 }
12362
12363 /**
12364 * If all looks good, perform GCs on all processes waiting for them.
12365 */
12366 final void performAppGcsIfAppropriateLocked() {
12367 if (canGcNow()) {
12368 performAppGcsLocked();
12369 return;
12370 }
12371 // Still not idle, wait some more.
12372 scheduleAppGcsLocked();
12373 }
12374
12375 /**
12376 * Schedule the execution of all pending app GCs.
12377 */
12378 final void scheduleAppGcsLocked() {
12379 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12380 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12381 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12382 }
12383
12384 /**
12385 * Set up to ask a process to GC itself. This will either do it
12386 * immediately, or put it on the list of processes to gc the next
12387 * time things are idle.
12388 */
12389 final void scheduleAppGcLocked(ProcessRecord app) {
12390 long now = SystemClock.uptimeMillis();
12391 if ((app.lastRequestedGc+5000) > now) {
12392 return;
12393 }
12394 if (!mProcessesToGc.contains(app)) {
12395 mProcessesToGc.add(app);
12396 scheduleAppGcsLocked();
12397 }
12398 }
12399
12400 private final boolean updateOomAdjLocked(
12401 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12402 app.hiddenAdj = hiddenAdj;
12403
12404 if (app.thread == null) {
12405 return true;
12406 }
12407
12408 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12409
12410 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12411 //Thread priority adjustment is disabled out to see
12412 //how the kernel scheduler performs.
12413 if (false) {
12414 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12415 app.setIsForeground = app.isForeground;
12416 if (app.pid != MY_PID) {
12417 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12418 + " to " + (app.isForeground
12419 ? Process.THREAD_PRIORITY_FOREGROUND
12420 : Process.THREAD_PRIORITY_DEFAULT));
12421 try {
12422 Process.setThreadPriority(app.pid, app.isForeground
12423 ? Process.THREAD_PRIORITY_FOREGROUND
12424 : Process.THREAD_PRIORITY_DEFAULT);
12425 } catch (RuntimeException e) {
12426 Log.w(TAG, "Exception trying to set priority of application thread "
12427 + app.pid, e);
12428 }
12429 }
12430 }
12431 }
12432 if (app.pid != 0 && app.pid != MY_PID) {
12433 if (app.curRawAdj != app.setRawAdj) {
12434 if (app.curRawAdj > FOREGROUND_APP_ADJ
12435 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12436 // If this app is transitioning from foreground to
12437 // non-foreground, have it do a gc.
12438 scheduleAppGcLocked(app);
12439 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12440 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12441 // Likewise do a gc when an app is moving in to the
12442 // background (such as a service stopping).
12443 scheduleAppGcLocked(app);
12444 }
12445 app.setRawAdj = app.curRawAdj;
12446 }
12447 if (adj != app.setAdj) {
12448 if (Process.setOomAdj(app.pid, adj)) {
12449 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12450 TAG, "Set app " + app.processName +
12451 " oom adj to " + adj);
12452 app.setAdj = adj;
12453 } else {
12454 return false;
12455 }
12456 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012457 if (app.setSchedGroup != app.curSchedGroup) {
12458 app.setSchedGroup = app.curSchedGroup;
12459 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12460 "Setting process group of " + app.processName
12461 + " to " + app.curSchedGroup);
12462 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012463 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012464 try {
12465 Process.setProcessGroup(app.pid, app.curSchedGroup);
12466 } catch (Exception e) {
12467 Log.w(TAG, "Failed setting process group of " + app.pid
12468 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012469 e.printStackTrace();
12470 } finally {
12471 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012472 }
12473 }
12474 if (false) {
12475 if (app.thread != null) {
12476 try {
12477 app.thread.setSchedulingGroup(app.curSchedGroup);
12478 } catch (RemoteException e) {
12479 }
12480 }
12481 }
12482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012483 }
12484
12485 return true;
12486 }
12487
12488 private final HistoryRecord resumedAppLocked() {
12489 HistoryRecord resumedActivity = mResumedActivity;
12490 if (resumedActivity == null || resumedActivity.app == null) {
12491 resumedActivity = mPausingActivity;
12492 if (resumedActivity == null || resumedActivity.app == null) {
12493 resumedActivity = topRunningActivityLocked(null);
12494 }
12495 }
12496 return resumedActivity;
12497 }
12498
12499 private final boolean updateOomAdjLocked(ProcessRecord app) {
12500 final HistoryRecord TOP_ACT = resumedAppLocked();
12501 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12502 int curAdj = app.curAdj;
12503 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12504 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12505
12506 mAdjSeq++;
12507
12508 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12509 if (res) {
12510 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12511 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12512 if (nowHidden != wasHidden) {
12513 // Changed to/from hidden state, so apps after it in the LRU
12514 // list may also be changed.
12515 updateOomAdjLocked();
12516 }
12517 }
12518 return res;
12519 }
12520
12521 private final boolean updateOomAdjLocked() {
12522 boolean didOomAdj = true;
12523 final HistoryRecord TOP_ACT = resumedAppLocked();
12524 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12525
12526 if (false) {
12527 RuntimeException e = new RuntimeException();
12528 e.fillInStackTrace();
12529 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12530 }
12531
12532 mAdjSeq++;
12533
12534 // First try updating the OOM adjustment for each of the
12535 // application processes based on their current state.
12536 int i = mLRUProcesses.size();
12537 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12538 while (i > 0) {
12539 i--;
12540 ProcessRecord app = mLRUProcesses.get(i);
12541 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12542 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12543 && app.curAdj == curHiddenAdj) {
12544 curHiddenAdj++;
12545 }
12546 } else {
12547 didOomAdj = false;
12548 }
12549 }
12550
12551 // todo: for now pretend like OOM ADJ didn't work, because things
12552 // aren't behaving as expected on Linux -- it's not killing processes.
12553 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12554 }
12555
12556 private final void trimApplications() {
12557 synchronized (this) {
12558 int i;
12559
12560 // First remove any unused application processes whose package
12561 // has been removed.
12562 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12563 final ProcessRecord app = mRemovedProcesses.get(i);
12564 if (app.activities.size() == 0
12565 && app.curReceiver == null && app.services.size() == 0) {
12566 Log.i(
12567 TAG, "Exiting empty application process "
12568 + app.processName + " ("
12569 + (app.thread != null ? app.thread.asBinder() : null)
12570 + ")\n");
12571 if (app.pid > 0 && app.pid != MY_PID) {
12572 Process.killProcess(app.pid);
12573 } else {
12574 try {
12575 app.thread.scheduleExit();
12576 } catch (Exception e) {
12577 // Ignore exceptions.
12578 }
12579 }
12580 cleanUpApplicationRecordLocked(app, false, -1);
12581 mRemovedProcesses.remove(i);
12582
12583 if (app.persistent) {
12584 if (app.persistent) {
12585 addAppLocked(app.info);
12586 }
12587 }
12588 }
12589 }
12590
12591 // Now try updating the OOM adjustment for each of the
12592 // application processes based on their current state.
12593 // If the setOomAdj() API is not supported, then go with our
12594 // back-up plan...
12595 if (!updateOomAdjLocked()) {
12596
12597 // Count how many processes are running services.
12598 int numServiceProcs = 0;
12599 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12600 final ProcessRecord app = mLRUProcesses.get(i);
12601
12602 if (app.persistent || app.services.size() != 0
12603 || app.curReceiver != null
12604 || app.persistentActivities > 0) {
12605 // Don't count processes holding services against our
12606 // maximum process count.
12607 if (localLOGV) Log.v(
12608 TAG, "Not trimming app " + app + " with services: "
12609 + app.services);
12610 numServiceProcs++;
12611 }
12612 }
12613
12614 int curMaxProcs = mProcessLimit;
12615 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12616 if (mAlwaysFinishActivities) {
12617 curMaxProcs = 1;
12618 }
12619 curMaxProcs += numServiceProcs;
12620
12621 // Quit as many processes as we can to get down to the desired
12622 // process count. First remove any processes that no longer
12623 // have activites running in them.
12624 for ( i=0;
12625 i<mLRUProcesses.size()
12626 && mLRUProcesses.size() > curMaxProcs;
12627 i++) {
12628 final ProcessRecord app = mLRUProcesses.get(i);
12629 // Quit an application only if it is not currently
12630 // running any activities.
12631 if (!app.persistent && app.activities.size() == 0
12632 && app.curReceiver == null && app.services.size() == 0) {
12633 Log.i(
12634 TAG, "Exiting empty application process "
12635 + app.processName + " ("
12636 + (app.thread != null ? app.thread.asBinder() : null)
12637 + ")\n");
12638 if (app.pid > 0 && app.pid != MY_PID) {
12639 Process.killProcess(app.pid);
12640 } else {
12641 try {
12642 app.thread.scheduleExit();
12643 } catch (Exception e) {
12644 // Ignore exceptions.
12645 }
12646 }
12647 // todo: For now we assume the application is not buggy
12648 // or evil, and will quit as a result of our request.
12649 // Eventually we need to drive this off of the death
12650 // notification, and kill the process if it takes too long.
12651 cleanUpApplicationRecordLocked(app, false, i);
12652 i--;
12653 }
12654 }
12655
12656 // If we still have too many processes, now from the least
12657 // recently used process we start finishing activities.
12658 if (Config.LOGV) Log.v(
12659 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12660 " of " + curMaxProcs + " processes");
12661 for ( i=0;
12662 i<mLRUProcesses.size()
12663 && mLRUProcesses.size() > curMaxProcs;
12664 i++) {
12665 final ProcessRecord app = mLRUProcesses.get(i);
12666 // Quit the application only if we have a state saved for
12667 // all of its activities.
12668 boolean canQuit = !app.persistent && app.curReceiver == null
12669 && app.services.size() == 0
12670 && app.persistentActivities == 0;
12671 int NUMA = app.activities.size();
12672 int j;
12673 if (Config.LOGV) Log.v(
12674 TAG, "Looking to quit " + app.processName);
12675 for (j=0; j<NUMA && canQuit; j++) {
12676 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12677 if (Config.LOGV) Log.v(
12678 TAG, " " + r.intent.getComponent().flattenToShortString()
12679 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12680 canQuit = (r.haveState || !r.stateNotNeeded)
12681 && !r.visible && r.stopped;
12682 }
12683 if (canQuit) {
12684 // Finish all of the activities, and then the app itself.
12685 for (j=0; j<NUMA; j++) {
12686 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12687 if (!r.finishing) {
12688 destroyActivityLocked(r, false);
12689 }
12690 r.resultTo = null;
12691 }
12692 Log.i(TAG, "Exiting application process "
12693 + app.processName + " ("
12694 + (app.thread != null ? app.thread.asBinder() : null)
12695 + ")\n");
12696 if (app.pid > 0 && app.pid != MY_PID) {
12697 Process.killProcess(app.pid);
12698 } else {
12699 try {
12700 app.thread.scheduleExit();
12701 } catch (Exception e) {
12702 // Ignore exceptions.
12703 }
12704 }
12705 // todo: For now we assume the application is not buggy
12706 // or evil, and will quit as a result of our request.
12707 // Eventually we need to drive this off of the death
12708 // notification, and kill the process if it takes too long.
12709 cleanUpApplicationRecordLocked(app, false, i);
12710 i--;
12711 //dump();
12712 }
12713 }
12714
12715 }
12716
12717 int curMaxActivities = MAX_ACTIVITIES;
12718 if (mAlwaysFinishActivities) {
12719 curMaxActivities = 1;
12720 }
12721
12722 // Finally, if there are too many activities now running, try to
12723 // finish as many as we can to get back down to the limit.
12724 for ( i=0;
12725 i<mLRUActivities.size()
12726 && mLRUActivities.size() > curMaxActivities;
12727 i++) {
12728 final HistoryRecord r
12729 = (HistoryRecord)mLRUActivities.get(i);
12730
12731 // We can finish this one if we have its icicle saved and
12732 // it is not persistent.
12733 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12734 && r.stopped && !r.persistent && !r.finishing) {
12735 final int origSize = mLRUActivities.size();
12736 destroyActivityLocked(r, true);
12737
12738 // This will remove it from the LRU list, so keep
12739 // our index at the same value. Note that this check to
12740 // see if the size changes is just paranoia -- if
12741 // something unexpected happens, we don't want to end up
12742 // in an infinite loop.
12743 if (origSize > mLRUActivities.size()) {
12744 i--;
12745 }
12746 }
12747 }
12748 }
12749 }
12750
12751 /** This method sends the specified signal to each of the persistent apps */
12752 public void signalPersistentProcesses(int sig) throws RemoteException {
12753 if (sig != Process.SIGNAL_USR1) {
12754 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12755 }
12756
12757 synchronized (this) {
12758 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12759 != PackageManager.PERMISSION_GRANTED) {
12760 throw new SecurityException("Requires permission "
12761 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12762 }
12763
12764 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12765 ProcessRecord r = mLRUProcesses.get(i);
12766 if (r.thread != null && r.persistent) {
12767 Process.sendSignal(r.pid, sig);
12768 }
12769 }
12770 }
12771 }
12772
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012773 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012774 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012775
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012776 try {
12777 synchronized (this) {
12778 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12779 // its own permission.
12780 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12781 != PackageManager.PERMISSION_GRANTED) {
12782 throw new SecurityException("Requires permission "
12783 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012784 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012785
12786 if (start && fd == null) {
12787 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012788 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012789
12790 ProcessRecord proc = null;
12791 try {
12792 int pid = Integer.parseInt(process);
12793 synchronized (mPidsSelfLocked) {
12794 proc = mPidsSelfLocked.get(pid);
12795 }
12796 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012797 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012798
12799 if (proc == null) {
12800 HashMap<String, SparseArray<ProcessRecord>> all
12801 = mProcessNames.getMap();
12802 SparseArray<ProcessRecord> procs = all.get(process);
12803 if (procs != null && procs.size() > 0) {
12804 proc = procs.valueAt(0);
12805 }
12806 }
12807
12808 if (proc == null || proc.thread == null) {
12809 throw new IllegalArgumentException("Unknown process: " + process);
12810 }
12811
12812 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12813 if (isSecure) {
12814 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12815 throw new SecurityException("Process not debuggable: " + proc);
12816 }
12817 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012818
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012819 proc.thread.profilerControl(start, path, fd);
12820 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012821 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012822 }
12823 } catch (RemoteException e) {
12824 throw new IllegalStateException("Process disappeared");
12825 } finally {
12826 if (fd != null) {
12827 try {
12828 fd.close();
12829 } catch (IOException e) {
12830 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012831 }
12832 }
12833 }
12834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012835 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12836 public void monitor() {
12837 synchronized (this) { }
12838 }
12839}