blob: aad542af4eaa83ec7107d85ef26b9808ca1f0f3c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
35import android.app.IActivityWatcher;
36import android.app.IApplicationThread;
37import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.IServiceConnection;
39import android.app.IThumbnailReceiver;
40import android.app.Instrumentation;
41import android.app.PendingIntent;
42import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070043import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020044import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.content.ComponentName;
46import android.content.ContentResolver;
47import android.content.Context;
48import android.content.Intent;
49import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070050import android.content.IIntentReceiver;
51import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.pm.ActivityInfo;
53import android.content.pm.ApplicationInfo;
54import android.content.pm.ConfigurationInfo;
55import android.content.pm.IPackageDataObserver;
56import android.content.pm.IPackageManager;
57import android.content.pm.InstrumentationInfo;
58import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070059import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.content.pm.ProviderInfo;
61import android.content.pm.ResolveInfo;
62import android.content.pm.ServiceInfo;
63import android.content.res.Configuration;
64import android.graphics.Bitmap;
65import android.net.Uri;
66import android.os.Binder;
67import android.os.Bundle;
68import android.os.Environment;
69import android.os.FileUtils;
70import android.os.Handler;
71import android.os.IBinder;
72import android.os.IPermissionController;
73import android.os.Looper;
74import android.os.Message;
75import android.os.Parcel;
76import android.os.ParcelFileDescriptor;
77import android.os.PowerManager;
78import android.os.Process;
79import android.os.RemoteException;
80import android.os.ServiceManager;
81import android.os.SystemClock;
82import android.os.SystemProperties;
83import android.provider.Checkin;
84import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020085import android.server.data.CrashData;
86import android.server.data.StackTraceElementData;
87import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.text.TextUtils;
89import android.util.Config;
90import android.util.EventLog;
91import android.util.Log;
92import android.util.PrintWriterPrinter;
93import android.util.SparseArray;
94import android.view.Gravity;
95import android.view.LayoutInflater;
96import android.view.View;
97import android.view.WindowManager;
98import android.view.WindowManagerPolicy;
99
100import dalvik.system.Zygote;
101
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200102import java.io.ByteArrayInputStream;
103import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import java.io.File;
105import java.io.FileDescriptor;
106import java.io.FileInputStream;
107import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.PrintWriter;
110import java.lang.IllegalStateException;
111import java.lang.ref.WeakReference;
112import java.util.ArrayList;
113import java.util.HashMap;
114import java.util.HashSet;
115import java.util.Iterator;
116import java.util.List;
117import java.util.Locale;
118import java.util.Map;
119
120public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
121 static final String TAG = "ActivityManager";
122 static final boolean DEBUG = false;
123 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
124 static final boolean DEBUG_SWITCH = localLOGV || false;
125 static final boolean DEBUG_TASKS = localLOGV || false;
126 static final boolean DEBUG_PAUSE = localLOGV || false;
127 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
128 static final boolean DEBUG_TRANSITION = localLOGV || false;
129 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700130 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 static final boolean DEBUG_SERVICE = localLOGV || false;
132 static final boolean DEBUG_VISBILITY = localLOGV || false;
133 static final boolean DEBUG_PROCESSES = localLOGV || false;
134 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700135 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700136 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean VALIDATE_TOKENS = false;
138 static final boolean SHOW_ACTIVITY_START_TIME = true;
139
140 // Control over CPU and battery monitoring.
141 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
142 static final boolean MONITOR_CPU_USAGE = true;
143 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
144 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
145 static final boolean MONITOR_THREAD_CPU_USAGE = false;
146
147 // Event log tags
148 static final int LOG_CONFIGURATION_CHANGED = 2719;
149 static final int LOG_CPU = 2721;
150 static final int LOG_AM_FINISH_ACTIVITY = 30001;
151 static final int LOG_TASK_TO_FRONT = 30002;
152 static final int LOG_AM_NEW_INTENT = 30003;
153 static final int LOG_AM_CREATE_TASK = 30004;
154 static final int LOG_AM_CREATE_ACTIVITY = 30005;
155 static final int LOG_AM_RESTART_ACTIVITY = 30006;
156 static final int LOG_AM_RESUME_ACTIVITY = 30007;
157 static final int LOG_ANR = 30008;
158 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
159 static final int LOG_AM_PROCESS_BOUND = 30010;
160 static final int LOG_AM_PROCESS_DIED = 30011;
161 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
162 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
163 static final int LOG_AM_PROCESS_START = 30014;
164 static final int LOG_AM_PROCESS_BAD = 30015;
165 static final int LOG_AM_PROCESS_GOOD = 30016;
166 static final int LOG_AM_LOW_MEMORY = 30017;
167 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
168 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
169 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
170 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
171 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
172 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
173 static final int LOG_AM_CREATE_SERVICE = 30030;
174 static final int LOG_AM_DESTROY_SERVICE = 30031;
175 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
176 static final int LOG_AM_DROP_PROCESS = 30033;
177 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
178 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
179 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
180
181 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
182 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
183
Dianne Hackborn1655be42009-05-08 14:29:01 -0700184 // The flags that are set for all calls we make to the package manager.
185 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700186 | PackageManager.GET_SUPPORTS_DENSITIES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 private static final String SYSTEM_SECURE = "ro.secure";
189
190 // This is the maximum number of application processes we would like
191 // to have running. Due to the asynchronous nature of things, we can
192 // temporarily go beyond this limit.
193 static final int MAX_PROCESSES = 2;
194
195 // Set to false to leave processes running indefinitely, relying on
196 // the kernel killing them as resources are required.
197 static final boolean ENFORCE_PROCESS_LIMIT = false;
198
199 // This is the maximum number of activities that we would like to have
200 // running at a given time.
201 static final int MAX_ACTIVITIES = 20;
202
203 // Maximum number of recent tasks that we can remember.
204 static final int MAX_RECENT_TASKS = 20;
205
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700206 // Amount of time after a call to stopAppSwitches() during which we will
207 // prevent further untrusted switches from happening.
208 static final long APP_SWITCH_DELAY_TIME = 5*1000;
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 // How long until we reset a task when the user returns to it. Currently
211 // 30 minutes.
212 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
213
214 // Set to true to disable the icon that is shown while a new activity
215 // is being started.
216 static final boolean SHOW_APP_STARTING_ICON = true;
217
218 // How long we wait until giving up on the last activity to pause. This
219 // is short because it directly impacts the responsiveness of starting the
220 // next activity.
221 static final int PAUSE_TIMEOUT = 500;
222
223 /**
224 * How long we can hold the launch wake lock before giving up.
225 */
226 static final int LAUNCH_TIMEOUT = 10*1000;
227
228 // How long we wait for a launched process to attach to the activity manager
229 // before we decide it's never going to come up for real.
230 static final int PROC_START_TIMEOUT = 10*1000;
231
232 // How long we wait until giving up on the last activity telling us it
233 // is idle.
234 static final int IDLE_TIMEOUT = 10*1000;
235
236 // How long to wait after going idle before forcing apps to GC.
237 static final int GC_TIMEOUT = 5*1000;
238
239 // How long we wait until giving up on an activity telling us it has
240 // finished destroying itself.
241 static final int DESTROY_TIMEOUT = 10*1000;
242
243 // How long we allow a receiver to run before giving up on it.
244 static final int BROADCAST_TIMEOUT = 10*1000;
245
246 // How long we wait for a service to finish executing.
247 static final int SERVICE_TIMEOUT = 20*1000;
248
249 // How long a service needs to be running until restarting its process
250 // is no longer considered to be a relaunch of the service.
251 static final int SERVICE_RESTART_DURATION = 5*1000;
252
253 // Maximum amount of time for there to be no activity on a service before
254 // we consider it non-essential and allow its process to go on the
255 // LRU background list.
256 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
257
258 // How long we wait until we timeout on key dispatching.
259 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
260
261 // The minimum time we allow between crashes, for us to consider this
262 // application to be bad and stop and its services and reject broadcasts.
263 static final int MIN_CRASH_INTERVAL = 60*1000;
264
265 // How long we wait until we timeout on key dispatching during instrumentation.
266 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
267
268 // OOM adjustments for processes in various states:
269
270 // This is a process without anything currently running in it. Definitely
271 // the first to go! Value set in system/rootdir/init.rc on startup.
272 // This value is initalized in the constructor, careful when refering to
273 // this static variable externally.
274 static int EMPTY_APP_ADJ;
275
276 // This is a process with a content provider that does not have any clients
277 // attached to it. If it did have any clients, its adjustment would be the
278 // one for the highest-priority of those processes.
279 static int CONTENT_PROVIDER_ADJ;
280
281 // This is a process only hosting activities that are not visible,
282 // so it can be killed without any disruption. Value set in
283 // system/rootdir/init.rc on startup.
284 final int HIDDEN_APP_MAX_ADJ;
285 static int HIDDEN_APP_MIN_ADJ;
286
The Android Open Source Project4df24232009-03-05 14:34:35 -0800287 // This is a process holding the home application -- we want to try
288 // avoiding killing it, even if it would normally be in the background,
289 // because the user interacts with it so much.
290 final int HOME_APP_ADJ;
291
Christopher Tate6fa95972009-06-05 18:43:55 -0700292 // This is a process currently hosting a backup operation. Killing it
293 // is not entirely fatal but is generally a bad idea.
294 final int BACKUP_APP_ADJ;
295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 // This is a process holding a secondary server -- killing it will not
297 // have much of an impact as far as the user is concerned. Value set in
298 // system/rootdir/init.rc on startup.
299 final int SECONDARY_SERVER_ADJ;
300
301 // This is a process only hosting activities that are visible to the
302 // user, so we'd prefer they don't disappear. Value set in
303 // system/rootdir/init.rc on startup.
304 final int VISIBLE_APP_ADJ;
305
306 // This is the process running the current foreground app. We'd really
307 // rather not kill it! Value set in system/rootdir/init.rc on startup.
308 final int FOREGROUND_APP_ADJ;
309
310 // This is a process running a core server, such as telephony. Definitely
311 // don't want to kill it, but doing so is not completely fatal.
312 static final int CORE_SERVER_ADJ = -12;
313
314 // The system process runs at the default adjustment.
315 static final int SYSTEM_ADJ = -16;
316
317 // Memory pages are 4K.
318 static final int PAGE_SIZE = 4*1024;
319
320 // Corresponding memory levels for above adjustments.
321 final int EMPTY_APP_MEM;
322 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800323 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700324 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 final int SECONDARY_SERVER_MEM;
326 final int VISIBLE_APP_MEM;
327 final int FOREGROUND_APP_MEM;
328
329 final int MY_PID;
330
331 static final String[] EMPTY_STRING_ARRAY = new String[0];
332
333 enum ActivityState {
334 INITIALIZING,
335 RESUMED,
336 PAUSING,
337 PAUSED,
338 STOPPING,
339 STOPPED,
340 FINISHING,
341 DESTROYING,
342 DESTROYED
343 }
344
345 /**
346 * The back history of all previous (and possibly still
347 * running) activities. It contains HistoryRecord objects.
348 */
349 final ArrayList mHistory = new ArrayList();
350
351 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700352 * Description of a request to start a new activity, which has been held
353 * due to app switches being disabled.
354 */
355 class PendingActivityLaunch {
356 HistoryRecord r;
357 HistoryRecord sourceRecord;
358 Uri[] grantedUriPermissions;
359 int grantedMode;
360 boolean onlyIfNeeded;
361 }
362
363 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
364 = new ArrayList<PendingActivityLaunch>();
365
366 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 * List of all active broadcasts that are to be executed immediately
368 * (without waiting for another broadcast to finish). Currently this only
369 * contains broadcasts to registered receivers, to avoid spinning up
370 * a bunch of processes to execute IntentReceiver components.
371 */
372 final ArrayList<BroadcastRecord> mParallelBroadcasts
373 = new ArrayList<BroadcastRecord>();
374
375 /**
376 * List of all active broadcasts that are to be executed one at a time.
377 * The object at the top of the list is the currently activity broadcasts;
378 * those after it are waiting for the top to finish..
379 */
380 final ArrayList<BroadcastRecord> mOrderedBroadcasts
381 = new ArrayList<BroadcastRecord>();
382
383 /**
384 * Set when we current have a BROADCAST_INTENT_MSG in flight.
385 */
386 boolean mBroadcastsScheduled = false;
387
388 /**
389 * Set to indicate whether to issue an onUserLeaving callback when a
390 * newly launched activity is being brought in front of us.
391 */
392 boolean mUserLeaving = false;
393
394 /**
395 * When we are in the process of pausing an activity, before starting the
396 * next one, this variable holds the activity that is currently being paused.
397 */
398 HistoryRecord mPausingActivity = null;
399
400 /**
401 * Current activity that is resumed, or null if there is none.
402 */
403 HistoryRecord mResumedActivity = null;
404
405 /**
406 * Activity we have told the window manager to have key focus.
407 */
408 HistoryRecord mFocusedActivity = null;
409
410 /**
411 * This is the last activity that we put into the paused state. This is
412 * used to determine if we need to do an activity transition while sleeping,
413 * when we normally hold the top activity paused.
414 */
415 HistoryRecord mLastPausedActivity = null;
416
417 /**
418 * List of activities that are waiting for a new activity
419 * to become visible before completing whatever operation they are
420 * supposed to do.
421 */
422 final ArrayList mWaitingVisibleActivities = new ArrayList();
423
424 /**
425 * List of activities that are ready to be stopped, but waiting
426 * for the next activity to settle down before doing so. It contains
427 * HistoryRecord objects.
428 */
429 final ArrayList<HistoryRecord> mStoppingActivities
430 = new ArrayList<HistoryRecord>();
431
432 /**
433 * List of intents that were used to start the most recent tasks.
434 */
435 final ArrayList<TaskRecord> mRecentTasks
436 = new ArrayList<TaskRecord>();
437
438 /**
439 * List of activities that are ready to be finished, but waiting
440 * for the previous activity to settle down before doing so. It contains
441 * HistoryRecord objects.
442 */
443 final ArrayList mFinishingActivities = new ArrayList();
444
445 /**
446 * All of the applications we currently have running organized by name.
447 * The keys are strings of the application package name (as
448 * returned by the package manager), and the keys are ApplicationRecord
449 * objects.
450 */
451 final ProcessMap<ProcessRecord> mProcessNames
452 = new ProcessMap<ProcessRecord>();
453
454 /**
455 * The last time that various processes have crashed.
456 */
457 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
458
459 /**
460 * Set of applications that we consider to be bad, and will reject
461 * incoming broadcasts from (which the user has no control over).
462 * Processes are added to this set when they have crashed twice within
463 * a minimum amount of time; they are removed from it when they are
464 * later restarted (hopefully due to some user action). The value is the
465 * time it was added to the list.
466 */
467 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
468
469 /**
470 * All of the processes we currently have running organized by pid.
471 * The keys are the pid running the application.
472 *
473 * <p>NOTE: This object is protected by its own lock, NOT the global
474 * activity manager lock!
475 */
476 final SparseArray<ProcessRecord> mPidsSelfLocked
477 = new SparseArray<ProcessRecord>();
478
479 /**
480 * All of the processes that have been forced to be foreground. The key
481 * is the pid of the caller who requested it (we hold a death
482 * link on it).
483 */
484 abstract class ForegroundToken implements IBinder.DeathRecipient {
485 int pid;
486 IBinder token;
487 }
488 final SparseArray<ForegroundToken> mForegroundProcesses
489 = new SparseArray<ForegroundToken>();
490
491 /**
492 * List of records for processes that someone had tried to start before the
493 * system was ready. We don't start them at that point, but ensure they
494 * are started by the time booting is complete.
495 */
496 final ArrayList<ProcessRecord> mProcessesOnHold
497 = new ArrayList<ProcessRecord>();
498
499 /**
500 * List of records for processes that we have started and are waiting
501 * for them to call back. This is really only needed when running in
502 * single processes mode, in which case we do not have a unique pid for
503 * each process.
504 */
505 final ArrayList<ProcessRecord> mStartingProcesses
506 = new ArrayList<ProcessRecord>();
507
508 /**
509 * List of persistent applications that are in the process
510 * of being started.
511 */
512 final ArrayList<ProcessRecord> mPersistentStartingProcesses
513 = new ArrayList<ProcessRecord>();
514
515 /**
516 * Processes that are being forcibly torn down.
517 */
518 final ArrayList<ProcessRecord> mRemovedProcesses
519 = new ArrayList<ProcessRecord>();
520
521 /**
522 * List of running applications, sorted by recent usage.
523 * The first entry in the list is the least recently used.
524 * It contains ApplicationRecord objects. This list does NOT include
525 * any persistent application records (since we never want to exit them).
526 */
527 final ArrayList<ProcessRecord> mLRUProcesses
528 = new ArrayList<ProcessRecord>();
529
530 /**
531 * List of processes that should gc as soon as things are idle.
532 */
533 final ArrayList<ProcessRecord> mProcessesToGc
534 = new ArrayList<ProcessRecord>();
535
536 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800537 * This is the process holding what we currently consider to be
538 * the "home" activity.
539 */
540 private ProcessRecord mHomeProcess;
541
542 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 * List of running activities, sorted by recent usage.
544 * The first entry in the list is the least recently used.
545 * It contains HistoryRecord objects.
546 */
547 private final ArrayList mLRUActivities = new ArrayList();
548
549 /**
550 * Set of PendingResultRecord objects that are currently active.
551 */
552 final HashSet mPendingResultRecords = new HashSet();
553
554 /**
555 * Set of IntentSenderRecord objects that are currently active.
556 */
557 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
558 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
559
560 /**
561 * Intent broadcast that we have tried to start, but are
562 * waiting for its application's process to be created. We only
563 * need one (instead of a list) because we always process broadcasts
564 * one at a time, so no others can be started while waiting for this
565 * one.
566 */
567 BroadcastRecord mPendingBroadcast = null;
568
569 /**
570 * Keeps track of all IIntentReceivers that have been registered for
571 * broadcasts. Hash keys are the receiver IBinder, hash value is
572 * a ReceiverList.
573 */
574 final HashMap mRegisteredReceivers = new HashMap();
575
576 /**
577 * Resolver for broadcast intents to registered receivers.
578 * Holds BroadcastFilter (subclass of IntentFilter).
579 */
580 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
581 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
582 @Override
583 protected boolean allowFilterResult(
584 BroadcastFilter filter, List<BroadcastFilter> dest) {
585 IBinder target = filter.receiverList.receiver.asBinder();
586 for (int i=dest.size()-1; i>=0; i--) {
587 if (dest.get(i).receiverList.receiver.asBinder() == target) {
588 return false;
589 }
590 }
591 return true;
592 }
593 };
594
595 /**
596 * State of all active sticky broadcasts. Keys are the action of the
597 * sticky Intent, values are an ArrayList of all broadcasted intents with
598 * that action (which should usually be one).
599 */
600 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
601 new HashMap<String, ArrayList<Intent>>();
602
603 /**
604 * All currently running services.
605 */
606 final HashMap<ComponentName, ServiceRecord> mServices =
607 new HashMap<ComponentName, ServiceRecord>();
608
609 /**
610 * All currently running services indexed by the Intent used to start them.
611 */
612 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
613 new HashMap<Intent.FilterComparison, ServiceRecord>();
614
615 /**
616 * All currently bound service connections. Keys are the IBinder of
617 * the client's IServiceConnection.
618 */
619 final HashMap<IBinder, ConnectionRecord> mServiceConnections
620 = new HashMap<IBinder, ConnectionRecord>();
621
622 /**
623 * List of services that we have been asked to start,
624 * but haven't yet been able to. It is used to hold start requests
625 * while waiting for their corresponding application thread to get
626 * going.
627 */
628 final ArrayList<ServiceRecord> mPendingServices
629 = new ArrayList<ServiceRecord>();
630
631 /**
632 * List of services that are scheduled to restart following a crash.
633 */
634 final ArrayList<ServiceRecord> mRestartingServices
635 = new ArrayList<ServiceRecord>();
636
637 /**
638 * List of services that are in the process of being stopped.
639 */
640 final ArrayList<ServiceRecord> mStoppingServices
641 = new ArrayList<ServiceRecord>();
642
643 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700644 * Backup/restore process management
645 */
646 String mBackupAppName = null;
647 BackupRecord mBackupTarget = null;
648
649 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 * List of PendingThumbnailsRecord objects of clients who are still
651 * waiting to receive all of the thumbnails for a task.
652 */
653 final ArrayList mPendingThumbnails = new ArrayList();
654
655 /**
656 * List of HistoryRecord objects that have been finished and must
657 * still report back to a pending thumbnail receiver.
658 */
659 final ArrayList mCancelledThumbnails = new ArrayList();
660
661 /**
662 * All of the currently running global content providers. Keys are a
663 * string containing the provider name and values are a
664 * ContentProviderRecord object containing the data about it. Note
665 * that a single provider may be published under multiple names, so
666 * there may be multiple entries here for a single one in mProvidersByClass.
667 */
668 final HashMap mProvidersByName = new HashMap();
669
670 /**
671 * All of the currently running global content providers. Keys are a
672 * string containing the provider's implementation class and values are a
673 * ContentProviderRecord object containing the data about it.
674 */
675 final HashMap mProvidersByClass = new HashMap();
676
677 /**
678 * List of content providers who have clients waiting for them. The
679 * application is currently being launched and the provider will be
680 * removed from this list once it is published.
681 */
682 final ArrayList mLaunchingProviders = new ArrayList();
683
684 /**
685 * Global set of specific Uri permissions that have been granted.
686 */
687 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
688 = new SparseArray<HashMap<Uri, UriPermission>>();
689
690 /**
691 * Thread-local storage used to carry caller permissions over through
692 * indirect content-provider access.
693 * @see #ActivityManagerService.openContentUri()
694 */
695 private class Identity {
696 public int pid;
697 public int uid;
698
699 Identity(int _pid, int _uid) {
700 pid = _pid;
701 uid = _uid;
702 }
703 }
704 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
705
706 /**
707 * All information we have collected about the runtime performance of
708 * any user id that can impact battery performance.
709 */
710 final BatteryStatsService mBatteryStatsService;
711
712 /**
713 * information about component usage
714 */
715 final UsageStatsService mUsageStatsService;
716
717 /**
718 * Current configuration information. HistoryRecord objects are given
719 * a reference to this object to indicate which configuration they are
720 * currently running in, so this object must be kept immutable.
721 */
722 Configuration mConfiguration = new Configuration();
723
724 /**
725 * List of initialization arguments to pass to all processes when binding applications to them.
726 * For example, references to the commonly used services.
727 */
728 HashMap<String, IBinder> mAppBindArgs;
729
730 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700731 * Temporary to avoid allocations. Protected by main lock.
732 */
733 final StringBuilder mStringBuilder = new StringBuilder(256);
734
735 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 * Used to control how we initialize the service.
737 */
738 boolean mStartRunning = false;
739 ComponentName mTopComponent;
740 String mTopAction;
741 String mTopData;
742 boolean mSystemReady = false;
743 boolean mBooting = false;
744
745 Context mContext;
746
747 int mFactoryTest;
748
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700749 boolean mCheckedForSetup;
750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700752 * The time at which we will allow normal application switches again,
753 * after a call to {@link #stopAppSwitches()}.
754 */
755 long mAppSwitchesAllowedTime;
756
757 /**
758 * This is set to true after the first switch after mAppSwitchesAllowedTime
759 * is set; any switches after that will clear the time.
760 */
761 boolean mDidAppSwitch;
762
763 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 * Set while we are wanting to sleep, to prevent any
765 * activities from being started/resumed.
766 */
767 boolean mSleeping = false;
768
769 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700770 * Set if we are shutting down the system, similar to sleeping.
771 */
772 boolean mShuttingDown = false;
773
774 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 * Set when the system is going to sleep, until we have
776 * successfully paused the current activity and released our wake lock.
777 * At that point the system is allowed to actually sleep.
778 */
779 PowerManager.WakeLock mGoingToSleep;
780
781 /**
782 * We don't want to allow the device to go to sleep while in the process
783 * of launching an activity. This is primarily to allow alarm intent
784 * receivers to launch an activity and get that to run before the device
785 * goes back to sleep.
786 */
787 PowerManager.WakeLock mLaunchingActivity;
788
789 /**
790 * Task identifier that activities are currently being started
791 * in. Incremented each time a new task is created.
792 * todo: Replace this with a TokenSpace class that generates non-repeating
793 * integers that won't wrap.
794 */
795 int mCurTask = 1;
796
797 /**
798 * Current sequence id for oom_adj computation traversal.
799 */
800 int mAdjSeq = 0;
801
802 /**
803 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
804 * is set, indicating the user wants processes started in such a way
805 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
806 * running in each process (thus no pre-initialized process, etc).
807 */
808 boolean mSimpleProcessManagement = false;
809
810 /**
811 * System monitoring: number of processes that died since the last
812 * N procs were started.
813 */
814 int[] mProcDeaths = new int[20];
815
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700816 /**
817 * This is set if we had to do a delayed dexopt of an app before launching
818 * it, to increasing the ANR timeouts in that case.
819 */
820 boolean mDidDexOpt;
821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 String mDebugApp = null;
823 boolean mWaitForDebugger = false;
824 boolean mDebugTransient = false;
825 String mOrigDebugApp = null;
826 boolean mOrigWaitForDebugger = false;
827 boolean mAlwaysFinishActivities = false;
828 IActivityWatcher mWatcher = null;
829
830 /**
831 * Callback of last caller to {@link #requestPss}.
832 */
833 Runnable mRequestPssCallback;
834
835 /**
836 * Remaining processes for which we are waiting results from the last
837 * call to {@link #requestPss}.
838 */
839 final ArrayList<ProcessRecord> mRequestPssList
840 = new ArrayList<ProcessRecord>();
841
842 /**
843 * Runtime statistics collection thread. This object's lock is used to
844 * protect all related state.
845 */
846 final Thread mProcessStatsThread;
847
848 /**
849 * Used to collect process stats when showing not responding dialog.
850 * Protected by mProcessStatsThread.
851 */
852 final ProcessStats mProcessStats = new ProcessStats(
853 MONITOR_THREAD_CPU_USAGE);
854 long mLastCpuTime = 0;
855 long mLastWriteTime = 0;
856
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700857 long mInitialStartTime = 0;
858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 /**
860 * Set to true after the system has finished booting.
861 */
862 boolean mBooted = false;
863
864 int mProcessLimit = 0;
865
866 WindowManagerService mWindowManager;
867
868 static ActivityManagerService mSelf;
869 static ActivityThread mSystemThread;
870
871 private final class AppDeathRecipient implements IBinder.DeathRecipient {
872 final ProcessRecord mApp;
873 final int mPid;
874 final IApplicationThread mAppThread;
875
876 AppDeathRecipient(ProcessRecord app, int pid,
877 IApplicationThread thread) {
878 if (localLOGV) Log.v(
879 TAG, "New death recipient " + this
880 + " for thread " + thread.asBinder());
881 mApp = app;
882 mPid = pid;
883 mAppThread = thread;
884 }
885
886 public void binderDied() {
887 if (localLOGV) Log.v(
888 TAG, "Death received in " + this
889 + " for thread " + mAppThread.asBinder());
890 removeRequestedPss(mApp);
891 synchronized(ActivityManagerService.this) {
892 appDiedLocked(mApp, mPid, mAppThread);
893 }
894 }
895 }
896
897 static final int SHOW_ERROR_MSG = 1;
898 static final int SHOW_NOT_RESPONDING_MSG = 2;
899 static final int SHOW_FACTORY_ERROR_MSG = 3;
900 static final int UPDATE_CONFIGURATION_MSG = 4;
901 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
902 static final int WAIT_FOR_DEBUGGER_MSG = 6;
903 static final int BROADCAST_INTENT_MSG = 7;
904 static final int BROADCAST_TIMEOUT_MSG = 8;
905 static final int PAUSE_TIMEOUT_MSG = 9;
906 static final int IDLE_TIMEOUT_MSG = 10;
907 static final int IDLE_NOW_MSG = 11;
908 static final int SERVICE_TIMEOUT_MSG = 12;
909 static final int UPDATE_TIME_ZONE = 13;
910 static final int SHOW_UID_ERROR_MSG = 14;
911 static final int IM_FEELING_LUCKY_MSG = 15;
912 static final int LAUNCH_TIMEOUT_MSG = 16;
913 static final int DESTROY_TIMEOUT_MSG = 17;
914 static final int SERVICE_ERROR_MSG = 18;
915 static final int RESUME_TOP_ACTIVITY_MSG = 19;
916 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700917 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918
919 AlertDialog mUidAlert;
920
921 final Handler mHandler = new Handler() {
922 //public Handler() {
923 // if (localLOGV) Log.v(TAG, "Handler started!");
924 //}
925
926 public void handleMessage(Message msg) {
927 switch (msg.what) {
928 case SHOW_ERROR_MSG: {
929 HashMap data = (HashMap) msg.obj;
930 byte[] crashData = (byte[])data.get("crashData");
931 if (crashData != null) {
932 // This needs to be *un*synchronized to avoid deadlock.
933 ContentResolver resolver = mContext.getContentResolver();
934 Checkin.reportCrash(resolver, crashData);
935 }
936 synchronized (ActivityManagerService.this) {
937 ProcessRecord proc = (ProcessRecord)data.get("app");
938 if (proc != null && proc.crashDialog != null) {
939 Log.e(TAG, "App already has crash dialog: " + proc);
940 return;
941 }
942 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700943 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 Dialog d = new AppErrorDialog(
945 mContext, res, proc,
946 (Integer)data.get("flags"),
947 (String)data.get("shortMsg"),
948 (String)data.get("longMsg"));
949 d.show();
950 proc.crashDialog = d;
951 } else {
952 // The device is asleep, so just pretend that the user
953 // saw a crash dialog and hit "force quit".
954 res.set(0);
955 }
956 }
957 } break;
958 case SHOW_NOT_RESPONDING_MSG: {
959 synchronized (ActivityManagerService.this) {
960 HashMap data = (HashMap) msg.obj;
961 ProcessRecord proc = (ProcessRecord)data.get("app");
962 if (proc != null && proc.anrDialog != null) {
963 Log.e(TAG, "App already has anr dialog: " + proc);
964 return;
965 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800966
967 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
968 null, null, 0, null, null, null,
969 false, false, MY_PID, Process.SYSTEM_UID);
970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
972 mContext, proc, (HistoryRecord)data.get("activity"));
973 d.show();
974 proc.anrDialog = d;
975 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700976
977 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 } break;
979 case SHOW_FACTORY_ERROR_MSG: {
980 Dialog d = new FactoryErrorDialog(
981 mContext, msg.getData().getCharSequence("msg"));
982 d.show();
983 enableScreenAfterBoot();
984 } break;
985 case UPDATE_CONFIGURATION_MSG: {
986 final ContentResolver resolver = mContext.getContentResolver();
987 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
988 } break;
989 case GC_BACKGROUND_PROCESSES_MSG: {
990 synchronized (ActivityManagerService.this) {
991 performAppGcsIfAppropriateLocked();
992 }
993 } break;
994 case WAIT_FOR_DEBUGGER_MSG: {
995 synchronized (ActivityManagerService.this) {
996 ProcessRecord app = (ProcessRecord)msg.obj;
997 if (msg.arg1 != 0) {
998 if (!app.waitedForDebugger) {
999 Dialog d = new AppWaitingForDebuggerDialog(
1000 ActivityManagerService.this,
1001 mContext, app);
1002 app.waitDialog = d;
1003 app.waitedForDebugger = true;
1004 d.show();
1005 }
1006 } else {
1007 if (app.waitDialog != null) {
1008 app.waitDialog.dismiss();
1009 app.waitDialog = null;
1010 }
1011 }
1012 }
1013 } break;
1014 case BROADCAST_INTENT_MSG: {
1015 if (DEBUG_BROADCAST) Log.v(
1016 TAG, "Received BROADCAST_INTENT_MSG");
1017 processNextBroadcast(true);
1018 } break;
1019 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001020 if (mDidDexOpt) {
1021 mDidDexOpt = false;
1022 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1023 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1024 return;
1025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 broadcastTimeout();
1027 } break;
1028 case PAUSE_TIMEOUT_MSG: {
1029 IBinder token = (IBinder)msg.obj;
1030 // We don't at this point know if the activity is fullscreen,
1031 // so we need to be conservative and assume it isn't.
1032 Log.w(TAG, "Activity pause timeout for " + token);
1033 activityPaused(token, null, true);
1034 } break;
1035 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001036 if (mDidDexOpt) {
1037 mDidDexOpt = false;
1038 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1039 nmsg.obj = msg.obj;
1040 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1041 return;
1042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 // We don't at this point know if the activity is fullscreen,
1044 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001045 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 Log.w(TAG, "Activity idle timeout for " + token);
1047 activityIdleInternal(token, true);
1048 } break;
1049 case DESTROY_TIMEOUT_MSG: {
1050 IBinder token = (IBinder)msg.obj;
1051 // We don't at this point know if the activity is fullscreen,
1052 // so we need to be conservative and assume it isn't.
1053 Log.w(TAG, "Activity destroy timeout for " + token);
1054 activityDestroyed(token);
1055 } break;
1056 case IDLE_NOW_MSG: {
1057 IBinder token = (IBinder)msg.obj;
1058 activityIdle(token);
1059 } break;
1060 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001061 if (mDidDexOpt) {
1062 mDidDexOpt = false;
1063 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1064 nmsg.obj = msg.obj;
1065 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1066 return;
1067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 serviceTimeout((ProcessRecord)msg.obj);
1069 } break;
1070 case UPDATE_TIME_ZONE: {
1071 synchronized (ActivityManagerService.this) {
1072 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1073 ProcessRecord r = mLRUProcesses.get(i);
1074 if (r.thread != null) {
1075 try {
1076 r.thread.updateTimeZone();
1077 } catch (RemoteException ex) {
1078 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1079 }
1080 }
1081 }
1082 }
1083 break;
1084 }
1085 case SHOW_UID_ERROR_MSG: {
1086 // XXX This is a temporary dialog, no need to localize.
1087 AlertDialog d = new BaseErrorDialog(mContext);
1088 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1089 d.setCancelable(false);
1090 d.setTitle("System UIDs Inconsistent");
1091 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1092 d.setButton("I'm Feeling Lucky",
1093 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1094 mUidAlert = d;
1095 d.show();
1096 } break;
1097 case IM_FEELING_LUCKY_MSG: {
1098 if (mUidAlert != null) {
1099 mUidAlert.dismiss();
1100 mUidAlert = null;
1101 }
1102 } break;
1103 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001104 if (mDidDexOpt) {
1105 mDidDexOpt = false;
1106 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1107 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1108 return;
1109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 synchronized (ActivityManagerService.this) {
1111 if (mLaunchingActivity.isHeld()) {
1112 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1113 mLaunchingActivity.release();
1114 }
1115 }
1116 } break;
1117 case SERVICE_ERROR_MSG: {
1118 ServiceRecord srv = (ServiceRecord)msg.obj;
1119 // This needs to be *un*synchronized to avoid deadlock.
1120 Checkin.logEvent(mContext.getContentResolver(),
1121 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1122 srv.name.toShortString());
1123 } break;
1124 case RESUME_TOP_ACTIVITY_MSG: {
1125 synchronized (ActivityManagerService.this) {
1126 resumeTopActivityLocked(null);
1127 }
1128 }
1129 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001130 if (mDidDexOpt) {
1131 mDidDexOpt = false;
1132 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1133 nmsg.obj = msg.obj;
1134 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1135 return;
1136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 ProcessRecord app = (ProcessRecord)msg.obj;
1138 synchronized (ActivityManagerService.this) {
1139 processStartTimedOutLocked(app);
1140 }
1141 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001142 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1143 synchronized (ActivityManagerService.this) {
1144 doPendingActivityLaunchesLocked(true);
1145 }
1146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 }
1148 }
1149 };
1150
1151 public static void setSystemProcess() {
1152 try {
1153 ActivityManagerService m = mSelf;
1154
1155 ServiceManager.addService("activity", m);
1156 ServiceManager.addService("meminfo", new MemBinder(m));
1157 if (MONITOR_CPU_USAGE) {
1158 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1159 }
1160 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1161 ServiceManager.addService("activity.services", new ServicesBinder(m));
1162 ServiceManager.addService("activity.senders", new SendersBinder(m));
1163 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1164 ServiceManager.addService("permission", new PermissionController(m));
1165
1166 ApplicationInfo info =
1167 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001168 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 synchronized (mSelf) {
1170 ProcessRecord app = mSelf.newProcessRecordLocked(
1171 mSystemThread.getApplicationThread(), info,
1172 info.processName);
1173 app.persistent = true;
1174 app.pid = Process.myPid();
1175 app.maxAdj = SYSTEM_ADJ;
1176 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1177 synchronized (mSelf.mPidsSelfLocked) {
1178 mSelf.mPidsSelfLocked.put(app.pid, app);
1179 }
1180 mSelf.updateLRUListLocked(app, true);
1181 }
1182 } catch (PackageManager.NameNotFoundException e) {
1183 throw new RuntimeException(
1184 "Unable to find android system package", e);
1185 }
1186 }
1187
1188 public void setWindowManager(WindowManagerService wm) {
1189 mWindowManager = wm;
1190 }
1191
1192 public static final Context main(int factoryTest) {
1193 AThread thr = new AThread();
1194 thr.start();
1195
1196 synchronized (thr) {
1197 while (thr.mService == null) {
1198 try {
1199 thr.wait();
1200 } catch (InterruptedException e) {
1201 }
1202 }
1203 }
1204
1205 ActivityManagerService m = thr.mService;
1206 mSelf = m;
1207 ActivityThread at = ActivityThread.systemMain();
1208 mSystemThread = at;
1209 Context context = at.getSystemContext();
1210 m.mContext = context;
1211 m.mFactoryTest = factoryTest;
1212 PowerManager pm =
1213 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1214 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1215 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1216 m.mLaunchingActivity.setReferenceCounted(false);
1217
1218 m.mBatteryStatsService.publish(context);
1219 m.mUsageStatsService.publish(context);
1220
1221 synchronized (thr) {
1222 thr.mReady = true;
1223 thr.notifyAll();
1224 }
1225
1226 m.startRunning(null, null, null, null);
1227
1228 return context;
1229 }
1230
1231 public static ActivityManagerService self() {
1232 return mSelf;
1233 }
1234
1235 static class AThread extends Thread {
1236 ActivityManagerService mService;
1237 boolean mReady = false;
1238
1239 public AThread() {
1240 super("ActivityManager");
1241 }
1242
1243 public void run() {
1244 Looper.prepare();
1245
1246 android.os.Process.setThreadPriority(
1247 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1248
1249 ActivityManagerService m = new ActivityManagerService();
1250
1251 synchronized (this) {
1252 mService = m;
1253 notifyAll();
1254 }
1255
1256 synchronized (this) {
1257 while (!mReady) {
1258 try {
1259 wait();
1260 } catch (InterruptedException e) {
1261 }
1262 }
1263 }
1264
1265 Looper.loop();
1266 }
1267 }
1268
1269 static class BroadcastsBinder extends Binder {
1270 ActivityManagerService mActivityManagerService;
1271 BroadcastsBinder(ActivityManagerService activityManagerService) {
1272 mActivityManagerService = activityManagerService;
1273 }
1274
1275 @Override
1276 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1277 mActivityManagerService.dumpBroadcasts(pw);
1278 }
1279 }
1280
1281 static class ServicesBinder extends Binder {
1282 ActivityManagerService mActivityManagerService;
1283 ServicesBinder(ActivityManagerService activityManagerService) {
1284 mActivityManagerService = activityManagerService;
1285 }
1286
1287 @Override
1288 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1289 mActivityManagerService.dumpServices(pw);
1290 }
1291 }
1292
1293 static class SendersBinder extends Binder {
1294 ActivityManagerService mActivityManagerService;
1295 SendersBinder(ActivityManagerService activityManagerService) {
1296 mActivityManagerService = activityManagerService;
1297 }
1298
1299 @Override
1300 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1301 mActivityManagerService.dumpSenders(pw);
1302 }
1303 }
1304
1305 static class ProvidersBinder extends Binder {
1306 ActivityManagerService mActivityManagerService;
1307 ProvidersBinder(ActivityManagerService activityManagerService) {
1308 mActivityManagerService = activityManagerService;
1309 }
1310
1311 @Override
1312 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1313 mActivityManagerService.dumpProviders(pw);
1314 }
1315 }
1316
1317 static class MemBinder extends Binder {
1318 ActivityManagerService mActivityManagerService;
1319 MemBinder(ActivityManagerService activityManagerService) {
1320 mActivityManagerService = activityManagerService;
1321 }
1322
1323 @Override
1324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1325 ActivityManagerService service = mActivityManagerService;
1326 ArrayList<ProcessRecord> procs;
1327 synchronized (mActivityManagerService) {
1328 if (args != null && args.length > 0
1329 && args[0].charAt(0) != '-') {
1330 procs = new ArrayList<ProcessRecord>();
1331 int pid = -1;
1332 try {
1333 pid = Integer.parseInt(args[0]);
1334 } catch (NumberFormatException e) {
1335
1336 }
1337 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1338 ProcessRecord proc = service.mLRUProcesses.get(i);
1339 if (proc.pid == pid) {
1340 procs.add(proc);
1341 } else if (proc.processName.equals(args[0])) {
1342 procs.add(proc);
1343 }
1344 }
1345 if (procs.size() <= 0) {
1346 pw.println("No process found for: " + args[0]);
1347 return;
1348 }
1349 } else {
1350 procs = service.mLRUProcesses;
1351 }
1352 }
1353 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1354 }
1355 }
1356
1357 static class CpuBinder extends Binder {
1358 ActivityManagerService mActivityManagerService;
1359 CpuBinder(ActivityManagerService activityManagerService) {
1360 mActivityManagerService = activityManagerService;
1361 }
1362
1363 @Override
1364 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1365 synchronized (mActivityManagerService.mProcessStatsThread) {
1366 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1367 }
1368 }
1369 }
1370
1371 private ActivityManagerService() {
1372 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1373 if (v != null && Integer.getInteger(v) != 0) {
1374 mSimpleProcessManagement = true;
1375 }
1376 v = System.getenv("ANDROID_DEBUG_APP");
1377 if (v != null) {
1378 mSimpleProcessManagement = true;
1379 }
1380
1381 MY_PID = Process.myPid();
1382
1383 File dataDir = Environment.getDataDirectory();
1384 File systemDir = new File(dataDir, "system");
1385 systemDir.mkdirs();
1386 mBatteryStatsService = new BatteryStatsService(new File(
1387 systemDir, "batterystats.bin").toString());
1388 mBatteryStatsService.getActiveStatistics().readLocked();
1389 mBatteryStatsService.getActiveStatistics().writeLocked();
1390
1391 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001392 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393
1394 mConfiguration.makeDefault();
1395 mProcessStats.init();
1396
1397 // Add ourself to the Watchdog monitors.
1398 Watchdog.getInstance().addMonitor(this);
1399
1400 // These values are set in system/rootdir/init.rc on startup.
1401 FOREGROUND_APP_ADJ =
1402 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1403 VISIBLE_APP_ADJ =
1404 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1405 SECONDARY_SERVER_ADJ =
1406 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001407 BACKUP_APP_ADJ =
1408 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001409 HOME_APP_ADJ =
1410 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 HIDDEN_APP_MIN_ADJ =
1412 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1413 CONTENT_PROVIDER_ADJ =
1414 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1415 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1416 EMPTY_APP_ADJ =
1417 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1418 FOREGROUND_APP_MEM =
1419 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1420 VISIBLE_APP_MEM =
1421 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1422 SECONDARY_SERVER_MEM =
1423 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001424 BACKUP_APP_MEM =
1425 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001426 HOME_APP_MEM =
1427 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 HIDDEN_APP_MEM =
1429 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1430 EMPTY_APP_MEM =
1431 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1432
1433 mProcessStatsThread = new Thread("ProcessStats") {
1434 public void run() {
1435 while (true) {
1436 try {
1437 try {
1438 synchronized(this) {
1439 final long now = SystemClock.uptimeMillis();
1440 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1441 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1442 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1443 // + ", write delay=" + nextWriteDelay);
1444 if (nextWriteDelay < nextCpuDelay) {
1445 nextCpuDelay = nextWriteDelay;
1446 }
1447 if (nextCpuDelay > 0) {
1448 this.wait(nextCpuDelay);
1449 }
1450 }
1451 } catch (InterruptedException e) {
1452 }
1453
1454 updateCpuStatsNow();
1455 } catch (Exception e) {
1456 Log.e(TAG, "Unexpected exception collecting process stats", e);
1457 }
1458 }
1459 }
1460 };
1461 mProcessStatsThread.start();
1462 }
1463
1464 @Override
1465 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1466 throws RemoteException {
1467 try {
1468 return super.onTransact(code, data, reply, flags);
1469 } catch (RuntimeException e) {
1470 // The activity manager only throws security exceptions, so let's
1471 // log all others.
1472 if (!(e instanceof SecurityException)) {
1473 Log.e(TAG, "Activity Manager Crash", e);
1474 }
1475 throw e;
1476 }
1477 }
1478
1479 void updateCpuStats() {
1480 synchronized (mProcessStatsThread) {
1481 final long now = SystemClock.uptimeMillis();
1482 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1483 mProcessStatsThread.notify();
1484 }
1485 }
1486 }
1487
1488 void updateCpuStatsNow() {
1489 synchronized (mProcessStatsThread) {
1490 final long now = SystemClock.uptimeMillis();
1491 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 if (MONITOR_CPU_USAGE &&
1494 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1495 mLastCpuTime = now;
1496 haveNewCpuStats = true;
1497 mProcessStats.update();
1498 //Log.i(TAG, mProcessStats.printCurrentState());
1499 //Log.i(TAG, "Total CPU usage: "
1500 // + mProcessStats.getTotalCpuPercent() + "%");
1501
1502 // Log the cpu usage if the property is set.
1503 if ("true".equals(SystemProperties.get("events.cpu"))) {
1504 int user = mProcessStats.getLastUserTime();
1505 int system = mProcessStats.getLastSystemTime();
1506 int iowait = mProcessStats.getLastIoWaitTime();
1507 int irq = mProcessStats.getLastIrqTime();
1508 int softIrq = mProcessStats.getLastSoftIrqTime();
1509 int idle = mProcessStats.getLastIdleTime();
1510
1511 int total = user + system + iowait + irq + softIrq + idle;
1512 if (total == 0) total = 1;
1513
1514 EventLog.writeEvent(LOG_CPU,
1515 ((user+system+iowait+irq+softIrq) * 100) / total,
1516 (user * 100) / total,
1517 (system * 100) / total,
1518 (iowait * 100) / total,
1519 (irq * 100) / total,
1520 (softIrq * 100) / total);
1521 }
1522 }
1523
Amith Yamasani819f9282009-06-24 23:18:15 -07001524 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001525 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 synchronized(mPidsSelfLocked) {
1527 if (haveNewCpuStats) {
1528 if (mBatteryStatsService.isOnBattery()) {
1529 final int N = mProcessStats.countWorkingStats();
1530 for (int i=0; i<N; i++) {
1531 ProcessStats.Stats st
1532 = mProcessStats.getWorkingStats(i);
1533 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1534 if (pr != null) {
1535 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1536 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001537 } else {
1538 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001539 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001540 if (ps != null) {
1541 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
1544 }
1545 }
1546 }
1547 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1550 mLastWriteTime = now;
1551 mBatteryStatsService.getActiveStatistics().writeLocked();
1552 }
1553 }
1554 }
1555 }
1556
1557 /**
1558 * Initialize the application bind args. These are passed to each
1559 * process when the bindApplication() IPC is sent to the process. They're
1560 * lazily setup to make sure the services are running when they're asked for.
1561 */
1562 private HashMap<String, IBinder> getCommonServicesLocked() {
1563 if (mAppBindArgs == null) {
1564 mAppBindArgs = new HashMap<String, IBinder>();
1565
1566 // Setup the application init args
1567 mAppBindArgs.put("package", ServiceManager.getService("package"));
1568 mAppBindArgs.put("window", ServiceManager.getService("window"));
1569 mAppBindArgs.put(Context.ALARM_SERVICE,
1570 ServiceManager.getService(Context.ALARM_SERVICE));
1571 }
1572 return mAppBindArgs;
1573 }
1574
1575 private final void setFocusedActivityLocked(HistoryRecord r) {
1576 if (mFocusedActivity != r) {
1577 mFocusedActivity = r;
1578 mWindowManager.setFocusedApp(r, true);
1579 }
1580 }
1581
1582 private final void updateLRUListLocked(ProcessRecord app,
1583 boolean oomAdj) {
1584 // put it on the LRU to keep track of when it should be exited.
1585 int lrui = mLRUProcesses.indexOf(app);
1586 if (lrui >= 0) mLRUProcesses.remove(lrui);
1587 mLRUProcesses.add(app);
1588 //Log.i(TAG, "Putting proc to front: " + app.processName);
1589 if (oomAdj) {
1590 updateOomAdjLocked();
1591 }
1592 }
1593
1594 private final boolean updateLRUListLocked(HistoryRecord r) {
1595 final boolean hadit = mLRUActivities.remove(r);
1596 mLRUActivities.add(r);
1597 return hadit;
1598 }
1599
1600 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1601 int i = mHistory.size()-1;
1602 while (i >= 0) {
1603 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1604 if (!r.finishing && r != notTop) {
1605 return r;
1606 }
1607 i--;
1608 }
1609 return null;
1610 }
1611
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001612 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1613 int i = mHistory.size()-1;
1614 while (i >= 0) {
1615 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1616 if (!r.finishing && !r.delayedResume && r != notTop) {
1617 return r;
1618 }
1619 i--;
1620 }
1621 return null;
1622 }
1623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 /**
1625 * This is a simplified version of topRunningActivityLocked that provides a number of
1626 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1627 *
1628 * @param token If non-null, any history records matching this token will be skipped.
1629 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1630 *
1631 * @return Returns the HistoryRecord of the next activity on the stack.
1632 */
1633 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1634 int i = mHistory.size()-1;
1635 while (i >= 0) {
1636 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1637 // Note: the taskId check depends on real taskId fields being non-zero
1638 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1639 return r;
1640 }
1641 i--;
1642 }
1643 return null;
1644 }
1645
1646 private final ProcessRecord getProcessRecordLocked(
1647 String processName, int uid) {
1648 if (uid == Process.SYSTEM_UID) {
1649 // The system gets to run in any process. If there are multiple
1650 // processes with the same uid, just pick the first (this
1651 // should never happen).
1652 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1653 processName);
1654 return procs != null ? procs.valueAt(0) : null;
1655 }
1656 ProcessRecord proc = mProcessNames.get(processName, uid);
1657 return proc;
1658 }
1659
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001660 private void ensurePackageDexOpt(String packageName) {
1661 IPackageManager pm = ActivityThread.getPackageManager();
1662 try {
1663 if (pm.performDexOpt(packageName)) {
1664 mDidDexOpt = true;
1665 }
1666 } catch (RemoteException e) {
1667 }
1668 }
1669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 private boolean isNextTransitionForward() {
1671 int transit = mWindowManager.getPendingAppTransition();
1672 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1673 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1674 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1675 }
1676
1677 private final boolean realStartActivityLocked(HistoryRecord r,
1678 ProcessRecord app, boolean andResume, boolean checkConfig)
1679 throws RemoteException {
1680
1681 r.startFreezingScreenLocked(app, 0);
1682 mWindowManager.setAppVisibility(r, true);
1683
1684 // Have the window manager re-evaluate the orientation of
1685 // the screen based on the new activity order. Note that
1686 // as a result of this, it can call back into the activity
1687 // manager with a new orientation. We don't care about that,
1688 // because the activity is not currently running so we are
1689 // just restarting it anyway.
1690 if (checkConfig) {
1691 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001692 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 r.mayFreezeScreenLocked(app) ? r : null);
1694 updateConfigurationLocked(config, r);
1695 }
1696
1697 r.app = app;
1698
1699 if (localLOGV) Log.v(TAG, "Launching: " + r);
1700
1701 int idx = app.activities.indexOf(r);
1702 if (idx < 0) {
1703 app.activities.add(r);
1704 }
1705 updateLRUListLocked(app, true);
1706
1707 try {
1708 if (app.thread == null) {
1709 throw new RemoteException();
1710 }
1711 List<ResultInfo> results = null;
1712 List<Intent> newIntents = null;
1713 if (andResume) {
1714 results = r.results;
1715 newIntents = r.newIntents;
1716 }
1717 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1718 + " icicle=" + r.icicle
1719 + " with results=" + results + " newIntents=" + newIntents
1720 + " andResume=" + andResume);
1721 if (andResume) {
1722 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1723 System.identityHashCode(r),
1724 r.task.taskId, r.shortComponentName);
1725 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001726 if (r.isHomeActivity) {
1727 mHomeProcess = app;
1728 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001729 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1731 r.info, r.icicle, results, newIntents, !andResume,
1732 isNextTransitionForward());
1733 // Update usage stats for launched activity
1734 updateUsageStats(r, true);
1735 } catch (RemoteException e) {
1736 if (r.launchFailed) {
1737 // This is the second time we failed -- finish activity
1738 // and give up.
1739 Log.e(TAG, "Second failure launching "
1740 + r.intent.getComponent().flattenToShortString()
1741 + ", giving up", e);
1742 appDiedLocked(app, app.pid, app.thread);
1743 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1744 "2nd-crash");
1745 return false;
1746 }
1747
1748 // This is the first time we failed -- restart process and
1749 // retry.
1750 app.activities.remove(r);
1751 throw e;
1752 }
1753
1754 r.launchFailed = false;
1755 if (updateLRUListLocked(r)) {
1756 Log.w(TAG, "Activity " + r
1757 + " being launched, but already in LRU list");
1758 }
1759
1760 if (andResume) {
1761 // As part of the process of launching, ActivityThread also performs
1762 // a resume.
1763 r.state = ActivityState.RESUMED;
1764 r.icicle = null;
1765 r.haveState = false;
1766 r.stopped = false;
1767 mResumedActivity = r;
1768 r.task.touchActiveTime();
1769 completeResumeLocked(r);
1770 pauseIfSleepingLocked();
1771 } else {
1772 // This activity is not starting in the resumed state... which
1773 // should look like we asked it to pause+stop (but remain visible),
1774 // and it has done so and reported back the current icicle and
1775 // other state.
1776 r.state = ActivityState.STOPPED;
1777 r.stopped = true;
1778 }
1779
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001780 // Launch the new version setup screen if needed. We do this -after-
1781 // launching the initial activity (that is, home), so that it can have
1782 // a chance to initialize itself while in the background, making the
1783 // switch back to it faster and look better.
1784 startSetupActivityLocked();
1785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 return true;
1787 }
1788
1789 private final void startSpecificActivityLocked(HistoryRecord r,
1790 boolean andResume, boolean checkConfig) {
1791 // Is this activity's application already running?
1792 ProcessRecord app = getProcessRecordLocked(r.processName,
1793 r.info.applicationInfo.uid);
1794
1795 if (r.startTime == 0) {
1796 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001797 if (mInitialStartTime == 0) {
1798 mInitialStartTime = r.startTime;
1799 }
1800 } else if (mInitialStartTime == 0) {
1801 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 }
1803
1804 if (app != null && app.thread != null) {
1805 try {
1806 realStartActivityLocked(r, app, andResume, checkConfig);
1807 return;
1808 } catch (RemoteException e) {
1809 Log.w(TAG, "Exception when starting activity "
1810 + r.intent.getComponent().flattenToShortString(), e);
1811 }
1812
1813 // If a dead object exception was thrown -- fall through to
1814 // restart the application.
1815 }
1816
1817 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1818 "activity", r.intent.getComponent());
1819 }
1820
1821 private final ProcessRecord startProcessLocked(String processName,
1822 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1823 String hostingType, ComponentName hostingName) {
1824 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1825 // We don't have to do anything more if:
1826 // (1) There is an existing application record; and
1827 // (2) The caller doesn't think it is dead, OR there is no thread
1828 // object attached to it so we know it couldn't have crashed; and
1829 // (3) There is a pid assigned to it, so it is either starting or
1830 // already running.
1831 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1832 + " app=" + app + " knownToBeDead=" + knownToBeDead
1833 + " thread=" + (app != null ? app.thread : null)
1834 + " pid=" + (app != null ? app.pid : -1));
1835 if (app != null &&
1836 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1837 return app;
1838 }
1839
1840 String hostingNameStr = hostingName != null
1841 ? hostingName.flattenToShortString() : null;
1842
1843 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1844 // If we are in the background, then check to see if this process
1845 // is bad. If so, we will just silently fail.
1846 if (mBadProcesses.get(info.processName, info.uid) != null) {
1847 return null;
1848 }
1849 } else {
1850 // When the user is explicitly starting a process, then clear its
1851 // crash count so that we won't make it bad until they see at
1852 // least one crash dialog again, and make the process good again
1853 // if it had been bad.
1854 mProcessCrashTimes.remove(info.processName, info.uid);
1855 if (mBadProcesses.get(info.processName, info.uid) != null) {
1856 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1857 info.processName);
1858 mBadProcesses.remove(info.processName, info.uid);
1859 if (app != null) {
1860 app.bad = false;
1861 }
1862 }
1863 }
1864
1865 if (app == null) {
1866 app = newProcessRecordLocked(null, info, processName);
1867 mProcessNames.put(processName, info.uid, app);
1868 } else {
1869 // If this is a new package in the process, add the package to the list
1870 app.addPackage(info.packageName);
1871 }
1872
1873 // If the system is not ready yet, then hold off on starting this
1874 // process until it is.
1875 if (!mSystemReady
1876 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1877 if (!mProcessesOnHold.contains(app)) {
1878 mProcessesOnHold.add(app);
1879 }
1880 return app;
1881 }
1882
1883 startProcessLocked(app, hostingType, hostingNameStr);
1884 return (app.pid != 0) ? app : null;
1885 }
1886
1887 private final void startProcessLocked(ProcessRecord app,
1888 String hostingType, String hostingNameStr) {
1889 if (app.pid > 0 && app.pid != MY_PID) {
1890 synchronized (mPidsSelfLocked) {
1891 mPidsSelfLocked.remove(app.pid);
1892 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1893 }
1894 app.pid = 0;
1895 }
1896
1897 mProcessesOnHold.remove(app);
1898
1899 updateCpuStats();
1900
1901 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1902 mProcDeaths[0] = 0;
1903
1904 try {
1905 int uid = app.info.uid;
1906 int[] gids = null;
1907 try {
1908 gids = mContext.getPackageManager().getPackageGids(
1909 app.info.packageName);
1910 } catch (PackageManager.NameNotFoundException e) {
1911 Log.w(TAG, "Unable to retrieve gids", e);
1912 }
1913 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1914 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1915 && mTopComponent != null
1916 && app.processName.equals(mTopComponent.getPackageName())) {
1917 uid = 0;
1918 }
1919 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1920 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1921 uid = 0;
1922 }
1923 }
1924 int debugFlags = 0;
1925 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1926 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1927 }
1928 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1929 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1930 }
1931 if ("1".equals(SystemProperties.get("debug.assert"))) {
1932 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1933 }
1934 int pid = Process.start("android.app.ActivityThread",
1935 mSimpleProcessManagement ? app.processName : null, uid, uid,
1936 gids, debugFlags, null);
1937 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1938 synchronized (bs) {
1939 if (bs.isOnBattery()) {
1940 app.batteryStats.incStartsLocked();
1941 }
1942 }
1943
1944 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1945 app.processName, hostingType,
1946 hostingNameStr != null ? hostingNameStr : "");
1947
1948 if (app.persistent) {
1949 Watchdog.getInstance().processStarted(app, app.processName, pid);
1950 }
1951
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001952 StringBuilder buf = mStringBuilder;
1953 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 buf.append("Start proc ");
1955 buf.append(app.processName);
1956 buf.append(" for ");
1957 buf.append(hostingType);
1958 if (hostingNameStr != null) {
1959 buf.append(" ");
1960 buf.append(hostingNameStr);
1961 }
1962 buf.append(": pid=");
1963 buf.append(pid);
1964 buf.append(" uid=");
1965 buf.append(uid);
1966 buf.append(" gids={");
1967 if (gids != null) {
1968 for (int gi=0; gi<gids.length; gi++) {
1969 if (gi != 0) buf.append(", ");
1970 buf.append(gids[gi]);
1971
1972 }
1973 }
1974 buf.append("}");
1975 Log.i(TAG, buf.toString());
1976 if (pid == 0 || pid == MY_PID) {
1977 // Processes are being emulated with threads.
1978 app.pid = MY_PID;
1979 app.removed = false;
1980 mStartingProcesses.add(app);
1981 } else if (pid > 0) {
1982 app.pid = pid;
1983 app.removed = false;
1984 synchronized (mPidsSelfLocked) {
1985 this.mPidsSelfLocked.put(pid, app);
1986 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1987 msg.obj = app;
1988 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1989 }
1990 } else {
1991 app.pid = 0;
1992 RuntimeException e = new RuntimeException(
1993 "Failure starting process " + app.processName
1994 + ": returned pid=" + pid);
1995 Log.e(TAG, e.getMessage(), e);
1996 }
1997 } catch (RuntimeException e) {
1998 // XXX do better error recovery.
1999 app.pid = 0;
2000 Log.e(TAG, "Failure starting process " + app.processName, e);
2001 }
2002 }
2003
2004 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2005 if (mPausingActivity != null) {
2006 RuntimeException e = new RuntimeException();
2007 Log.e(TAG, "Trying to pause when pause is already pending for "
2008 + mPausingActivity, e);
2009 }
2010 HistoryRecord prev = mResumedActivity;
2011 if (prev == null) {
2012 RuntimeException e = new RuntimeException();
2013 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2014 resumeTopActivityLocked(null);
2015 return;
2016 }
2017 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2018 mResumedActivity = null;
2019 mPausingActivity = prev;
2020 mLastPausedActivity = prev;
2021 prev.state = ActivityState.PAUSING;
2022 prev.task.touchActiveTime();
2023
2024 updateCpuStats();
2025
2026 if (prev.app != null && prev.app.thread != null) {
2027 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2028 try {
2029 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2030 System.identityHashCode(prev),
2031 prev.shortComponentName);
2032 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2033 prev.configChangeFlags);
2034 updateUsageStats(prev, false);
2035 } catch (Exception e) {
2036 // Ignore exception, if process died other code will cleanup.
2037 Log.w(TAG, "Exception thrown during pause", e);
2038 mPausingActivity = null;
2039 mLastPausedActivity = null;
2040 }
2041 } else {
2042 mPausingActivity = null;
2043 mLastPausedActivity = null;
2044 }
2045
2046 // If we are not going to sleep, we want to ensure the device is
2047 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002048 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 mLaunchingActivity.acquire();
2050 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2051 // To be safe, don't allow the wake lock to be held for too long.
2052 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2053 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2054 }
2055 }
2056
2057
2058 if (mPausingActivity != null) {
2059 // Have the window manager pause its key dispatching until the new
2060 // activity has started. If we're pausing the activity just because
2061 // the screen is being turned off and the UI is sleeping, don't interrupt
2062 // key dispatch; the same activity will pick it up again on wakeup.
2063 if (!uiSleeping) {
2064 prev.pauseKeyDispatchingLocked();
2065 } else {
2066 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2067 }
2068
2069 // Schedule a pause timeout in case the app doesn't respond.
2070 // We don't give it much time because this directly impacts the
2071 // responsiveness seen by the user.
2072 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2073 msg.obj = prev;
2074 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2075 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2076 } else {
2077 // This activity failed to schedule the
2078 // pause, so just treat it as being paused now.
2079 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2080 resumeTopActivityLocked(null);
2081 }
2082 }
2083
2084 private final void completePauseLocked() {
2085 HistoryRecord prev = mPausingActivity;
2086 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2087
2088 if (prev != null) {
2089 if (prev.finishing) {
2090 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2091 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2092 } else if (prev.app != null) {
2093 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2094 if (prev.waitingVisible) {
2095 prev.waitingVisible = false;
2096 mWaitingVisibleActivities.remove(prev);
2097 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2098 TAG, "Complete pause, no longer waiting: " + prev);
2099 }
2100 if (prev.configDestroy) {
2101 // The previous is being paused because the configuration
2102 // is changing, which means it is actually stopping...
2103 // To juggle the fact that we are also starting a new
2104 // instance right now, we need to first completely stop
2105 // the current instance before starting the new one.
2106 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2107 destroyActivityLocked(prev, true);
2108 } else {
2109 mStoppingActivities.add(prev);
2110 if (mStoppingActivities.size() > 3) {
2111 // If we already have a few activities waiting to stop,
2112 // then give up on things going idle and start clearing
2113 // them out.
2114 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2115 Message msg = Message.obtain();
2116 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2117 mHandler.sendMessage(msg);
2118 }
2119 }
2120 } else {
2121 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2122 prev = null;
2123 }
2124 mPausingActivity = null;
2125 }
2126
Dianne Hackborn55280a92009-05-07 15:53:46 -07002127 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 resumeTopActivityLocked(prev);
2129 } else {
2130 if (mGoingToSleep.isHeld()) {
2131 mGoingToSleep.release();
2132 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002133 if (mShuttingDown) {
2134 notifyAll();
2135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 }
2137
2138 if (prev != null) {
2139 prev.resumeKeyDispatchingLocked();
2140 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002141
2142 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2143 long diff = 0;
2144 synchronized (mProcessStatsThread) {
2145 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2146 }
2147 if (diff > 0) {
2148 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2149 synchronized (bsi) {
2150 BatteryStatsImpl.Uid.Proc ps =
2151 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2152 prev.info.packageName);
2153 if (ps != null) {
2154 ps.addForegroundTimeLocked(diff);
2155 }
2156 }
2157 }
2158 }
2159 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 /**
2163 * Once we know that we have asked an application to put an activity in
2164 * the resumed state (either by launching it or explicitly telling it),
2165 * this function updates the rest of our state to match that fact.
2166 */
2167 private final void completeResumeLocked(HistoryRecord next) {
2168 next.idle = false;
2169 next.results = null;
2170 next.newIntents = null;
2171
2172 // schedule an idle timeout in case the app doesn't do it for us.
2173 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2174 msg.obj = next;
2175 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2176
2177 if (false) {
2178 // The activity was never told to pause, so just keep
2179 // things going as-is. To maintain our own state,
2180 // we need to emulate it coming back and saying it is
2181 // idle.
2182 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2183 msg.obj = next;
2184 mHandler.sendMessage(msg);
2185 }
2186
2187 next.thumbnail = null;
2188 setFocusedActivityLocked(next);
2189 next.resumeKeyDispatchingLocked();
2190 ensureActivitiesVisibleLocked(null, 0);
2191 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002192
2193 // Mark the point when the activity is resuming
2194 // TODO: To be more accurate, the mark should be before the onCreate,
2195 // not after the onResume. But for subsequent starts, onResume is fine.
2196 if (next.app != null) {
2197 synchronized (mProcessStatsThread) {
2198 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2199 }
2200 } else {
2201 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
2204
2205 /**
2206 * Make sure that all activities that need to be visible (that is, they
2207 * currently can be seen by the user) actually are.
2208 */
2209 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2210 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2211 if (DEBUG_VISBILITY) Log.v(
2212 TAG, "ensureActivitiesVisible behind " + top
2213 + " configChanges=0x" + Integer.toHexString(configChanges));
2214
2215 // If the top activity is not fullscreen, then we need to
2216 // make sure any activities under it are now visible.
2217 final int count = mHistory.size();
2218 int i = count-1;
2219 while (mHistory.get(i) != top) {
2220 i--;
2221 }
2222 HistoryRecord r;
2223 boolean behindFullscreen = false;
2224 for (; i>=0; i--) {
2225 r = (HistoryRecord)mHistory.get(i);
2226 if (DEBUG_VISBILITY) Log.v(
2227 TAG, "Make visible? " + r + " finishing=" + r.finishing
2228 + " state=" + r.state);
2229 if (r.finishing) {
2230 continue;
2231 }
2232
2233 final boolean doThisProcess = onlyThisProcess == null
2234 || onlyThisProcess.equals(r.processName);
2235
2236 // First: if this is not the current activity being started, make
2237 // sure it matches the current configuration.
2238 if (r != starting && doThisProcess) {
2239 ensureActivityConfigurationLocked(r, 0);
2240 }
2241
2242 if (r.app == null || r.app.thread == null) {
2243 if (onlyThisProcess == null
2244 || onlyThisProcess.equals(r.processName)) {
2245 // This activity needs to be visible, but isn't even
2246 // running... get it started, but don't resume it
2247 // at this point.
2248 if (DEBUG_VISBILITY) Log.v(
2249 TAG, "Start and freeze screen for " + r);
2250 if (r != starting) {
2251 r.startFreezingScreenLocked(r.app, configChanges);
2252 }
2253 if (!r.visible) {
2254 if (DEBUG_VISBILITY) Log.v(
2255 TAG, "Starting and making visible: " + r);
2256 mWindowManager.setAppVisibility(r, true);
2257 }
2258 if (r != starting) {
2259 startSpecificActivityLocked(r, false, false);
2260 }
2261 }
2262
2263 } else if (r.visible) {
2264 // If this activity is already visible, then there is nothing
2265 // else to do here.
2266 if (DEBUG_VISBILITY) Log.v(
2267 TAG, "Skipping: already visible at " + r);
2268 r.stopFreezingScreenLocked(false);
2269
2270 } else if (onlyThisProcess == null) {
2271 // This activity is not currently visible, but is running.
2272 // Tell it to become visible.
2273 r.visible = true;
2274 if (r.state != ActivityState.RESUMED && r != starting) {
2275 // If this activity is paused, tell it
2276 // to now show its window.
2277 if (DEBUG_VISBILITY) Log.v(
2278 TAG, "Making visible and scheduling visibility: " + r);
2279 try {
2280 mWindowManager.setAppVisibility(r, true);
2281 r.app.thread.scheduleWindowVisibility(r, true);
2282 r.stopFreezingScreenLocked(false);
2283 } catch (Exception e) {
2284 // Just skip on any failure; we'll make it
2285 // visible when it next restarts.
2286 Log.w(TAG, "Exception thrown making visibile: "
2287 + r.intent.getComponent(), e);
2288 }
2289 }
2290 }
2291
2292 // Aggregate current change flags.
2293 configChanges |= r.configChangeFlags;
2294
2295 if (r.fullscreen) {
2296 // At this point, nothing else needs to be shown
2297 if (DEBUG_VISBILITY) Log.v(
2298 TAG, "Stopping: fullscreen at " + r);
2299 behindFullscreen = true;
2300 i--;
2301 break;
2302 }
2303 }
2304
2305 // Now for any activities that aren't visible to the user, make
2306 // sure they no longer are keeping the screen frozen.
2307 while (i >= 0) {
2308 r = (HistoryRecord)mHistory.get(i);
2309 if (DEBUG_VISBILITY) Log.v(
2310 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2311 + " state=" + r.state
2312 + " behindFullscreen=" + behindFullscreen);
2313 if (!r.finishing) {
2314 if (behindFullscreen) {
2315 if (r.visible) {
2316 if (DEBUG_VISBILITY) Log.v(
2317 TAG, "Making invisible: " + r);
2318 r.visible = false;
2319 try {
2320 mWindowManager.setAppVisibility(r, false);
2321 if ((r.state == ActivityState.STOPPING
2322 || r.state == ActivityState.STOPPED)
2323 && r.app != null && r.app.thread != null) {
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Scheduling invisibility: " + r);
2326 r.app.thread.scheduleWindowVisibility(r, false);
2327 }
2328 } catch (Exception e) {
2329 // Just skip on any failure; we'll make it
2330 // visible when it next restarts.
2331 Log.w(TAG, "Exception thrown making hidden: "
2332 + r.intent.getComponent(), e);
2333 }
2334 } else {
2335 if (DEBUG_VISBILITY) Log.v(
2336 TAG, "Already invisible: " + r);
2337 }
2338 } else if (r.fullscreen) {
2339 if (DEBUG_VISBILITY) Log.v(
2340 TAG, "Now behindFullscreen: " + r);
2341 behindFullscreen = true;
2342 }
2343 }
2344 i--;
2345 }
2346 }
2347
2348 /**
2349 * Version of ensureActivitiesVisible that can easily be called anywhere.
2350 */
2351 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2352 int configChanges) {
2353 HistoryRecord r = topRunningActivityLocked(null);
2354 if (r != null) {
2355 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2356 }
2357 }
2358
2359 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2360 if (resumed) {
2361 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2362 } else {
2363 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2364 }
2365 }
2366
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002367 private boolean startHomeActivityLocked() {
2368 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2369 && mTopAction == null) {
2370 // We are running in factory test mode, but unable to find
2371 // the factory test app, so just sit around displaying the
2372 // error message and don't try to start anything.
2373 return false;
2374 }
2375 Intent intent = new Intent(
2376 mTopAction,
2377 mTopData != null ? Uri.parse(mTopData) : null);
2378 intent.setComponent(mTopComponent);
2379 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2380 intent.addCategory(Intent.CATEGORY_HOME);
2381 }
2382 ActivityInfo aInfo =
2383 intent.resolveActivityInfo(mContext.getPackageManager(),
2384 STOCK_PM_FLAGS);
2385 if (aInfo != null) {
2386 intent.setComponent(new ComponentName(
2387 aInfo.applicationInfo.packageName, aInfo.name));
2388 // Don't do this if the home app is currently being
2389 // instrumented.
2390 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2391 aInfo.applicationInfo.uid);
2392 if (app == null || app.instrumentationClass == null) {
2393 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2394 startActivityLocked(null, intent, null, null, 0, aInfo,
2395 null, null, 0, 0, 0, false, false);
2396 }
2397 }
2398
2399
2400 return true;
2401 }
2402
2403 /**
2404 * Starts the "new version setup screen" if appropriate.
2405 */
2406 private void startSetupActivityLocked() {
2407 // Only do this once per boot.
2408 if (mCheckedForSetup) {
2409 return;
2410 }
2411
2412 // We will show this screen if the current one is a different
2413 // version than the last one shown, and we are not running in
2414 // low-level factory test mode.
2415 final ContentResolver resolver = mContext.getContentResolver();
2416 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2417 Settings.Secure.getInt(resolver,
2418 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2419 mCheckedForSetup = true;
2420
2421 // See if we should be showing the platform update setup UI.
2422 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2423 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2424 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2425
2426 // We don't allow third party apps to replace this.
2427 ResolveInfo ri = null;
2428 for (int i=0; ris != null && i<ris.size(); i++) {
2429 if ((ris.get(i).activityInfo.applicationInfo.flags
2430 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2431 ri = ris.get(i);
2432 break;
2433 }
2434 }
2435
2436 if (ri != null) {
2437 String vers = ri.activityInfo.metaData != null
2438 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2439 : null;
2440 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2441 vers = ri.activityInfo.applicationInfo.metaData.getString(
2442 Intent.METADATA_SETUP_VERSION);
2443 }
2444 String lastVers = Settings.Secure.getString(
2445 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2446 if (vers != null && !vers.equals(lastVers)) {
2447 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2448 intent.setComponent(new ComponentName(
2449 ri.activityInfo.packageName, ri.activityInfo.name));
2450 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2451 null, null, 0, 0, 0, false, false);
2452 }
2453 }
2454 }
2455 }
2456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 /**
2458 * Ensure that the top activity in the stack is resumed.
2459 *
2460 * @param prev The previously resumed activity, for when in the process
2461 * of pausing; can be null to call from elsewhere.
2462 *
2463 * @return Returns true if something is being resumed, or false if
2464 * nothing happened.
2465 */
2466 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2467 // Find the first activity that is not finishing.
2468 HistoryRecord next = topRunningActivityLocked(null);
2469
2470 // Remember how we'll process this pause/resume situation, and ensure
2471 // that the state is reset however we wind up proceeding.
2472 final boolean userLeaving = mUserLeaving;
2473 mUserLeaving = false;
2474
2475 if (next == null) {
2476 // There are no more activities! Let's just start up the
2477 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002478 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 }
2480
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002481 next.delayedResume = false;
2482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 // If the top activity is the resumed one, nothing to do.
2484 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2485 // Make sure we have executed any pending transitions, since there
2486 // should be nothing left to do at this point.
2487 mWindowManager.executeAppTransition();
2488 return false;
2489 }
2490
2491 // If we are sleeping, and there is no resumed activity, and the top
2492 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002493 if ((mSleeping || mShuttingDown)
2494 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002495 // Make sure we have executed any pending transitions, since there
2496 // should be nothing left to do at this point.
2497 mWindowManager.executeAppTransition();
2498 return false;
2499 }
2500
2501 // The activity may be waiting for stop, but that is no longer
2502 // appropriate for it.
2503 mStoppingActivities.remove(next);
2504 mWaitingVisibleActivities.remove(next);
2505
2506 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2507
2508 // If we are currently pausing an activity, then don't do anything
2509 // until that is done.
2510 if (mPausingActivity != null) {
2511 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2512 return false;
2513 }
2514
2515 // We need to start pausing the current activity so the top one
2516 // can be resumed...
2517 if (mResumedActivity != null) {
2518 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2519 startPausingLocked(userLeaving, false);
2520 return true;
2521 }
2522
2523 if (prev != null && prev != next) {
2524 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2525 prev.waitingVisible = true;
2526 mWaitingVisibleActivities.add(prev);
2527 if (DEBUG_SWITCH) Log.v(
2528 TAG, "Resuming top, waiting visible to hide: " + prev);
2529 } else {
2530 // The next activity is already visible, so hide the previous
2531 // activity's windows right now so we can show the new one ASAP.
2532 // We only do this if the previous is finishing, which should mean
2533 // it is on top of the one being resumed so hiding it quickly
2534 // is good. Otherwise, we want to do the normal route of allowing
2535 // the resumed activity to be shown so we can decide if the
2536 // previous should actually be hidden depending on whether the
2537 // new one is found to be full-screen or not.
2538 if (prev.finishing) {
2539 mWindowManager.setAppVisibility(prev, false);
2540 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2541 + prev + ", waitingVisible="
2542 + (prev != null ? prev.waitingVisible : null)
2543 + ", nowVisible=" + next.nowVisible);
2544 } else {
2545 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2546 + prev + ", waitingVisible="
2547 + (prev != null ? prev.waitingVisible : null)
2548 + ", nowVisible=" + next.nowVisible);
2549 }
2550 }
2551 }
2552
2553 // We are starting up the next activity, so tell the window manager
2554 // that the previous one will be hidden soon. This way it can know
2555 // to ignore it when computing the desired screen orientation.
2556 if (prev != null) {
2557 if (prev.finishing) {
2558 if (DEBUG_TRANSITION) Log.v(TAG,
2559 "Prepare close transition: prev=" + prev);
2560 mWindowManager.prepareAppTransition(prev.task == next.task
2561 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2562 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2563 mWindowManager.setAppWillBeHidden(prev);
2564 mWindowManager.setAppVisibility(prev, false);
2565 } else {
2566 if (DEBUG_TRANSITION) Log.v(TAG,
2567 "Prepare open transition: prev=" + prev);
2568 mWindowManager.prepareAppTransition(prev.task == next.task
2569 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2570 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2571 }
2572 if (false) {
2573 mWindowManager.setAppWillBeHidden(prev);
2574 mWindowManager.setAppVisibility(prev, false);
2575 }
2576 } else if (mHistory.size() > 1) {
2577 if (DEBUG_TRANSITION) Log.v(TAG,
2578 "Prepare open transition: no previous");
2579 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2580 }
2581
2582 if (next.app != null && next.app.thread != null) {
2583 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2584
2585 // This activity is now becoming visible.
2586 mWindowManager.setAppVisibility(next, true);
2587
2588 HistoryRecord lastResumedActivity = mResumedActivity;
2589 ActivityState lastState = next.state;
2590
2591 updateCpuStats();
2592
2593 next.state = ActivityState.RESUMED;
2594 mResumedActivity = next;
2595 next.task.touchActiveTime();
2596 updateLRUListLocked(next.app, true);
2597 updateLRUListLocked(next);
2598
2599 // Have the window manager re-evaluate the orientation of
2600 // the screen based on the new activity order.
2601 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002602 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603 next.mayFreezeScreenLocked(next.app) ? next : null);
2604 if (config != null) {
2605 next.frozenBeforeDestroy = true;
2606 }
2607 if (!updateConfigurationLocked(config, next)) {
2608 // The configuration update wasn't able to keep the existing
2609 // instance of the activity, and instead started a new one.
2610 // We should be all done, but let's just make sure our activity
2611 // is still at the top and schedule another run if something
2612 // weird happened.
2613 HistoryRecord nextNext = topRunningActivityLocked(null);
2614 if (DEBUG_SWITCH) Log.i(TAG,
2615 "Activity config changed during resume: " + next
2616 + ", new next: " + nextNext);
2617 if (nextNext != next) {
2618 // Do over!
2619 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2620 }
2621 mWindowManager.executeAppTransition();
2622 return true;
2623 }
2624
2625 try {
2626 // Deliver all pending results.
2627 ArrayList a = next.results;
2628 if (a != null) {
2629 final int N = a.size();
2630 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002631 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002632 TAG, "Delivering results to " + next
2633 + ": " + a);
2634 next.app.thread.scheduleSendResult(next, a);
2635 }
2636 }
2637
2638 if (next.newIntents != null) {
2639 next.app.thread.scheduleNewIntent(next.newIntents, next);
2640 }
2641
2642 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2643 System.identityHashCode(next),
2644 next.task.taskId, next.shortComponentName);
2645 updateUsageStats(next, true);
2646
2647 next.app.thread.scheduleResumeActivity(next,
2648 isNextTransitionForward());
2649 pauseIfSleepingLocked();
2650
2651 } catch (Exception e) {
2652 // Whoops, need to restart this activity!
2653 next.state = lastState;
2654 mResumedActivity = lastResumedActivity;
2655 if (Config.LOGD) Log.d(TAG,
2656 "Restarting because process died: " + next);
2657 if (!next.hasBeenLaunched) {
2658 next.hasBeenLaunched = true;
2659 } else {
2660 if (SHOW_APP_STARTING_ICON) {
2661 mWindowManager.setAppStartingWindow(
2662 next, next.packageName, next.theme,
2663 next.nonLocalizedLabel,
2664 next.labelRes, next.icon, null, true);
2665 }
2666 }
2667 startSpecificActivityLocked(next, true, false);
2668 return true;
2669 }
2670
2671 // From this point on, if something goes wrong there is no way
2672 // to recover the activity.
2673 try {
2674 next.visible = true;
2675 completeResumeLocked(next);
2676 } catch (Exception e) {
2677 // If any exception gets thrown, toss away this
2678 // activity and try the next one.
2679 Log.w(TAG, "Exception thrown during resume of " + next, e);
2680 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2681 "resume-exception");
2682 return true;
2683 }
2684
2685 // Didn't need to use the icicle, and it is now out of date.
2686 next.icicle = null;
2687 next.haveState = false;
2688 next.stopped = false;
2689
2690 } else {
2691 // Whoops, need to restart this activity!
2692 if (!next.hasBeenLaunched) {
2693 next.hasBeenLaunched = true;
2694 } else {
2695 if (SHOW_APP_STARTING_ICON) {
2696 mWindowManager.setAppStartingWindow(
2697 next, next.packageName, next.theme,
2698 next.nonLocalizedLabel,
2699 next.labelRes, next.icon, null, true);
2700 }
2701 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2702 }
2703 startSpecificActivityLocked(next, true, true);
2704 }
2705
2706 return true;
2707 }
2708
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002709 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2710 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 final int NH = mHistory.size();
2712
2713 int addPos = -1;
2714
2715 if (!newTask) {
2716 // If starting in an existing task, find where that is...
2717 HistoryRecord next = null;
2718 boolean startIt = true;
2719 for (int i = NH-1; i >= 0; i--) {
2720 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2721 if (p.finishing) {
2722 continue;
2723 }
2724 if (p.task == r.task) {
2725 // Here it is! Now, if this is not yet visible to the
2726 // user, then just add it without starting; it will
2727 // get started when the user navigates back to it.
2728 addPos = i+1;
2729 if (!startIt) {
2730 mHistory.add(addPos, r);
2731 r.inHistory = true;
2732 r.task.numActivities++;
2733 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2734 r.info.screenOrientation, r.fullscreen);
2735 if (VALIDATE_TOKENS) {
2736 mWindowManager.validateAppTokens(mHistory);
2737 }
2738 return;
2739 }
2740 break;
2741 }
2742 if (p.fullscreen) {
2743 startIt = false;
2744 }
2745 next = p;
2746 }
2747 }
2748
2749 // Place a new activity at top of stack, so it is next to interact
2750 // with the user.
2751 if (addPos < 0) {
2752 addPos = mHistory.size();
2753 }
2754
2755 // If we are not placing the new activity frontmost, we do not want
2756 // to deliver the onUserLeaving callback to the actual frontmost
2757 // activity
2758 if (addPos < NH) {
2759 mUserLeaving = false;
2760 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2761 }
2762
2763 // Slot the activity into the history stack and proceed
2764 mHistory.add(addPos, r);
2765 r.inHistory = true;
2766 r.frontOfTask = newTask;
2767 r.task.numActivities++;
2768 if (NH > 0) {
2769 // We want to show the starting preview window if we are
2770 // switching to a new task, or the next activity's process is
2771 // not currently running.
2772 boolean showStartingIcon = newTask;
2773 ProcessRecord proc = r.app;
2774 if (proc == null) {
2775 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2776 }
2777 if (proc == null || proc.thread == null) {
2778 showStartingIcon = true;
2779 }
2780 if (DEBUG_TRANSITION) Log.v(TAG,
2781 "Prepare open transition: starting " + r);
2782 mWindowManager.prepareAppTransition(newTask
2783 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2784 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2785 mWindowManager.addAppToken(
2786 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2787 boolean doShow = true;
2788 if (newTask) {
2789 // Even though this activity is starting fresh, we still need
2790 // to reset it to make sure we apply affinities to move any
2791 // existing activities from other tasks in to it.
2792 // If the caller has requested that the target task be
2793 // reset, then do so.
2794 if ((r.intent.getFlags()
2795 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2796 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002797 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002798 }
2799 }
2800 if (SHOW_APP_STARTING_ICON && doShow) {
2801 // Figure out if we are transitioning from another activity that is
2802 // "has the same starting icon" as the next one. This allows the
2803 // window manager to keep the previous window it had previously
2804 // created, if it still had one.
2805 HistoryRecord prev = mResumedActivity;
2806 if (prev != null) {
2807 // We don't want to reuse the previous starting preview if:
2808 // (1) The current activity is in a different task.
2809 if (prev.task != r.task) prev = null;
2810 // (2) The current activity is already displayed.
2811 else if (prev.nowVisible) prev = null;
2812 }
2813 mWindowManager.setAppStartingWindow(
2814 r, r.packageName, r.theme, r.nonLocalizedLabel,
2815 r.labelRes, r.icon, prev, showStartingIcon);
2816 }
2817 } else {
2818 // If this is the first activity, don't do any fancy animations,
2819 // because there is nothing for it to animate on top of.
2820 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2821 r.info.screenOrientation, r.fullscreen);
2822 }
2823 if (VALIDATE_TOKENS) {
2824 mWindowManager.validateAppTokens(mHistory);
2825 }
2826
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002827 if (doResume) {
2828 resumeTopActivityLocked(null);
2829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002830 }
2831
2832 /**
2833 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002834 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2835 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836 * an instance of that activity in the stack and, if found, finish all
2837 * activities on top of it and return the instance.
2838 *
2839 * @param newR Description of the new activity being started.
2840 * @return Returns the old activity that should be continue to be used,
2841 * or null if none was found.
2842 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002843 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002844 HistoryRecord newR, boolean doClear) {
2845 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002846
2847 // First find the requested task.
2848 while (i > 0) {
2849 i--;
2850 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2851 if (r.task.taskId == taskId) {
2852 i++;
2853 break;
2854 }
2855 }
2856
2857 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002858 while (i > 0) {
2859 i--;
2860 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2861 if (r.finishing) {
2862 continue;
2863 }
2864 if (r.task.taskId != taskId) {
2865 return null;
2866 }
2867 if (r.realActivity.equals(newR.realActivity)) {
2868 // Here it is! Now finish everything in front...
2869 HistoryRecord ret = r;
2870 if (doClear) {
2871 while (i < (mHistory.size()-1)) {
2872 i++;
2873 r = (HistoryRecord)mHistory.get(i);
2874 if (r.finishing) {
2875 continue;
2876 }
2877 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2878 null, "clear")) {
2879 i--;
2880 }
2881 }
2882 }
2883
2884 // Finally, if this is a normal launch mode (that is, not
2885 // expecting onNewIntent()), then we will finish the current
2886 // instance of the activity so a new fresh one can be started.
2887 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2888 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002889 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002890 if (index >= 0) {
2891 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2892 null, "clear");
2893 }
2894 return null;
2895 }
2896 }
2897
2898 return ret;
2899 }
2900 }
2901
2902 return null;
2903 }
2904
2905 /**
2906 * Find the activity in the history stack within the given task. Returns
2907 * the index within the history at which it's found, or < 0 if not found.
2908 */
2909 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2910 int i = mHistory.size();
2911 while (i > 0) {
2912 i--;
2913 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2914 if (candidate.task.taskId != task) {
2915 break;
2916 }
2917 if (candidate.realActivity.equals(r.realActivity)) {
2918 return i;
2919 }
2920 }
2921
2922 return -1;
2923 }
2924
2925 /**
2926 * Reorder the history stack so that the activity at the given index is
2927 * brought to the front.
2928 */
2929 private final HistoryRecord moveActivityToFrontLocked(int where) {
2930 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2931 int top = mHistory.size();
2932 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2933 mHistory.add(top, newTop);
2934 oldTop.frontOfTask = false;
2935 newTop.frontOfTask = true;
2936 return newTop;
2937 }
2938
2939 /**
2940 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2941 * method will be called at the proper time.
2942 */
2943 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2944 boolean sent = false;
2945 if (r.state == ActivityState.RESUMED
2946 && r.app != null && r.app.thread != null) {
2947 try {
2948 ArrayList<Intent> ar = new ArrayList<Intent>();
2949 ar.add(new Intent(intent));
2950 r.app.thread.scheduleNewIntent(ar, r);
2951 sent = true;
2952 } catch (Exception e) {
2953 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2954 }
2955 }
2956 if (!sent) {
2957 r.addNewIntentLocked(new Intent(intent));
2958 }
2959 }
2960
2961 private final void logStartActivity(int tag, HistoryRecord r,
2962 TaskRecord task) {
2963 EventLog.writeEvent(tag,
2964 System.identityHashCode(r), task.taskId,
2965 r.shortComponentName, r.intent.getAction(),
2966 r.intent.getType(), r.intent.getDataString(),
2967 r.intent.getFlags());
2968 }
2969
2970 private final int startActivityLocked(IApplicationThread caller,
2971 Intent intent, String resolvedType,
2972 Uri[] grantedUriPermissions,
2973 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2974 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002975 int callingPid, int callingUid, boolean onlyIfNeeded,
2976 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 Log.i(TAG, "Starting activity: " + intent);
2978
2979 HistoryRecord sourceRecord = null;
2980 HistoryRecord resultRecord = null;
2981 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002982 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002983 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002984 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2985 if (index >= 0) {
2986 sourceRecord = (HistoryRecord)mHistory.get(index);
2987 if (requestCode >= 0 && !sourceRecord.finishing) {
2988 resultRecord = sourceRecord;
2989 }
2990 }
2991 }
2992
2993 int launchFlags = intent.getFlags();
2994
2995 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2996 && sourceRecord != null) {
2997 // Transfer the result target from the source activity to the new
2998 // one being started, including any failures.
2999 if (requestCode >= 0) {
3000 return START_FORWARD_AND_REQUEST_CONFLICT;
3001 }
3002 resultRecord = sourceRecord.resultTo;
3003 resultWho = sourceRecord.resultWho;
3004 requestCode = sourceRecord.requestCode;
3005 sourceRecord.resultTo = null;
3006 if (resultRecord != null) {
3007 resultRecord.removeResultsLocked(
3008 sourceRecord, resultWho, requestCode);
3009 }
3010 }
3011
3012 int err = START_SUCCESS;
3013
3014 if (intent.getComponent() == null) {
3015 // We couldn't find a class that can handle the given Intent.
3016 // That's the end of that!
3017 err = START_INTENT_NOT_RESOLVED;
3018 }
3019
3020 if (err == START_SUCCESS && aInfo == null) {
3021 // We couldn't find the specific class specified in the Intent.
3022 // Also the end of the line.
3023 err = START_CLASS_NOT_FOUND;
3024 }
3025
3026 ProcessRecord callerApp = null;
3027 if (err == START_SUCCESS && caller != null) {
3028 callerApp = getRecordForAppLocked(caller);
3029 if (callerApp != null) {
3030 callingPid = callerApp.pid;
3031 callingUid = callerApp.info.uid;
3032 } else {
3033 Log.w(TAG, "Unable to find app for caller " + caller
3034 + " (pid=" + callingPid + ") when starting: "
3035 + intent.toString());
3036 err = START_PERMISSION_DENIED;
3037 }
3038 }
3039
3040 if (err != START_SUCCESS) {
3041 if (resultRecord != null) {
3042 sendActivityResultLocked(-1,
3043 resultRecord, resultWho, requestCode,
3044 Activity.RESULT_CANCELED, null);
3045 }
3046 return err;
3047 }
3048
3049 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3050 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3051 if (perm != PackageManager.PERMISSION_GRANTED) {
3052 if (resultRecord != null) {
3053 sendActivityResultLocked(-1,
3054 resultRecord, resultWho, requestCode,
3055 Activity.RESULT_CANCELED, null);
3056 }
3057 String msg = "Permission Denial: starting " + intent.toString()
3058 + " from " + callerApp + " (pid=" + callingPid
3059 + ", uid=" + callingUid + ")"
3060 + " requires " + aInfo.permission;
3061 Log.w(TAG, msg);
3062 throw new SecurityException(msg);
3063 }
3064
3065 if (mWatcher != null) {
3066 boolean abort = false;
3067 try {
3068 // The Intent we give to the watcher has the extra data
3069 // stripped off, since it can contain private information.
3070 Intent watchIntent = intent.cloneFilter();
3071 abort = !mWatcher.activityStarting(watchIntent,
3072 aInfo.applicationInfo.packageName);
3073 } catch (RemoteException e) {
3074 mWatcher = null;
3075 }
3076
3077 if (abort) {
3078 if (resultRecord != null) {
3079 sendActivityResultLocked(-1,
3080 resultRecord, resultWho, requestCode,
3081 Activity.RESULT_CANCELED, null);
3082 }
3083 // We pretend to the caller that it was really started, but
3084 // they will just get a cancel result.
3085 return START_SUCCESS;
3086 }
3087 }
3088
3089 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3090 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003091 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003093 if (mResumedActivity == null
3094 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3095 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3096 PendingActivityLaunch pal = new PendingActivityLaunch();
3097 pal.r = r;
3098 pal.sourceRecord = sourceRecord;
3099 pal.grantedUriPermissions = grantedUriPermissions;
3100 pal.grantedMode = grantedMode;
3101 pal.onlyIfNeeded = onlyIfNeeded;
3102 mPendingActivityLaunches.add(pal);
3103 return START_SWITCHES_CANCELED;
3104 }
3105 }
3106
3107 if (mDidAppSwitch) {
3108 // This is the second allowed switch since we stopped switches,
3109 // so now just generally allow switches. Use case: user presses
3110 // home (switches disabled, switch to home, mDidAppSwitch now true);
3111 // user taps a home icon (coming from home so allowed, we hit here
3112 // and now allow anyone to switch again).
3113 mAppSwitchesAllowedTime = 0;
3114 } else {
3115 mDidAppSwitch = true;
3116 }
3117
3118 doPendingActivityLaunchesLocked(false);
3119
3120 return startActivityUncheckedLocked(r, sourceRecord,
3121 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3122 }
3123
3124 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3125 final int N = mPendingActivityLaunches.size();
3126 if (N <= 0) {
3127 return;
3128 }
3129 for (int i=0; i<N; i++) {
3130 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3131 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3132 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3133 doResume && i == (N-1));
3134 }
3135 mPendingActivityLaunches.clear();
3136 }
3137
3138 private final int startActivityUncheckedLocked(HistoryRecord r,
3139 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3140 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3141 final Intent intent = r.intent;
3142 final int callingUid = r.launchedFromUid;
3143
3144 int launchFlags = intent.getFlags();
3145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 // We'll invoke onUserLeaving before onPause only if the launching
3147 // activity did not explicitly state that this is an automated launch.
3148 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3149 if (DEBUG_USER_LEAVING) Log.v(TAG,
3150 "startActivity() => mUserLeaving=" + mUserLeaving);
3151
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003152 // If the caller has asked not to resume at this point, we make note
3153 // of this in the record so that we can skip it when trying to find
3154 // the top running activity.
3155 if (!doResume) {
3156 r.delayedResume = true;
3157 }
3158
3159 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3160 != 0 ? r : null;
3161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 // If the onlyIfNeeded flag is set, then we can do this if the activity
3163 // being launched is the same as the one making the call... or, as
3164 // a special case, if we do not know the caller then we count the
3165 // current top activity as the caller.
3166 if (onlyIfNeeded) {
3167 HistoryRecord checkedCaller = sourceRecord;
3168 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003169 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 }
3171 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3172 // Caller is not the same as launcher, so always needed.
3173 onlyIfNeeded = false;
3174 }
3175 }
3176
3177 if (grantedUriPermissions != null && callingUid > 0) {
3178 for (int i=0; i<grantedUriPermissions.length; i++) {
3179 grantUriPermissionLocked(callingUid, r.packageName,
3180 grantedUriPermissions[i], grantedMode, r);
3181 }
3182 }
3183
3184 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3185 intent, r);
3186
3187 if (sourceRecord == null) {
3188 // This activity is not being started from another... in this
3189 // case we -always- start a new task.
3190 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3191 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3192 + intent);
3193 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3194 }
3195 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3196 // The original activity who is starting us is running as a single
3197 // instance... this new activity it is starting must go on its
3198 // own task.
3199 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3200 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3201 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3202 // The activity being started is a single instance... it always
3203 // gets launched into its own task.
3204 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3205 }
3206
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003207 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 // For whatever reason this activity is being launched into a new
3209 // task... yet the caller has requested a result back. Well, that
3210 // is pretty messed up, so instead immediately send back a cancel
3211 // and let the new task continue launched as normal without a
3212 // dependency on its originator.
3213 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3214 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003215 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 Activity.RESULT_CANCELED, null);
3217 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 }
3219
3220 boolean addingToTask = false;
3221 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3222 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3223 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3224 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3225 // If bring to front is requested, and no result is requested, and
3226 // we can find a task that was started with this same
3227 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003228 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003229 // See if there is a task to bring to the front. If this is
3230 // a SINGLE_INSTANCE activity, there can be one and only one
3231 // instance of it in the history, and it is always in its own
3232 // unique task, so we do a special search.
3233 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3234 ? findTaskLocked(intent, r.info)
3235 : findActivityLocked(intent, r.info);
3236 if (taskTop != null) {
3237 if (taskTop.task.intent == null) {
3238 // This task was started because of movement of
3239 // the activity based on affinity... now that we
3240 // are actually launching it, we can assign the
3241 // base intent.
3242 taskTop.task.setIntent(intent, r.info);
3243 }
3244 // If the target task is not in the front, then we need
3245 // to bring it to the front... except... well, with
3246 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3247 // to have the same behavior as if a new instance was
3248 // being started, which means not bringing it to the front
3249 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003250 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 if (curTop.task != taskTop.task) {
3252 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3253 boolean callerAtFront = sourceRecord == null
3254 || curTop.task == sourceRecord.task;
3255 if (callerAtFront) {
3256 // We really do want to push this one into the
3257 // user's face, right now.
3258 moveTaskToFrontLocked(taskTop.task);
3259 }
3260 }
3261 // If the caller has requested that the target task be
3262 // reset, then do so.
3263 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3264 taskTop = resetTaskIfNeededLocked(taskTop, r);
3265 }
3266 if (onlyIfNeeded) {
3267 // We don't need to start a new activity, and
3268 // the client said not to do anything if that
3269 // is the case, so this is it! And for paranoia, make
3270 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003271 if (doResume) {
3272 resumeTopActivityLocked(null);
3273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 return START_RETURN_INTENT_TO_CALLER;
3275 }
3276 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3277 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3278 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3279 // In this situation we want to remove all activities
3280 // from the task up to the one being started. In most
3281 // cases this means we are resetting the task to its
3282 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003283 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 taskTop.task.taskId, r, true);
3285 if (top != null) {
3286 if (top.frontOfTask) {
3287 // Activity aliases may mean we use different
3288 // intents for the top activity, so make sure
3289 // the task now has the identity of the new
3290 // intent.
3291 top.task.setIntent(r.intent, r.info);
3292 }
3293 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3294 deliverNewIntentLocked(top, r.intent);
3295 } else {
3296 // A special case: we need to
3297 // start the activity because it is not currently
3298 // running, and the caller has asked to clear the
3299 // current task to have this activity at the top.
3300 addingToTask = true;
3301 // Now pretend like this activity is being started
3302 // by the top of its task, so it is put in the
3303 // right place.
3304 sourceRecord = taskTop;
3305 }
3306 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3307 // In this case the top activity on the task is the
3308 // same as the one being launched, so we take that
3309 // as a request to bring the task to the foreground.
3310 // If the top activity in the task is the root
3311 // activity, deliver this new intent to it if it
3312 // desires.
3313 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3314 && taskTop.realActivity.equals(r.realActivity)) {
3315 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3316 if (taskTop.frontOfTask) {
3317 taskTop.task.setIntent(r.intent, r.info);
3318 }
3319 deliverNewIntentLocked(taskTop, r.intent);
3320 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3321 // In this case we are launching the root activity
3322 // of the task, but with a different intent. We
3323 // should start a new instance on top.
3324 addingToTask = true;
3325 sourceRecord = taskTop;
3326 }
3327 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3328 // In this case an activity is being launched in to an
3329 // existing task, without resetting that task. This
3330 // is typically the situation of launching an activity
3331 // from a notification or shortcut. We want to place
3332 // the new activity on top of the current task.
3333 addingToTask = true;
3334 sourceRecord = taskTop;
3335 } else if (!taskTop.task.rootWasReset) {
3336 // In this case we are launching in to an existing task
3337 // that has not yet been started from its front door.
3338 // The current task has been brought to the front.
3339 // Ideally, we'd probably like to place this new task
3340 // at the bottom of its stack, but that's a little hard
3341 // to do with the current organization of the code so
3342 // for now we'll just drop it.
3343 taskTop.task.setIntent(r.intent, r.info);
3344 }
3345 if (!addingToTask) {
3346 // We didn't do anything... but it was needed (a.k.a., client
3347 // don't use that intent!) And for paranoia, make
3348 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003349 if (doResume) {
3350 resumeTopActivityLocked(null);
3351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 return START_TASK_TO_FRONT;
3353 }
3354 }
3355 }
3356 }
3357
3358 //String uri = r.intent.toURI();
3359 //Intent intent2 = new Intent(uri);
3360 //Log.i(TAG, "Given intent: " + r.intent);
3361 //Log.i(TAG, "URI is: " + uri);
3362 //Log.i(TAG, "To intent: " + intent2);
3363
3364 if (r.packageName != null) {
3365 // If the activity being launched is the same as the one currently
3366 // at the top, then we need to check if it should only be launched
3367 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003368 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3369 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370 if (top.realActivity.equals(r.realActivity)) {
3371 if (top.app != null && top.app.thread != null) {
3372 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3373 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3374 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3375 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3376 // For paranoia, make sure we have correctly
3377 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003378 if (doResume) {
3379 resumeTopActivityLocked(null);
3380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 if (onlyIfNeeded) {
3382 // We don't need to start a new activity, and
3383 // the client said not to do anything if that
3384 // is the case, so this is it!
3385 return START_RETURN_INTENT_TO_CALLER;
3386 }
3387 deliverNewIntentLocked(top, r.intent);
3388 return START_DELIVERED_TO_TOP;
3389 }
3390 }
3391 }
3392 }
3393
3394 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003395 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003397 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003398 Activity.RESULT_CANCELED, null);
3399 }
3400 return START_CLASS_NOT_FOUND;
3401 }
3402
3403 boolean newTask = false;
3404
3405 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003406 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3408 // todo: should do better management of integers.
3409 mCurTask++;
3410 if (mCurTask <= 0) {
3411 mCurTask = 1;
3412 }
3413 r.task = new TaskRecord(mCurTask, r.info, intent,
3414 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3415 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3416 + " in new task " + r.task);
3417 newTask = true;
3418 addRecentTask(r.task);
3419
3420 } else if (sourceRecord != null) {
3421 if (!addingToTask &&
3422 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3423 // In this case, we are adding the activity to an existing
3424 // task, but the caller has asked to clear that task if the
3425 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003426 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 sourceRecord.task.taskId, r, true);
3428 if (top != null) {
3429 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3430 deliverNewIntentLocked(top, r.intent);
3431 // For paranoia, make sure we have correctly
3432 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003433 if (doResume) {
3434 resumeTopActivityLocked(null);
3435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 return START_DELIVERED_TO_TOP;
3437 }
3438 } else if (!addingToTask &&
3439 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3440 // In this case, we are launching an activity in our own task
3441 // that may already be running somewhere in the history, and
3442 // we want to shuffle it to the front of the stack if so.
3443 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3444 if (where >= 0) {
3445 HistoryRecord top = moveActivityToFrontLocked(where);
3446 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3447 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003448 if (doResume) {
3449 resumeTopActivityLocked(null);
3450 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003451 return START_DELIVERED_TO_TOP;
3452 }
3453 }
3454 // An existing activity is starting this new activity, so we want
3455 // to keep the new one in the same task as the one that is starting
3456 // it.
3457 r.task = sourceRecord.task;
3458 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3459 + " in existing task " + r.task);
3460
3461 } else {
3462 // This not being started from an existing activity, and not part
3463 // of a new task... just put it in the top task, though these days
3464 // this case should never happen.
3465 final int N = mHistory.size();
3466 HistoryRecord prev =
3467 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3468 r.task = prev != null
3469 ? prev.task
3470 : new TaskRecord(mCurTask, r.info, intent,
3471 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3472 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3473 + " in new guessed " + r.task);
3474 }
3475 if (newTask) {
3476 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3477 }
3478 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003479 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003480 return START_SUCCESS;
3481 }
3482
3483 public final int startActivity(IApplicationThread caller,
3484 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3485 int grantedMode, IBinder resultTo,
3486 String resultWho, int requestCode, boolean onlyIfNeeded,
3487 boolean debug) {
3488 // Refuse possible leaked file descriptors
3489 if (intent != null && intent.hasFileDescriptors()) {
3490 throw new IllegalArgumentException("File descriptors passed in Intent");
3491 }
3492
The Android Open Source Project4df24232009-03-05 14:34:35 -08003493 final boolean componentSpecified = intent.getComponent() != null;
3494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003495 // Don't modify the client's object!
3496 intent = new Intent(intent);
3497
3498 // Collect information about the target of the Intent.
3499 // Must do this before locking, because resolving the intent
3500 // may require launching a process to run its content provider.
3501 ActivityInfo aInfo;
3502 try {
3503 ResolveInfo rInfo =
3504 ActivityThread.getPackageManager().resolveIntent(
3505 intent, resolvedType,
3506 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003507 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003508 aInfo = rInfo != null ? rInfo.activityInfo : null;
3509 } catch (RemoteException e) {
3510 aInfo = null;
3511 }
3512
3513 if (aInfo != null) {
3514 // Store the found target back into the intent, because now that
3515 // we have it we never want to do this again. For example, if the
3516 // user navigates back to this point in the history, we should
3517 // always restart the exact same activity.
3518 intent.setComponent(new ComponentName(
3519 aInfo.applicationInfo.packageName, aInfo.name));
3520
3521 // Don't debug things in the system process
3522 if (debug) {
3523 if (!aInfo.processName.equals("system")) {
3524 setDebugApp(aInfo.processName, true, false);
3525 }
3526 }
3527 }
3528
3529 synchronized(this) {
3530 final long origId = Binder.clearCallingIdentity();
3531 int res = startActivityLocked(caller, intent, resolvedType,
3532 grantedUriPermissions, grantedMode, aInfo,
3533 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003534 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 Binder.restoreCallingIdentity(origId);
3536 return res;
3537 }
3538 }
3539
3540 public boolean startNextMatchingActivity(IBinder callingActivity,
3541 Intent intent) {
3542 // Refuse possible leaked file descriptors
3543 if (intent != null && intent.hasFileDescriptors() == true) {
3544 throw new IllegalArgumentException("File descriptors passed in Intent");
3545 }
3546
3547 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003548 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 if (index < 0) {
3550 return false;
3551 }
3552 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3553 if (r.app == null || r.app.thread == null) {
3554 // The caller is not running... d'oh!
3555 return false;
3556 }
3557 intent = new Intent(intent);
3558 // The caller is not allowed to change the data.
3559 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3560 // And we are resetting to find the next component...
3561 intent.setComponent(null);
3562
3563 ActivityInfo aInfo = null;
3564 try {
3565 List<ResolveInfo> resolves =
3566 ActivityThread.getPackageManager().queryIntentActivities(
3567 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003568 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569
3570 // Look for the original activity in the list...
3571 final int N = resolves != null ? resolves.size() : 0;
3572 for (int i=0; i<N; i++) {
3573 ResolveInfo rInfo = resolves.get(i);
3574 if (rInfo.activityInfo.packageName.equals(r.packageName)
3575 && rInfo.activityInfo.name.equals(r.info.name)) {
3576 // We found the current one... the next matching is
3577 // after it.
3578 i++;
3579 if (i<N) {
3580 aInfo = resolves.get(i).activityInfo;
3581 }
3582 break;
3583 }
3584 }
3585 } catch (RemoteException e) {
3586 }
3587
3588 if (aInfo == null) {
3589 // Nobody who is next!
3590 return false;
3591 }
3592
3593 intent.setComponent(new ComponentName(
3594 aInfo.applicationInfo.packageName, aInfo.name));
3595 intent.setFlags(intent.getFlags()&~(
3596 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3597 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3598 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3599 Intent.FLAG_ACTIVITY_NEW_TASK));
3600
3601 // Okay now we need to start the new activity, replacing the
3602 // currently running activity. This is a little tricky because
3603 // we want to start the new one as if the current one is finished,
3604 // but not finish the current one first so that there is no flicker.
3605 // And thus...
3606 final boolean wasFinishing = r.finishing;
3607 r.finishing = true;
3608
3609 // Propagate reply information over to the new activity.
3610 final HistoryRecord resultTo = r.resultTo;
3611 final String resultWho = r.resultWho;
3612 final int requestCode = r.requestCode;
3613 r.resultTo = null;
3614 if (resultTo != null) {
3615 resultTo.removeResultsLocked(r, resultWho, requestCode);
3616 }
3617
3618 final long origId = Binder.clearCallingIdentity();
3619 // XXX we are not dealing with propagating grantedUriPermissions...
3620 // those are not yet exposed to user code, so there is no need.
3621 int res = startActivityLocked(r.app.thread, intent,
3622 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003623 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 Binder.restoreCallingIdentity(origId);
3625
3626 r.finishing = wasFinishing;
3627 if (res != START_SUCCESS) {
3628 return false;
3629 }
3630 return true;
3631 }
3632 }
3633
3634 final int startActivityInPackage(int uid,
3635 Intent intent, String resolvedType, IBinder resultTo,
3636 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003637 final boolean componentSpecified = intent.getComponent() != null;
3638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 // Don't modify the client's object!
3640 intent = new Intent(intent);
3641
3642 // Collect information about the target of the Intent.
3643 // Must do this before locking, because resolving the intent
3644 // may require launching a process to run its content provider.
3645 ActivityInfo aInfo;
3646 try {
3647 ResolveInfo rInfo =
3648 ActivityThread.getPackageManager().resolveIntent(
3649 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003650 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 aInfo = rInfo != null ? rInfo.activityInfo : null;
3652 } catch (RemoteException e) {
3653 aInfo = null;
3654 }
3655
3656 if (aInfo != null) {
3657 // Store the found target back into the intent, because now that
3658 // we have it we never want to do this again. For example, if the
3659 // user navigates back to this point in the history, we should
3660 // always restart the exact same activity.
3661 intent.setComponent(new ComponentName(
3662 aInfo.applicationInfo.packageName, aInfo.name));
3663 }
3664
3665 synchronized(this) {
3666 return startActivityLocked(null, intent, resolvedType,
3667 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003668 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 }
3670 }
3671
3672 private final void addRecentTask(TaskRecord task) {
3673 // Remove any existing entries that are the same kind of task.
3674 int N = mRecentTasks.size();
3675 for (int i=0; i<N; i++) {
3676 TaskRecord tr = mRecentTasks.get(i);
3677 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3678 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3679 mRecentTasks.remove(i);
3680 i--;
3681 N--;
3682 if (task.intent == null) {
3683 // If the new recent task we are adding is not fully
3684 // specified, then replace it with the existing recent task.
3685 task = tr;
3686 }
3687 }
3688 }
3689 if (N >= MAX_RECENT_TASKS) {
3690 mRecentTasks.remove(N-1);
3691 }
3692 mRecentTasks.add(0, task);
3693 }
3694
3695 public void setRequestedOrientation(IBinder token,
3696 int requestedOrientation) {
3697 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003698 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003699 if (index < 0) {
3700 return;
3701 }
3702 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3703 final long origId = Binder.clearCallingIdentity();
3704 mWindowManager.setAppOrientation(r, requestedOrientation);
3705 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003706 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 r.mayFreezeScreenLocked(r.app) ? r : null);
3708 if (config != null) {
3709 r.frozenBeforeDestroy = true;
3710 if (!updateConfigurationLocked(config, r)) {
3711 resumeTopActivityLocked(null);
3712 }
3713 }
3714 Binder.restoreCallingIdentity(origId);
3715 }
3716 }
3717
3718 public int getRequestedOrientation(IBinder token) {
3719 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003720 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 if (index < 0) {
3722 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3723 }
3724 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3725 return mWindowManager.getAppOrientation(r);
3726 }
3727 }
3728
3729 private final void stopActivityLocked(HistoryRecord r) {
3730 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3731 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3732 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3733 if (!r.finishing) {
3734 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3735 "no-history");
3736 }
3737 } else if (r.app != null && r.app.thread != null) {
3738 if (mFocusedActivity == r) {
3739 setFocusedActivityLocked(topRunningActivityLocked(null));
3740 }
3741 r.resumeKeyDispatchingLocked();
3742 try {
3743 r.stopped = false;
3744 r.state = ActivityState.STOPPING;
3745 if (DEBUG_VISBILITY) Log.v(
3746 TAG, "Stopping visible=" + r.visible + " for " + r);
3747 if (!r.visible) {
3748 mWindowManager.setAppVisibility(r, false);
3749 }
3750 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3751 } catch (Exception e) {
3752 // Maybe just ignore exceptions here... if the process
3753 // has crashed, our death notification will clean things
3754 // up.
3755 Log.w(TAG, "Exception thrown during pause", e);
3756 // Just in case, assume it to be stopped.
3757 r.stopped = true;
3758 r.state = ActivityState.STOPPED;
3759 if (r.configDestroy) {
3760 destroyActivityLocked(r, true);
3761 }
3762 }
3763 }
3764 }
3765
3766 /**
3767 * @return Returns true if the activity is being finished, false if for
3768 * some reason it is being left as-is.
3769 */
3770 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3771 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003772 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003773 TAG, "Finishing activity: token=" + token
3774 + ", result=" + resultCode + ", data=" + resultData);
3775
Dianne Hackborn75b03852009-06-12 15:43:26 -07003776 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 if (index < 0) {
3778 return false;
3779 }
3780 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3781
3782 // Is this the last activity left?
3783 boolean lastActivity = true;
3784 for (int i=mHistory.size()-1; i>=0; i--) {
3785 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3786 if (!p.finishing && p != r) {
3787 lastActivity = false;
3788 break;
3789 }
3790 }
3791
3792 // If this is the last activity, but it is the home activity, then
3793 // just don't finish it.
3794 if (lastActivity) {
3795 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3796 return false;
3797 }
3798 }
3799
3800 finishActivityLocked(r, index, resultCode, resultData, reason);
3801 return true;
3802 }
3803
3804 /**
3805 * @return Returns true if this activity has been removed from the history
3806 * list, or false if it is still in the list and will be removed later.
3807 */
3808 private final boolean finishActivityLocked(HistoryRecord r, int index,
3809 int resultCode, Intent resultData, String reason) {
3810 if (r.finishing) {
3811 Log.w(TAG, "Duplicate finish request for " + r);
3812 return false;
3813 }
3814
3815 r.finishing = true;
3816 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3817 System.identityHashCode(r),
3818 r.task.taskId, r.shortComponentName, reason);
3819 r.task.numActivities--;
3820 if (r.frontOfTask && index < (mHistory.size()-1)) {
3821 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3822 if (next.task == r.task) {
3823 next.frontOfTask = true;
3824 }
3825 }
3826
3827 r.pauseKeyDispatchingLocked();
3828 if (mFocusedActivity == r) {
3829 setFocusedActivityLocked(topRunningActivityLocked(null));
3830 }
3831
3832 // send the result
3833 HistoryRecord resultTo = r.resultTo;
3834 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003835 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3836 + " who=" + r.resultWho + " req=" + r.requestCode
3837 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003838 if (r.info.applicationInfo.uid > 0) {
3839 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3840 r.packageName, resultData, r);
3841 }
3842 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3843 resultData);
3844 r.resultTo = null;
3845 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003846 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847
3848 // Make sure this HistoryRecord is not holding on to other resources,
3849 // because clients have remote IPC references to this object so we
3850 // can't assume that will go away and want to avoid circular IPC refs.
3851 r.results = null;
3852 r.pendingResults = null;
3853 r.newIntents = null;
3854 r.icicle = null;
3855
3856 if (mPendingThumbnails.size() > 0) {
3857 // There are clients waiting to receive thumbnails so, in case
3858 // this is an activity that someone is waiting for, add it
3859 // to the pending list so we can correctly update the clients.
3860 mCancelledThumbnails.add(r);
3861 }
3862
3863 if (mResumedActivity == r) {
3864 boolean endTask = index <= 0
3865 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3866 if (DEBUG_TRANSITION) Log.v(TAG,
3867 "Prepare close transition: finishing " + r);
3868 mWindowManager.prepareAppTransition(endTask
3869 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3870 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3871
3872 // Tell window manager to prepare for this one to be removed.
3873 mWindowManager.setAppVisibility(r, false);
3874
3875 if (mPausingActivity == null) {
3876 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3877 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3878 startPausingLocked(false, false);
3879 }
3880
3881 } else if (r.state != ActivityState.PAUSING) {
3882 // If the activity is PAUSING, we will complete the finish once
3883 // it is done pausing; else we can just directly finish it here.
3884 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3885 return finishCurrentActivityLocked(r, index,
3886 FINISH_AFTER_PAUSE) == null;
3887 } else {
3888 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3889 }
3890
3891 return false;
3892 }
3893
3894 private static final int FINISH_IMMEDIATELY = 0;
3895 private static final int FINISH_AFTER_PAUSE = 1;
3896 private static final int FINISH_AFTER_VISIBLE = 2;
3897
3898 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3899 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003900 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901 if (index < 0) {
3902 return null;
3903 }
3904
3905 return finishCurrentActivityLocked(r, index, mode);
3906 }
3907
3908 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3909 int index, int mode) {
3910 // First things first: if this activity is currently visible,
3911 // and the resumed activity is not yet visible, then hold off on
3912 // finishing until the resumed one becomes visible.
3913 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3914 if (!mStoppingActivities.contains(r)) {
3915 mStoppingActivities.add(r);
3916 if (mStoppingActivities.size() > 3) {
3917 // If we already have a few activities waiting to stop,
3918 // then give up on things going idle and start clearing
3919 // them out.
3920 Message msg = Message.obtain();
3921 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3922 mHandler.sendMessage(msg);
3923 }
3924 }
3925 r.state = ActivityState.STOPPING;
3926 updateOomAdjLocked();
3927 return r;
3928 }
3929
3930 // make sure the record is cleaned out of other places.
3931 mStoppingActivities.remove(r);
3932 mWaitingVisibleActivities.remove(r);
3933 if (mResumedActivity == r) {
3934 mResumedActivity = null;
3935 }
3936 final ActivityState prevState = r.state;
3937 r.state = ActivityState.FINISHING;
3938
3939 if (mode == FINISH_IMMEDIATELY
3940 || prevState == ActivityState.STOPPED
3941 || prevState == ActivityState.INITIALIZING) {
3942 // If this activity is already stopped, we can just finish
3943 // it right now.
3944 return destroyActivityLocked(r, true) ? null : r;
3945 } else {
3946 // Need to go through the full pause cycle to get this
3947 // activity into the stopped state and then finish it.
3948 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3949 mFinishingActivities.add(r);
3950 resumeTopActivityLocked(null);
3951 }
3952 return r;
3953 }
3954
3955 /**
3956 * This is the internal entry point for handling Activity.finish().
3957 *
3958 * @param token The Binder token referencing the Activity we want to finish.
3959 * @param resultCode Result code, if any, from this Activity.
3960 * @param resultData Result data (Intent), if any, from this Activity.
3961 *
3962 * @result Returns true if the activity successfully finished, or false if it is still running.
3963 */
3964 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3965 // Refuse possible leaked file descriptors
3966 if (resultData != null && resultData.hasFileDescriptors() == true) {
3967 throw new IllegalArgumentException("File descriptors passed in Intent");
3968 }
3969
3970 synchronized(this) {
3971 if (mWatcher != null) {
3972 // Find the first activity that is not finishing.
3973 HistoryRecord next = topRunningActivityLocked(token, 0);
3974 if (next != null) {
3975 // ask watcher if this is allowed
3976 boolean resumeOK = true;
3977 try {
3978 resumeOK = mWatcher.activityResuming(next.packageName);
3979 } catch (RemoteException e) {
3980 mWatcher = null;
3981 }
3982
3983 if (!resumeOK) {
3984 return false;
3985 }
3986 }
3987 }
3988 final long origId = Binder.clearCallingIdentity();
3989 boolean res = requestFinishActivityLocked(token, resultCode,
3990 resultData, "app-request");
3991 Binder.restoreCallingIdentity(origId);
3992 return res;
3993 }
3994 }
3995
3996 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3997 String resultWho, int requestCode, int resultCode, Intent data) {
3998
3999 if (callingUid > 0) {
4000 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4001 data, r);
4002 }
4003
The Android Open Source Project10592532009-03-18 17:39:46 -07004004 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4005 + " : who=" + resultWho + " req=" + requestCode
4006 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004007 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4008 try {
4009 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4010 list.add(new ResultInfo(resultWho, requestCode,
4011 resultCode, data));
4012 r.app.thread.scheduleSendResult(r, list);
4013 return;
4014 } catch (Exception e) {
4015 Log.w(TAG, "Exception thrown sending result to " + r, e);
4016 }
4017 }
4018
4019 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4020 }
4021
4022 public final void finishSubActivity(IBinder token, String resultWho,
4023 int requestCode) {
4024 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004025 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026 if (index < 0) {
4027 return;
4028 }
4029 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4030
4031 final long origId = Binder.clearCallingIdentity();
4032
4033 int i;
4034 for (i=mHistory.size()-1; i>=0; i--) {
4035 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4036 if (r.resultTo == self && r.requestCode == requestCode) {
4037 if ((r.resultWho == null && resultWho == null) ||
4038 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4039 finishActivityLocked(r, i,
4040 Activity.RESULT_CANCELED, null, "request-sub");
4041 }
4042 }
4043 }
4044
4045 Binder.restoreCallingIdentity(origId);
4046 }
4047 }
4048
4049 /**
4050 * Perform clean-up of service connections in an activity record.
4051 */
4052 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4053 // Throw away any services that have been bound by this activity.
4054 if (r.connections != null) {
4055 Iterator<ConnectionRecord> it = r.connections.iterator();
4056 while (it.hasNext()) {
4057 ConnectionRecord c = it.next();
4058 removeConnectionLocked(c, null, r);
4059 }
4060 r.connections = null;
4061 }
4062 }
4063
4064 /**
4065 * Perform the common clean-up of an activity record. This is called both
4066 * as part of destroyActivityLocked() (when destroying the client-side
4067 * representation) and cleaning things up as a result of its hosting
4068 * processing going away, in which case there is no remaining client-side
4069 * state to destroy so only the cleanup here is needed.
4070 */
4071 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4072 if (mResumedActivity == r) {
4073 mResumedActivity = null;
4074 }
4075 if (mFocusedActivity == r) {
4076 mFocusedActivity = null;
4077 }
4078
4079 r.configDestroy = false;
4080 r.frozenBeforeDestroy = false;
4081
4082 // Make sure this record is no longer in the pending finishes list.
4083 // This could happen, for example, if we are trimming activities
4084 // down to the max limit while they are still waiting to finish.
4085 mFinishingActivities.remove(r);
4086 mWaitingVisibleActivities.remove(r);
4087
4088 // Remove any pending results.
4089 if (r.finishing && r.pendingResults != null) {
4090 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4091 PendingIntentRecord rec = apr.get();
4092 if (rec != null) {
4093 cancelIntentSenderLocked(rec, false);
4094 }
4095 }
4096 r.pendingResults = null;
4097 }
4098
4099 if (cleanServices) {
4100 cleanUpActivityServicesLocked(r);
4101 }
4102
4103 if (mPendingThumbnails.size() > 0) {
4104 // There are clients waiting to receive thumbnails so, in case
4105 // this is an activity that someone is waiting for, add it
4106 // to the pending list so we can correctly update the clients.
4107 mCancelledThumbnails.add(r);
4108 }
4109
4110 // Get rid of any pending idle timeouts.
4111 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4112 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4113 }
4114
4115 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4116 if (r.state != ActivityState.DESTROYED) {
4117 mHistory.remove(r);
4118 r.inHistory = false;
4119 r.state = ActivityState.DESTROYED;
4120 mWindowManager.removeAppToken(r);
4121 if (VALIDATE_TOKENS) {
4122 mWindowManager.validateAppTokens(mHistory);
4123 }
4124 cleanUpActivityServicesLocked(r);
4125 removeActivityUriPermissionsLocked(r);
4126 }
4127 }
4128
4129 /**
4130 * Destroy the current CLIENT SIDE instance of an activity. This may be
4131 * called both when actually finishing an activity, or when performing
4132 * a configuration switch where we destroy the current client-side object
4133 * but then create a new client-side object for this same HistoryRecord.
4134 */
4135 private final boolean destroyActivityLocked(HistoryRecord r,
4136 boolean removeFromApp) {
4137 if (DEBUG_SWITCH) Log.v(
4138 TAG, "Removing activity: token=" + r
4139 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4140 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4141 System.identityHashCode(r),
4142 r.task.taskId, r.shortComponentName);
4143
4144 boolean removedFromHistory = false;
4145
4146 cleanUpActivityLocked(r, false);
4147
4148 if (r.app != null) {
4149 if (removeFromApp) {
4150 int idx = r.app.activities.indexOf(r);
4151 if (idx >= 0) {
4152 r.app.activities.remove(idx);
4153 }
4154 if (r.persistent) {
4155 decPersistentCountLocked(r.app);
4156 }
4157 }
4158
4159 boolean skipDestroy = false;
4160
4161 try {
4162 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4163 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4164 r.configChangeFlags);
4165 } catch (Exception e) {
4166 // We can just ignore exceptions here... if the process
4167 // has crashed, our death notification will clean things
4168 // up.
4169 //Log.w(TAG, "Exception thrown during finish", e);
4170 if (r.finishing) {
4171 removeActivityFromHistoryLocked(r);
4172 removedFromHistory = true;
4173 skipDestroy = true;
4174 }
4175 }
4176
4177 r.app = null;
4178 r.nowVisible = false;
4179
4180 if (r.finishing && !skipDestroy) {
4181 r.state = ActivityState.DESTROYING;
4182 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4183 msg.obj = r;
4184 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4185 } else {
4186 r.state = ActivityState.DESTROYED;
4187 }
4188 } else {
4189 // remove this record from the history.
4190 if (r.finishing) {
4191 removeActivityFromHistoryLocked(r);
4192 removedFromHistory = true;
4193 } else {
4194 r.state = ActivityState.DESTROYED;
4195 }
4196 }
4197
4198 r.configChangeFlags = 0;
4199
4200 if (!mLRUActivities.remove(r)) {
4201 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4202 }
4203
4204 return removedFromHistory;
4205 }
4206
4207 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4208 ProcessRecord app)
4209 {
4210 int i = list.size();
4211 if (localLOGV) Log.v(
4212 TAG, "Removing app " + app + " from list " + list
4213 + " with " + i + " entries");
4214 while (i > 0) {
4215 i--;
4216 HistoryRecord r = (HistoryRecord)list.get(i);
4217 if (localLOGV) Log.v(
4218 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4219 if (r.app == app) {
4220 if (localLOGV) Log.v(TAG, "Removing this entry!");
4221 list.remove(i);
4222 }
4223 }
4224 }
4225
4226 /**
4227 * Main function for removing an existing process from the activity manager
4228 * as a result of that process going away. Clears out all connections
4229 * to the process.
4230 */
4231 private final void handleAppDiedLocked(ProcessRecord app,
4232 boolean restarting) {
4233 cleanUpApplicationRecordLocked(app, restarting, -1);
4234 if (!restarting) {
4235 mLRUProcesses.remove(app);
4236 }
4237
4238 // Just in case...
4239 if (mPausingActivity != null && mPausingActivity.app == app) {
4240 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4241 mPausingActivity = null;
4242 }
4243 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4244 mLastPausedActivity = null;
4245 }
4246
4247 // Remove this application's activities from active lists.
4248 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4249 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4250 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4251 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4252
4253 boolean atTop = true;
4254 boolean hasVisibleActivities = false;
4255
4256 // Clean out the history list.
4257 int i = mHistory.size();
4258 if (localLOGV) Log.v(
4259 TAG, "Removing app " + app + " from history with " + i + " entries");
4260 while (i > 0) {
4261 i--;
4262 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4263 if (localLOGV) Log.v(
4264 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4265 if (r.app == app) {
4266 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4267 if (localLOGV) Log.v(
4268 TAG, "Removing this entry! frozen=" + r.haveState
4269 + " finishing=" + r.finishing);
4270 mHistory.remove(i);
4271
4272 r.inHistory = false;
4273 mWindowManager.removeAppToken(r);
4274 if (VALIDATE_TOKENS) {
4275 mWindowManager.validateAppTokens(mHistory);
4276 }
4277 removeActivityUriPermissionsLocked(r);
4278
4279 } else {
4280 // We have the current state for this activity, so
4281 // it can be restarted later when needed.
4282 if (localLOGV) Log.v(
4283 TAG, "Keeping entry, setting app to null");
4284 if (r.visible) {
4285 hasVisibleActivities = true;
4286 }
4287 r.app = null;
4288 r.nowVisible = false;
4289 if (!r.haveState) {
4290 r.icicle = null;
4291 }
4292 }
4293
4294 cleanUpActivityLocked(r, true);
4295 r.state = ActivityState.STOPPED;
4296 }
4297 atTop = false;
4298 }
4299
4300 app.activities.clear();
4301
4302 if (app.instrumentationClass != null) {
4303 Log.w(TAG, "Crash of app " + app.processName
4304 + " running instrumentation " + app.instrumentationClass);
4305 Bundle info = new Bundle();
4306 info.putString("shortMsg", "Process crashed.");
4307 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4308 }
4309
4310 if (!restarting) {
4311 if (!resumeTopActivityLocked(null)) {
4312 // If there was nothing to resume, and we are not already
4313 // restarting this process, but there is a visible activity that
4314 // is hosted by the process... then make sure all visible
4315 // activities are running, taking care of restarting this
4316 // process.
4317 if (hasVisibleActivities) {
4318 ensureActivitiesVisibleLocked(null, 0);
4319 }
4320 }
4321 }
4322 }
4323
4324 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4325 IBinder threadBinder = thread.asBinder();
4326
4327 // Find the application record.
4328 int count = mLRUProcesses.size();
4329 int i;
4330 for (i=0; i<count; i++) {
4331 ProcessRecord rec = mLRUProcesses.get(i);
4332 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4333 return i;
4334 }
4335 }
4336 return -1;
4337 }
4338
4339 private final ProcessRecord getRecordForAppLocked(
4340 IApplicationThread thread) {
4341 if (thread == null) {
4342 return null;
4343 }
4344
4345 int appIndex = getLRURecordIndexForAppLocked(thread);
4346 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4347 }
4348
4349 private final void appDiedLocked(ProcessRecord app, int pid,
4350 IApplicationThread thread) {
4351
4352 mProcDeaths[0]++;
4353
4354 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4355 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4356 + ") has died.");
4357 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4358 if (localLOGV) Log.v(
4359 TAG, "Dying app: " + app + ", pid: " + pid
4360 + ", thread: " + thread.asBinder());
4361 boolean doLowMem = app.instrumentationClass == null;
4362 handleAppDiedLocked(app, false);
4363
4364 if (doLowMem) {
4365 // If there are no longer any background processes running,
4366 // and the app that died was not running instrumentation,
4367 // then tell everyone we are now low on memory.
4368 boolean haveBg = false;
4369 int count = mLRUProcesses.size();
4370 int i;
4371 for (i=0; i<count; i++) {
4372 ProcessRecord rec = mLRUProcesses.get(i);
4373 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4374 haveBg = true;
4375 break;
4376 }
4377 }
4378
4379 if (!haveBg) {
4380 Log.i(TAG, "Low Memory: No more background processes.");
4381 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4382 for (i=0; i<count; i++) {
4383 ProcessRecord rec = mLRUProcesses.get(i);
4384 if (rec.thread != null) {
4385 rec.lastRequestedGc = SystemClock.uptimeMillis();
4386 try {
4387 rec.thread.scheduleLowMemory();
4388 } catch (RemoteException e) {
4389 // Don't care if the process is gone.
4390 }
4391 }
4392 }
4393 }
4394 }
4395 } else if (Config.LOGD) {
4396 Log.d(TAG, "Received spurious death notification for thread "
4397 + thread.asBinder());
4398 }
4399 }
4400
4401 final String readFile(String filename) {
4402 try {
4403 FileInputStream fs = new FileInputStream(filename);
4404 byte[] inp = new byte[8192];
4405 int size = fs.read(inp);
4406 fs.close();
4407 return new String(inp, 0, 0, size);
4408 } catch (java.io.IOException e) {
4409 }
4410 return "";
4411 }
4412
4413 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4414 final String annotation) {
4415 if (app.notResponding || app.crashing) {
4416 return;
4417 }
4418
4419 // Log the ANR to the event log.
4420 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4421
4422 // If we are on a secure build and the application is not interesting to the user (it is
4423 // not visible or in the background), just kill it instead of displaying a dialog.
4424 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4425 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4426 Process.killProcess(app.pid);
4427 return;
4428 }
4429
4430 // DeviceMonitor.start();
4431
4432 String processInfo = null;
4433 if (MONITOR_CPU_USAGE) {
4434 updateCpuStatsNow();
4435 synchronized (mProcessStatsThread) {
4436 processInfo = mProcessStats.printCurrentState();
4437 }
4438 }
4439
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004440 StringBuilder info = mStringBuilder;
4441 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004442 info.append("ANR (application not responding) in process: ");
4443 info.append(app.processName);
4444 if (annotation != null) {
4445 info.append("\nAnnotation: ");
4446 info.append(annotation);
4447 }
4448 if (MONITOR_CPU_USAGE) {
4449 info.append("\nCPU usage:\n");
4450 info.append(processInfo);
4451 }
4452 Log.i(TAG, info.toString());
4453
4454 // The application is not responding. Dump as many thread traces as we can.
4455 boolean fileDump = prepareTraceFile(true);
4456 if (!fileDump) {
4457 // Dumping traces to the log, just dump the process that isn't responding so
4458 // we don't overflow the log
4459 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4460 } else {
4461 // Dumping traces to a file so dump all active processes we know about
4462 synchronized (this) {
4463 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4464 ProcessRecord r = mLRUProcesses.get(i);
4465 if (r.thread != null) {
4466 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4467 }
4468 }
4469 }
4470 }
4471
4472 if (mWatcher != null) {
4473 try {
4474 int res = mWatcher.appNotResponding(app.processName,
4475 app.pid, info.toString());
4476 if (res != 0) {
4477 if (res < 0) {
4478 // wait until the SIGQUIT has had a chance to process before killing the
4479 // process.
4480 try {
4481 wait(2000);
4482 } catch (InterruptedException e) {
4483 }
4484
4485 Process.killProcess(app.pid);
4486 return;
4487 }
4488 }
4489 } catch (RemoteException e) {
4490 mWatcher = null;
4491 }
4492 }
4493
4494 makeAppNotRespondingLocked(app,
4495 activity != null ? activity.shortComponentName : null,
4496 annotation != null ? "ANR " + annotation : "ANR",
4497 info.toString(), null);
4498 Message msg = Message.obtain();
4499 HashMap map = new HashMap();
4500 msg.what = SHOW_NOT_RESPONDING_MSG;
4501 msg.obj = map;
4502 map.put("app", app);
4503 if (activity != null) {
4504 map.put("activity", activity);
4505 }
4506
4507 mHandler.sendMessage(msg);
4508 return;
4509 }
4510
4511 /**
4512 * If a stack trace file has been configured, prepare the filesystem
4513 * by creating the directory if it doesn't exist and optionally
4514 * removing the old trace file.
4515 *
4516 * @param removeExisting If set, the existing trace file will be removed.
4517 * @return Returns true if the trace file preparations succeeded
4518 */
4519 public static boolean prepareTraceFile(boolean removeExisting) {
4520 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4521 boolean fileReady = false;
4522 if (!TextUtils.isEmpty(tracesPath)) {
4523 File f = new File(tracesPath);
4524 if (!f.exists()) {
4525 // Ensure the enclosing directory exists
4526 File dir = f.getParentFile();
4527 if (!dir.exists()) {
4528 fileReady = dir.mkdirs();
4529 FileUtils.setPermissions(dir.getAbsolutePath(),
4530 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4531 } else if (dir.isDirectory()) {
4532 fileReady = true;
4533 }
4534 } else if (removeExisting) {
4535 // Remove the previous traces file, so we don't fill the disk.
4536 // The VM will recreate it
4537 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4538 fileReady = f.delete();
4539 }
4540 }
4541
4542 return fileReady;
4543 }
4544
4545
4546 private final void decPersistentCountLocked(ProcessRecord app)
4547 {
4548 app.persistentActivities--;
4549 if (app.persistentActivities > 0) {
4550 // Still more of 'em...
4551 return;
4552 }
4553 if (app.persistent) {
4554 // Ah, but the application itself is persistent. Whatever!
4555 return;
4556 }
4557
4558 // App is no longer persistent... make sure it and the ones
4559 // following it in the LRU list have the correc oom_adj.
4560 updateOomAdjLocked();
4561 }
4562
4563 public void setPersistent(IBinder token, boolean isPersistent) {
4564 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4565 != PackageManager.PERMISSION_GRANTED) {
4566 String msg = "Permission Denial: setPersistent() from pid="
4567 + Binder.getCallingPid()
4568 + ", uid=" + Binder.getCallingUid()
4569 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4570 Log.w(TAG, msg);
4571 throw new SecurityException(msg);
4572 }
4573
4574 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004575 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 if (index < 0) {
4577 return;
4578 }
4579 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4580 ProcessRecord app = r.app;
4581
4582 if (localLOGV) Log.v(
4583 TAG, "Setting persistence " + isPersistent + ": " + r);
4584
4585 if (isPersistent) {
4586 if (r.persistent) {
4587 // Okay okay, I heard you already!
4588 if (localLOGV) Log.v(TAG, "Already persistent!");
4589 return;
4590 }
4591 r.persistent = true;
4592 app.persistentActivities++;
4593 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4594 if (app.persistentActivities > 1) {
4595 // We aren't the first...
4596 if (localLOGV) Log.v(TAG, "Not the first!");
4597 return;
4598 }
4599 if (app.persistent) {
4600 // This would be redundant.
4601 if (localLOGV) Log.v(TAG, "App is persistent!");
4602 return;
4603 }
4604
4605 // App is now persistent... make sure it and the ones
4606 // following it now have the correct oom_adj.
4607 final long origId = Binder.clearCallingIdentity();
4608 updateOomAdjLocked();
4609 Binder.restoreCallingIdentity(origId);
4610
4611 } else {
4612 if (!r.persistent) {
4613 // Okay okay, I heard you already!
4614 return;
4615 }
4616 r.persistent = false;
4617 final long origId = Binder.clearCallingIdentity();
4618 decPersistentCountLocked(app);
4619 Binder.restoreCallingIdentity(origId);
4620
4621 }
4622 }
4623 }
4624
4625 public boolean clearApplicationUserData(final String packageName,
4626 final IPackageDataObserver observer) {
4627 int uid = Binder.getCallingUid();
4628 int pid = Binder.getCallingPid();
4629 long callingId = Binder.clearCallingIdentity();
4630 try {
4631 IPackageManager pm = ActivityThread.getPackageManager();
4632 int pkgUid = -1;
4633 synchronized(this) {
4634 try {
4635 pkgUid = pm.getPackageUid(packageName);
4636 } catch (RemoteException e) {
4637 }
4638 if (pkgUid == -1) {
4639 Log.w(TAG, "Invalid packageName:" + packageName);
4640 return false;
4641 }
4642 if (uid == pkgUid || checkComponentPermission(
4643 android.Manifest.permission.CLEAR_APP_USER_DATA,
4644 pid, uid, -1)
4645 == PackageManager.PERMISSION_GRANTED) {
4646 restartPackageLocked(packageName, pkgUid);
4647 } else {
4648 throw new SecurityException(pid+" does not have permission:"+
4649 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4650 "for process:"+packageName);
4651 }
4652 }
4653
4654 try {
4655 //clear application user data
4656 pm.clearApplicationUserData(packageName, observer);
4657 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4658 Uri.fromParts("package", packageName, null));
4659 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4660 broadcastIntentLocked(null, null, intent,
4661 null, null, 0, null, null, null,
4662 false, false, MY_PID, Process.SYSTEM_UID);
4663 } catch (RemoteException e) {
4664 }
4665 } finally {
4666 Binder.restoreCallingIdentity(callingId);
4667 }
4668 return true;
4669 }
4670
4671 public void restartPackage(final String packageName) {
4672 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4673 != PackageManager.PERMISSION_GRANTED) {
4674 String msg = "Permission Denial: restartPackage() from pid="
4675 + Binder.getCallingPid()
4676 + ", uid=" + Binder.getCallingUid()
4677 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4678 Log.w(TAG, msg);
4679 throw new SecurityException(msg);
4680 }
4681
4682 long callingId = Binder.clearCallingIdentity();
4683 try {
4684 IPackageManager pm = ActivityThread.getPackageManager();
4685 int pkgUid = -1;
4686 synchronized(this) {
4687 try {
4688 pkgUid = pm.getPackageUid(packageName);
4689 } catch (RemoteException e) {
4690 }
4691 if (pkgUid == -1) {
4692 Log.w(TAG, "Invalid packageName: " + packageName);
4693 return;
4694 }
4695 restartPackageLocked(packageName, pkgUid);
4696 }
4697 } finally {
4698 Binder.restoreCallingIdentity(callingId);
4699 }
4700 }
4701
4702 private void restartPackageLocked(final String packageName, int uid) {
4703 uninstallPackageLocked(packageName, uid, false);
4704 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4705 Uri.fromParts("package", packageName, null));
4706 intent.putExtra(Intent.EXTRA_UID, uid);
4707 broadcastIntentLocked(null, null, intent,
4708 null, null, 0, null, null, null,
4709 false, false, MY_PID, Process.SYSTEM_UID);
4710 }
4711
4712 private final void uninstallPackageLocked(String name, int uid,
4713 boolean callerWillRestart) {
4714 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4715
4716 int i, N;
4717
4718 final String procNamePrefix = name + ":";
4719 if (uid < 0) {
4720 try {
4721 uid = ActivityThread.getPackageManager().getPackageUid(name);
4722 } catch (RemoteException e) {
4723 }
4724 }
4725
4726 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4727 while (badApps.hasNext()) {
4728 SparseArray<Long> ba = badApps.next();
4729 if (ba.get(uid) != null) {
4730 badApps.remove();
4731 }
4732 }
4733
4734 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4735
4736 // Remove all processes this package may have touched: all with the
4737 // same UID (except for the system or root user), and all whose name
4738 // matches the package name.
4739 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4740 final int NA = apps.size();
4741 for (int ia=0; ia<NA; ia++) {
4742 ProcessRecord app = apps.valueAt(ia);
4743 if (app.removed) {
4744 procs.add(app);
4745 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4746 || app.processName.equals(name)
4747 || app.processName.startsWith(procNamePrefix)) {
4748 app.removed = true;
4749 procs.add(app);
4750 }
4751 }
4752 }
4753
4754 N = procs.size();
4755 for (i=0; i<N; i++) {
4756 removeProcessLocked(procs.get(i), callerWillRestart);
4757 }
4758
4759 for (i=mHistory.size()-1; i>=0; i--) {
4760 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4761 if (r.packageName.equals(name)) {
4762 if (Config.LOGD) Log.d(
4763 TAG, " Force finishing activity "
4764 + r.intent.getComponent().flattenToShortString());
4765 if (r.app != null) {
4766 r.app.removed = true;
4767 }
4768 r.app = null;
4769 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4770 }
4771 }
4772
4773 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4774 for (ServiceRecord service : mServices.values()) {
4775 if (service.packageName.equals(name)) {
4776 if (service.app != null) {
4777 service.app.removed = true;
4778 }
4779 service.app = null;
4780 services.add(service);
4781 }
4782 }
4783
4784 N = services.size();
4785 for (i=0; i<N; i++) {
4786 bringDownServiceLocked(services.get(i), true);
4787 }
4788
4789 resumeTopActivityLocked(null);
4790 }
4791
4792 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4793 final String name = app.processName;
4794 final int uid = app.info.uid;
4795 if (Config.LOGD) Log.d(
4796 TAG, "Force removing process " + app + " (" + name
4797 + "/" + uid + ")");
4798
4799 mProcessNames.remove(name, uid);
4800 boolean needRestart = false;
4801 if (app.pid > 0 && app.pid != MY_PID) {
4802 int pid = app.pid;
4803 synchronized (mPidsSelfLocked) {
4804 mPidsSelfLocked.remove(pid);
4805 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4806 }
4807 handleAppDiedLocked(app, true);
4808 mLRUProcesses.remove(app);
4809 Process.killProcess(pid);
4810
4811 if (app.persistent) {
4812 if (!callerWillRestart) {
4813 addAppLocked(app.info);
4814 } else {
4815 needRestart = true;
4816 }
4817 }
4818 } else {
4819 mRemovedProcesses.add(app);
4820 }
4821
4822 return needRestart;
4823 }
4824
4825 private final void processStartTimedOutLocked(ProcessRecord app) {
4826 final int pid = app.pid;
4827 boolean gone = false;
4828 synchronized (mPidsSelfLocked) {
4829 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4830 if (knownApp != null && knownApp.thread == null) {
4831 mPidsSelfLocked.remove(pid);
4832 gone = true;
4833 }
4834 }
4835
4836 if (gone) {
4837 Log.w(TAG, "Process " + app + " failed to attach");
4838 mProcessNames.remove(app.processName, app.info.uid);
4839 Process.killProcess(pid);
4840 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4841 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4842 mPendingBroadcast = null;
4843 scheduleBroadcastsLocked();
4844 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004845 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4846 Log.w(TAG, "Unattached app died before backup, skipping");
4847 try {
4848 IBackupManager bm = IBackupManager.Stub.asInterface(
4849 ServiceManager.getService(Context.BACKUP_SERVICE));
4850 bm.agentDisconnected(app.info.packageName);
4851 } catch (RemoteException e) {
4852 // Can't happen; the backup manager is local
4853 }
4854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004855 } else {
4856 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4857 }
4858 }
4859
4860 private final boolean attachApplicationLocked(IApplicationThread thread,
4861 int pid) {
4862
4863 // Find the application record that is being attached... either via
4864 // the pid if we are running in multiple processes, or just pull the
4865 // next app record if we are emulating process with anonymous threads.
4866 ProcessRecord app;
4867 if (pid != MY_PID && pid >= 0) {
4868 synchronized (mPidsSelfLocked) {
4869 app = mPidsSelfLocked.get(pid);
4870 }
4871 } else if (mStartingProcesses.size() > 0) {
4872 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004873 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004874 } else {
4875 app = null;
4876 }
4877
4878 if (app == null) {
4879 Log.w(TAG, "No pending application record for pid " + pid
4880 + " (IApplicationThread " + thread + "); dropping process");
4881 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4882 if (pid > 0 && pid != MY_PID) {
4883 Process.killProcess(pid);
4884 } else {
4885 try {
4886 thread.scheduleExit();
4887 } catch (Exception e) {
4888 // Ignore exceptions.
4889 }
4890 }
4891 return false;
4892 }
4893
4894 // If this application record is still attached to a previous
4895 // process, clean it up now.
4896 if (app.thread != null) {
4897 handleAppDiedLocked(app, true);
4898 }
4899
4900 // Tell the process all about itself.
4901
4902 if (localLOGV) Log.v(
4903 TAG, "Binding process pid " + pid + " to record " + app);
4904
4905 String processName = app.processName;
4906 try {
4907 thread.asBinder().linkToDeath(new AppDeathRecipient(
4908 app, pid, thread), 0);
4909 } catch (RemoteException e) {
4910 app.resetPackageList();
4911 startProcessLocked(app, "link fail", processName);
4912 return false;
4913 }
4914
4915 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4916
4917 app.thread = thread;
4918 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004919 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004920 app.forcingToForeground = null;
4921 app.foregroundServices = false;
4922 app.debugging = false;
4923
4924 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4925
4926 List providers = generateApplicationProvidersLocked(app);
4927
4928 if (localLOGV) Log.v(
4929 TAG, "New app record " + app
4930 + " thread=" + thread.asBinder() + " pid=" + pid);
4931 try {
4932 int testMode = IApplicationThread.DEBUG_OFF;
4933 if (mDebugApp != null && mDebugApp.equals(processName)) {
4934 testMode = mWaitForDebugger
4935 ? IApplicationThread.DEBUG_WAIT
4936 : IApplicationThread.DEBUG_ON;
4937 app.debugging = true;
4938 if (mDebugTransient) {
4939 mDebugApp = mOrigDebugApp;
4940 mWaitForDebugger = mOrigWaitForDebugger;
4941 }
4942 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004943 // If the app is being launched for restore or full backup, set it up specially
4944 boolean isRestrictedBackupMode = false;
4945 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4946 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4947 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4948 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004949 ensurePackageDexOpt(app.instrumentationInfo != null
4950 ? app.instrumentationInfo.packageName
4951 : app.info.packageName);
4952 if (app.instrumentationClass != null) {
4953 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004954 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004955 thread.bindApplication(processName, app.instrumentationInfo != null
4956 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004957 app.instrumentationClass, app.instrumentationProfileFile,
4958 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004959 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004960 updateLRUListLocked(app, false);
4961 app.lastRequestedGc = SystemClock.uptimeMillis();
4962 } catch (Exception e) {
4963 // todo: Yikes! What should we do? For now we will try to
4964 // start another process, but that could easily get us in
4965 // an infinite loop of restarting processes...
4966 Log.w(TAG, "Exception thrown during bind!", e);
4967
4968 app.resetPackageList();
4969 startProcessLocked(app, "bind fail", processName);
4970 return false;
4971 }
4972
4973 // Remove this record from the list of starting applications.
4974 mPersistentStartingProcesses.remove(app);
4975 mProcessesOnHold.remove(app);
4976
4977 boolean badApp = false;
4978 boolean didSomething = false;
4979
4980 // See if the top visible activity is waiting to run in this process...
4981 HistoryRecord hr = topRunningActivityLocked(null);
4982 if (hr != null) {
4983 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4984 && processName.equals(hr.processName)) {
4985 try {
4986 if (realStartActivityLocked(hr, app, true, true)) {
4987 didSomething = true;
4988 }
4989 } catch (Exception e) {
4990 Log.w(TAG, "Exception in new application when starting activity "
4991 + hr.intent.getComponent().flattenToShortString(), e);
4992 badApp = true;
4993 }
4994 } else {
4995 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4996 }
4997 }
4998
4999 // Find any services that should be running in this process...
5000 if (!badApp && mPendingServices.size() > 0) {
5001 ServiceRecord sr = null;
5002 try {
5003 for (int i=0; i<mPendingServices.size(); i++) {
5004 sr = mPendingServices.get(i);
5005 if (app.info.uid != sr.appInfo.uid
5006 || !processName.equals(sr.processName)) {
5007 continue;
5008 }
5009
5010 mPendingServices.remove(i);
5011 i--;
5012 realStartServiceLocked(sr, app);
5013 didSomething = true;
5014 }
5015 } catch (Exception e) {
5016 Log.w(TAG, "Exception in new application when starting service "
5017 + sr.shortName, e);
5018 badApp = true;
5019 }
5020 }
5021
5022 // Check if the next broadcast receiver is in this process...
5023 BroadcastRecord br = mPendingBroadcast;
5024 if (!badApp && br != null && br.curApp == app) {
5025 try {
5026 mPendingBroadcast = null;
5027 processCurBroadcastLocked(br, app);
5028 didSomething = true;
5029 } catch (Exception e) {
5030 Log.w(TAG, "Exception in new application when starting receiver "
5031 + br.curComponent.flattenToShortString(), e);
5032 badApp = true;
5033 logBroadcastReceiverDiscard(br);
5034 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5035 br.resultExtras, br.resultAbort, true);
5036 scheduleBroadcastsLocked();
5037 }
5038 }
5039
Christopher Tate181fafa2009-05-14 11:12:14 -07005040 // Check whether the next backup agent is in this process...
5041 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5042 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005043 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005044 try {
5045 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5046 } catch (Exception e) {
5047 Log.w(TAG, "Exception scheduling backup agent creation: ");
5048 e.printStackTrace();
5049 }
5050 }
5051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 if (badApp) {
5053 // todo: Also need to kill application to deal with all
5054 // kinds of exceptions.
5055 handleAppDiedLocked(app, false);
5056 return false;
5057 }
5058
5059 if (!didSomething) {
5060 updateOomAdjLocked();
5061 }
5062
5063 return true;
5064 }
5065
5066 public final void attachApplication(IApplicationThread thread) {
5067 synchronized (this) {
5068 int callingPid = Binder.getCallingPid();
5069 final long origId = Binder.clearCallingIdentity();
5070 attachApplicationLocked(thread, callingPid);
5071 Binder.restoreCallingIdentity(origId);
5072 }
5073 }
5074
5075 public final void activityIdle(IBinder token) {
5076 final long origId = Binder.clearCallingIdentity();
5077 activityIdleInternal(token, false);
5078 Binder.restoreCallingIdentity(origId);
5079 }
5080
5081 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5082 boolean remove) {
5083 int N = mStoppingActivities.size();
5084 if (N <= 0) return null;
5085
5086 ArrayList<HistoryRecord> stops = null;
5087
5088 final boolean nowVisible = mResumedActivity != null
5089 && mResumedActivity.nowVisible
5090 && !mResumedActivity.waitingVisible;
5091 for (int i=0; i<N; i++) {
5092 HistoryRecord s = mStoppingActivities.get(i);
5093 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5094 + nowVisible + " waitingVisible=" + s.waitingVisible
5095 + " finishing=" + s.finishing);
5096 if (s.waitingVisible && nowVisible) {
5097 mWaitingVisibleActivities.remove(s);
5098 s.waitingVisible = false;
5099 if (s.finishing) {
5100 // If this activity is finishing, it is sitting on top of
5101 // everyone else but we now know it is no longer needed...
5102 // so get rid of it. Otherwise, we need to go through the
5103 // normal flow and hide it once we determine that it is
5104 // hidden by the activities in front of it.
5105 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5106 mWindowManager.setAppVisibility(s, false);
5107 }
5108 }
5109 if (!s.waitingVisible && remove) {
5110 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5111 if (stops == null) {
5112 stops = new ArrayList<HistoryRecord>();
5113 }
5114 stops.add(s);
5115 mStoppingActivities.remove(i);
5116 N--;
5117 i--;
5118 }
5119 }
5120
5121 return stops;
5122 }
5123
5124 void enableScreenAfterBoot() {
5125 mWindowManager.enableScreenAfterBoot();
5126 }
5127
5128 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5129 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5130
5131 ArrayList<HistoryRecord> stops = null;
5132 ArrayList<HistoryRecord> finishes = null;
5133 ArrayList<HistoryRecord> thumbnails = null;
5134 int NS = 0;
5135 int NF = 0;
5136 int NT = 0;
5137 IApplicationThread sendThumbnail = null;
5138 boolean booting = false;
5139 boolean enableScreen = false;
5140
5141 synchronized (this) {
5142 if (token != null) {
5143 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5144 }
5145
5146 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005147 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005148 if (index >= 0) {
5149 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5150
5151 // No longer need to keep the device awake.
5152 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5153 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5154 mLaunchingActivity.release();
5155 }
5156
5157 // We are now idle. If someone is waiting for a thumbnail from
5158 // us, we can now deliver.
5159 r.idle = true;
5160 scheduleAppGcsLocked();
5161 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5162 sendThumbnail = r.app.thread;
5163 r.thumbnailNeeded = false;
5164 }
5165
5166 // If this activity is fullscreen, set up to hide those under it.
5167
5168 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5169 ensureActivitiesVisibleLocked(null, 0);
5170
5171 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5172 if (!mBooted && !fromTimeout) {
5173 mBooted = true;
5174 enableScreen = true;
5175 }
5176 }
5177
5178 // Atomically retrieve all of the other things to do.
5179 stops = processStoppingActivitiesLocked(true);
5180 NS = stops != null ? stops.size() : 0;
5181 if ((NF=mFinishingActivities.size()) > 0) {
5182 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5183 mFinishingActivities.clear();
5184 }
5185 if ((NT=mCancelledThumbnails.size()) > 0) {
5186 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5187 mCancelledThumbnails.clear();
5188 }
5189
5190 booting = mBooting;
5191 mBooting = false;
5192 }
5193
5194 int i;
5195
5196 // Send thumbnail if requested.
5197 if (sendThumbnail != null) {
5198 try {
5199 sendThumbnail.requestThumbnail(token);
5200 } catch (Exception e) {
5201 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5202 sendPendingThumbnail(null, token, null, null, true);
5203 }
5204 }
5205
5206 // Stop any activities that are scheduled to do so but have been
5207 // waiting for the next one to start.
5208 for (i=0; i<NS; i++) {
5209 HistoryRecord r = (HistoryRecord)stops.get(i);
5210 synchronized (this) {
5211 if (r.finishing) {
5212 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5213 } else {
5214 stopActivityLocked(r);
5215 }
5216 }
5217 }
5218
5219 // Finish any activities that are scheduled to do so but have been
5220 // waiting for the next one to start.
5221 for (i=0; i<NF; i++) {
5222 HistoryRecord r = (HistoryRecord)finishes.get(i);
5223 synchronized (this) {
5224 destroyActivityLocked(r, true);
5225 }
5226 }
5227
5228 // Report back to any thumbnail receivers.
5229 for (i=0; i<NT; i++) {
5230 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5231 sendPendingThumbnail(r, null, null, null, true);
5232 }
5233
5234 if (booting) {
5235 // Ensure that any processes we had put on hold are now started
5236 // up.
5237 final int NP = mProcessesOnHold.size();
5238 if (NP > 0) {
5239 ArrayList<ProcessRecord> procs =
5240 new ArrayList<ProcessRecord>(mProcessesOnHold);
5241 for (int ip=0; ip<NP; ip++) {
5242 this.startProcessLocked(procs.get(ip), "on-hold", null);
5243 }
5244 }
5245 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5246 // Tell anyone interested that we are done booting!
5247 synchronized (this) {
5248 broadcastIntentLocked(null, null,
5249 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5250 null, null, 0, null, null,
5251 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5252 false, false, MY_PID, Process.SYSTEM_UID);
5253 }
5254 }
5255 }
5256
5257 trimApplications();
5258 //dump();
5259 //mWindowManager.dump();
5260
5261 if (enableScreen) {
5262 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5263 SystemClock.uptimeMillis());
5264 enableScreenAfterBoot();
5265 }
5266 }
5267
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005268 final void ensureScreenEnabled() {
5269 boolean enableScreen;
5270 synchronized (this) {
5271 enableScreen = !mBooted;
5272 mBooted = true;
5273 }
5274
5275 if (enableScreen) {
5276 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5277 SystemClock.uptimeMillis());
5278 enableScreenAfterBoot();
5279 }
5280 }
5281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005282 public final void activityPaused(IBinder token, Bundle icicle) {
5283 // Refuse possible leaked file descriptors
5284 if (icicle != null && icicle.hasFileDescriptors()) {
5285 throw new IllegalArgumentException("File descriptors passed in Bundle");
5286 }
5287
5288 final long origId = Binder.clearCallingIdentity();
5289 activityPaused(token, icicle, false);
5290 Binder.restoreCallingIdentity(origId);
5291 }
5292
5293 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5294 if (DEBUG_PAUSE) Log.v(
5295 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5296 + ", timeout=" + timeout);
5297
5298 HistoryRecord r = null;
5299
5300 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005301 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005302 if (index >= 0) {
5303 r = (HistoryRecord)mHistory.get(index);
5304 if (!timeout) {
5305 r.icicle = icicle;
5306 r.haveState = true;
5307 }
5308 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5309 if (mPausingActivity == r) {
5310 r.state = ActivityState.PAUSED;
5311 completePauseLocked();
5312 } else {
5313 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5314 System.identityHashCode(r), r.shortComponentName,
5315 mPausingActivity != null
5316 ? mPausingActivity.shortComponentName : "(none)");
5317 }
5318 }
5319 }
5320 }
5321
5322 public final void activityStopped(IBinder token, Bitmap thumbnail,
5323 CharSequence description) {
5324 if (localLOGV) Log.v(
5325 TAG, "Activity stopped: token=" + token);
5326
5327 HistoryRecord r = null;
5328
5329 final long origId = Binder.clearCallingIdentity();
5330
5331 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005332 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005333 if (index >= 0) {
5334 r = (HistoryRecord)mHistory.get(index);
5335 r.thumbnail = thumbnail;
5336 r.description = description;
5337 r.stopped = true;
5338 r.state = ActivityState.STOPPED;
5339 if (!r.finishing) {
5340 if (r.configDestroy) {
5341 destroyActivityLocked(r, true);
5342 resumeTopActivityLocked(null);
5343 }
5344 }
5345 }
5346 }
5347
5348 if (r != null) {
5349 sendPendingThumbnail(r, null, null, null, false);
5350 }
5351
5352 trimApplications();
5353
5354 Binder.restoreCallingIdentity(origId);
5355 }
5356
5357 public final void activityDestroyed(IBinder token) {
5358 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5359 synchronized (this) {
5360 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5361
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 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5365 if (r.state == ActivityState.DESTROYING) {
5366 final long origId = Binder.clearCallingIdentity();
5367 removeActivityFromHistoryLocked(r);
5368 Binder.restoreCallingIdentity(origId);
5369 }
5370 }
5371 }
5372 }
5373
5374 public String getCallingPackage(IBinder token) {
5375 synchronized (this) {
5376 HistoryRecord r = getCallingRecordLocked(token);
5377 return r != null && r.app != null ? r.app.processName : null;
5378 }
5379 }
5380
5381 public ComponentName getCallingActivity(IBinder token) {
5382 synchronized (this) {
5383 HistoryRecord r = getCallingRecordLocked(token);
5384 return r != null ? r.intent.getComponent() : null;
5385 }
5386 }
5387
5388 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005389 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005390 if (index >= 0) {
5391 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5392 if (r != null) {
5393 return r.resultTo;
5394 }
5395 }
5396 return null;
5397 }
5398
5399 public ComponentName getActivityClassForToken(IBinder token) {
5400 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005401 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005402 if (index >= 0) {
5403 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5404 return r.intent.getComponent();
5405 }
5406 return null;
5407 }
5408 }
5409
5410 public String getPackageForToken(IBinder token) {
5411 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005412 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005413 if (index >= 0) {
5414 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5415 return r.packageName;
5416 }
5417 return null;
5418 }
5419 }
5420
5421 public IIntentSender getIntentSender(int type,
5422 String packageName, IBinder token, String resultWho,
5423 int requestCode, Intent intent, String resolvedType, int flags) {
5424 // Refuse possible leaked file descriptors
5425 if (intent != null && intent.hasFileDescriptors() == true) {
5426 throw new IllegalArgumentException("File descriptors passed in Intent");
5427 }
5428
5429 synchronized(this) {
5430 int callingUid = Binder.getCallingUid();
5431 try {
5432 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5433 Process.supportsProcesses()) {
5434 int uid = ActivityThread.getPackageManager()
5435 .getPackageUid(packageName);
5436 if (uid != Binder.getCallingUid()) {
5437 String msg = "Permission Denial: getIntentSender() from pid="
5438 + Binder.getCallingPid()
5439 + ", uid=" + Binder.getCallingUid()
5440 + ", (need uid=" + uid + ")"
5441 + " is not allowed to send as package " + packageName;
5442 Log.w(TAG, msg);
5443 throw new SecurityException(msg);
5444 }
5445 }
5446 } catch (RemoteException e) {
5447 throw new SecurityException(e);
5448 }
5449 HistoryRecord activity = null;
5450 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005451 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 if (index < 0) {
5453 return null;
5454 }
5455 activity = (HistoryRecord)mHistory.get(index);
5456 if (activity.finishing) {
5457 return null;
5458 }
5459 }
5460
5461 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5462 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5463 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5464 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5465 |PendingIntent.FLAG_UPDATE_CURRENT);
5466
5467 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5468 type, packageName, activity, resultWho,
5469 requestCode, intent, resolvedType, flags);
5470 WeakReference<PendingIntentRecord> ref;
5471 ref = mIntentSenderRecords.get(key);
5472 PendingIntentRecord rec = ref != null ? ref.get() : null;
5473 if (rec != null) {
5474 if (!cancelCurrent) {
5475 if (updateCurrent) {
5476 rec.key.requestIntent.replaceExtras(intent);
5477 }
5478 return rec;
5479 }
5480 rec.canceled = true;
5481 mIntentSenderRecords.remove(key);
5482 }
5483 if (noCreate) {
5484 return rec;
5485 }
5486 rec = new PendingIntentRecord(this, key, callingUid);
5487 mIntentSenderRecords.put(key, rec.ref);
5488 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5489 if (activity.pendingResults == null) {
5490 activity.pendingResults
5491 = new HashSet<WeakReference<PendingIntentRecord>>();
5492 }
5493 activity.pendingResults.add(rec.ref);
5494 }
5495 return rec;
5496 }
5497 }
5498
5499 public void cancelIntentSender(IIntentSender sender) {
5500 if (!(sender instanceof PendingIntentRecord)) {
5501 return;
5502 }
5503 synchronized(this) {
5504 PendingIntentRecord rec = (PendingIntentRecord)sender;
5505 try {
5506 int uid = ActivityThread.getPackageManager()
5507 .getPackageUid(rec.key.packageName);
5508 if (uid != Binder.getCallingUid()) {
5509 String msg = "Permission Denial: cancelIntentSender() from pid="
5510 + Binder.getCallingPid()
5511 + ", uid=" + Binder.getCallingUid()
5512 + " is not allowed to cancel packges "
5513 + rec.key.packageName;
5514 Log.w(TAG, msg);
5515 throw new SecurityException(msg);
5516 }
5517 } catch (RemoteException e) {
5518 throw new SecurityException(e);
5519 }
5520 cancelIntentSenderLocked(rec, true);
5521 }
5522 }
5523
5524 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5525 rec.canceled = true;
5526 mIntentSenderRecords.remove(rec.key);
5527 if (cleanActivity && rec.key.activity != null) {
5528 rec.key.activity.pendingResults.remove(rec.ref);
5529 }
5530 }
5531
5532 public String getPackageForIntentSender(IIntentSender pendingResult) {
5533 if (!(pendingResult instanceof PendingIntentRecord)) {
5534 return null;
5535 }
5536 synchronized(this) {
5537 try {
5538 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5539 return res.key.packageName;
5540 } catch (ClassCastException e) {
5541 }
5542 }
5543 return null;
5544 }
5545
5546 public void setProcessLimit(int max) {
5547 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5548 "setProcessLimit()");
5549 mProcessLimit = max;
5550 }
5551
5552 public int getProcessLimit() {
5553 return mProcessLimit;
5554 }
5555
5556 void foregroundTokenDied(ForegroundToken token) {
5557 synchronized (ActivityManagerService.this) {
5558 synchronized (mPidsSelfLocked) {
5559 ForegroundToken cur
5560 = mForegroundProcesses.get(token.pid);
5561 if (cur != token) {
5562 return;
5563 }
5564 mForegroundProcesses.remove(token.pid);
5565 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5566 if (pr == null) {
5567 return;
5568 }
5569 pr.forcingToForeground = null;
5570 pr.foregroundServices = false;
5571 }
5572 updateOomAdjLocked();
5573 }
5574 }
5575
5576 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5577 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5578 "setProcessForeground()");
5579 synchronized(this) {
5580 boolean changed = false;
5581
5582 synchronized (mPidsSelfLocked) {
5583 ProcessRecord pr = mPidsSelfLocked.get(pid);
5584 if (pr == null) {
5585 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5586 return;
5587 }
5588 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5589 if (oldToken != null) {
5590 oldToken.token.unlinkToDeath(oldToken, 0);
5591 mForegroundProcesses.remove(pid);
5592 pr.forcingToForeground = null;
5593 changed = true;
5594 }
5595 if (isForeground && token != null) {
5596 ForegroundToken newToken = new ForegroundToken() {
5597 public void binderDied() {
5598 foregroundTokenDied(this);
5599 }
5600 };
5601 newToken.pid = pid;
5602 newToken.token = token;
5603 try {
5604 token.linkToDeath(newToken, 0);
5605 mForegroundProcesses.put(pid, newToken);
5606 pr.forcingToForeground = token;
5607 changed = true;
5608 } catch (RemoteException e) {
5609 // If the process died while doing this, we will later
5610 // do the cleanup with the process death link.
5611 }
5612 }
5613 }
5614
5615 if (changed) {
5616 updateOomAdjLocked();
5617 }
5618 }
5619 }
5620
5621 // =========================================================
5622 // PERMISSIONS
5623 // =========================================================
5624
5625 static class PermissionController extends IPermissionController.Stub {
5626 ActivityManagerService mActivityManagerService;
5627 PermissionController(ActivityManagerService activityManagerService) {
5628 mActivityManagerService = activityManagerService;
5629 }
5630
5631 public boolean checkPermission(String permission, int pid, int uid) {
5632 return mActivityManagerService.checkPermission(permission, pid,
5633 uid) == PackageManager.PERMISSION_GRANTED;
5634 }
5635 }
5636
5637 /**
5638 * This can be called with or without the global lock held.
5639 */
5640 int checkComponentPermission(String permission, int pid, int uid,
5641 int reqUid) {
5642 // We might be performing an operation on behalf of an indirect binder
5643 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5644 // client identity accordingly before proceeding.
5645 Identity tlsIdentity = sCallerIdentity.get();
5646 if (tlsIdentity != null) {
5647 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5648 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5649 uid = tlsIdentity.uid;
5650 pid = tlsIdentity.pid;
5651 }
5652
5653 // Root, system server and our own process get to do everything.
5654 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5655 !Process.supportsProcesses()) {
5656 return PackageManager.PERMISSION_GRANTED;
5657 }
5658 // If the target requires a specific UID, always fail for others.
5659 if (reqUid >= 0 && uid != reqUid) {
5660 return PackageManager.PERMISSION_DENIED;
5661 }
5662 if (permission == null) {
5663 return PackageManager.PERMISSION_GRANTED;
5664 }
5665 try {
5666 return ActivityThread.getPackageManager()
5667 .checkUidPermission(permission, uid);
5668 } catch (RemoteException e) {
5669 // Should never happen, but if it does... deny!
5670 Log.e(TAG, "PackageManager is dead?!?", e);
5671 }
5672 return PackageManager.PERMISSION_DENIED;
5673 }
5674
5675 /**
5676 * As the only public entry point for permissions checking, this method
5677 * can enforce the semantic that requesting a check on a null global
5678 * permission is automatically denied. (Internally a null permission
5679 * string is used when calling {@link #checkComponentPermission} in cases
5680 * when only uid-based security is needed.)
5681 *
5682 * This can be called with or without the global lock held.
5683 */
5684 public int checkPermission(String permission, int pid, int uid) {
5685 if (permission == null) {
5686 return PackageManager.PERMISSION_DENIED;
5687 }
5688 return checkComponentPermission(permission, pid, uid, -1);
5689 }
5690
5691 /**
5692 * Binder IPC calls go through the public entry point.
5693 * This can be called with or without the global lock held.
5694 */
5695 int checkCallingPermission(String permission) {
5696 return checkPermission(permission,
5697 Binder.getCallingPid(),
5698 Binder.getCallingUid());
5699 }
5700
5701 /**
5702 * This can be called with or without the global lock held.
5703 */
5704 void enforceCallingPermission(String permission, String func) {
5705 if (checkCallingPermission(permission)
5706 == PackageManager.PERMISSION_GRANTED) {
5707 return;
5708 }
5709
5710 String msg = "Permission Denial: " + func + " from pid="
5711 + Binder.getCallingPid()
5712 + ", uid=" + Binder.getCallingUid()
5713 + " requires " + permission;
5714 Log.w(TAG, msg);
5715 throw new SecurityException(msg);
5716 }
5717
5718 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5719 ProviderInfo pi, int uid, int modeFlags) {
5720 try {
5721 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5722 if ((pi.readPermission != null) &&
5723 (pm.checkUidPermission(pi.readPermission, uid)
5724 != PackageManager.PERMISSION_GRANTED)) {
5725 return false;
5726 }
5727 }
5728 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5729 if ((pi.writePermission != null) &&
5730 (pm.checkUidPermission(pi.writePermission, uid)
5731 != PackageManager.PERMISSION_GRANTED)) {
5732 return false;
5733 }
5734 }
5735 return true;
5736 } catch (RemoteException e) {
5737 return false;
5738 }
5739 }
5740
5741 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5742 int modeFlags) {
5743 // Root gets to do everything.
5744 if (uid == 0 || !Process.supportsProcesses()) {
5745 return true;
5746 }
5747 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5748 if (perms == null) return false;
5749 UriPermission perm = perms.get(uri);
5750 if (perm == null) return false;
5751 return (modeFlags&perm.modeFlags) == modeFlags;
5752 }
5753
5754 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5755 // Another redirected-binder-call permissions check as in
5756 // {@link checkComponentPermission}.
5757 Identity tlsIdentity = sCallerIdentity.get();
5758 if (tlsIdentity != null) {
5759 uid = tlsIdentity.uid;
5760 pid = tlsIdentity.pid;
5761 }
5762
5763 // Our own process gets to do everything.
5764 if (pid == MY_PID) {
5765 return PackageManager.PERMISSION_GRANTED;
5766 }
5767 synchronized(this) {
5768 return checkUriPermissionLocked(uri, uid, modeFlags)
5769 ? PackageManager.PERMISSION_GRANTED
5770 : PackageManager.PERMISSION_DENIED;
5771 }
5772 }
5773
5774 private void grantUriPermissionLocked(int callingUid,
5775 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5776 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5777 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5778 if (modeFlags == 0) {
5779 return;
5780 }
5781
5782 final IPackageManager pm = ActivityThread.getPackageManager();
5783
5784 // If this is not a content: uri, we can't do anything with it.
5785 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5786 return;
5787 }
5788
5789 String name = uri.getAuthority();
5790 ProviderInfo pi = null;
5791 ContentProviderRecord cpr
5792 = (ContentProviderRecord)mProvidersByName.get(name);
5793 if (cpr != null) {
5794 pi = cpr.info;
5795 } else {
5796 try {
5797 pi = pm.resolveContentProvider(name,
5798 PackageManager.GET_URI_PERMISSION_PATTERNS);
5799 } catch (RemoteException ex) {
5800 }
5801 }
5802 if (pi == null) {
5803 Log.w(TAG, "No content provider found for: " + name);
5804 return;
5805 }
5806
5807 int targetUid;
5808 try {
5809 targetUid = pm.getPackageUid(targetPkg);
5810 if (targetUid < 0) {
5811 return;
5812 }
5813 } catch (RemoteException ex) {
5814 return;
5815 }
5816
5817 // First... does the target actually need this permission?
5818 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5819 // No need to grant the target this permission.
5820 return;
5821 }
5822
5823 // Second... maybe someone else has already granted the
5824 // permission?
5825 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5826 // No need to grant the target this permission.
5827 return;
5828 }
5829
5830 // Third... is the provider allowing granting of URI permissions?
5831 if (!pi.grantUriPermissions) {
5832 throw new SecurityException("Provider " + pi.packageName
5833 + "/" + pi.name
5834 + " does not allow granting of Uri permissions (uri "
5835 + uri + ")");
5836 }
5837 if (pi.uriPermissionPatterns != null) {
5838 final int N = pi.uriPermissionPatterns.length;
5839 boolean allowed = false;
5840 for (int i=0; i<N; i++) {
5841 if (pi.uriPermissionPatterns[i] != null
5842 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5843 allowed = true;
5844 break;
5845 }
5846 }
5847 if (!allowed) {
5848 throw new SecurityException("Provider " + pi.packageName
5849 + "/" + pi.name
5850 + " does not allow granting of permission to path of Uri "
5851 + uri);
5852 }
5853 }
5854
5855 // Fourth... does the caller itself have permission to access
5856 // this uri?
5857 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5858 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5859 throw new SecurityException("Uid " + callingUid
5860 + " does not have permission to uri " + uri);
5861 }
5862 }
5863
5864 // Okay! So here we are: the caller has the assumed permission
5865 // to the uri, and the target doesn't. Let's now give this to
5866 // the target.
5867
5868 HashMap<Uri, UriPermission> targetUris
5869 = mGrantedUriPermissions.get(targetUid);
5870 if (targetUris == null) {
5871 targetUris = new HashMap<Uri, UriPermission>();
5872 mGrantedUriPermissions.put(targetUid, targetUris);
5873 }
5874
5875 UriPermission perm = targetUris.get(uri);
5876 if (perm == null) {
5877 perm = new UriPermission(targetUid, uri);
5878 targetUris.put(uri, perm);
5879
5880 }
5881 perm.modeFlags |= modeFlags;
5882 if (activity == null) {
5883 perm.globalModeFlags |= modeFlags;
5884 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5885 perm.readActivities.add(activity);
5886 if (activity.readUriPermissions == null) {
5887 activity.readUriPermissions = new HashSet<UriPermission>();
5888 }
5889 activity.readUriPermissions.add(perm);
5890 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5891 perm.writeActivities.add(activity);
5892 if (activity.writeUriPermissions == null) {
5893 activity.writeUriPermissions = new HashSet<UriPermission>();
5894 }
5895 activity.writeUriPermissions.add(perm);
5896 }
5897 }
5898
5899 private void grantUriPermissionFromIntentLocked(int callingUid,
5900 String targetPkg, Intent intent, HistoryRecord activity) {
5901 if (intent == null) {
5902 return;
5903 }
5904 Uri data = intent.getData();
5905 if (data == null) {
5906 return;
5907 }
5908 grantUriPermissionLocked(callingUid, targetPkg, data,
5909 intent.getFlags(), activity);
5910 }
5911
5912 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5913 Uri uri, int modeFlags) {
5914 synchronized(this) {
5915 final ProcessRecord r = getRecordForAppLocked(caller);
5916 if (r == null) {
5917 throw new SecurityException("Unable to find app for caller "
5918 + caller
5919 + " when granting permission to uri " + uri);
5920 }
5921 if (targetPkg == null) {
5922 Log.w(TAG, "grantUriPermission: null target");
5923 return;
5924 }
5925 if (uri == null) {
5926 Log.w(TAG, "grantUriPermission: null uri");
5927 return;
5928 }
5929
5930 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5931 null);
5932 }
5933 }
5934
5935 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5936 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5937 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5938 HashMap<Uri, UriPermission> perms
5939 = mGrantedUriPermissions.get(perm.uid);
5940 if (perms != null) {
5941 perms.remove(perm.uri);
5942 if (perms.size() == 0) {
5943 mGrantedUriPermissions.remove(perm.uid);
5944 }
5945 }
5946 }
5947 }
5948
5949 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5950 if (activity.readUriPermissions != null) {
5951 for (UriPermission perm : activity.readUriPermissions) {
5952 perm.readActivities.remove(activity);
5953 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5954 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5955 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5956 removeUriPermissionIfNeededLocked(perm);
5957 }
5958 }
5959 }
5960 if (activity.writeUriPermissions != null) {
5961 for (UriPermission perm : activity.writeUriPermissions) {
5962 perm.writeActivities.remove(activity);
5963 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5964 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5965 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5966 removeUriPermissionIfNeededLocked(perm);
5967 }
5968 }
5969 }
5970 }
5971
5972 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5973 int modeFlags) {
5974 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5975 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5976 if (modeFlags == 0) {
5977 return;
5978 }
5979
5980 final IPackageManager pm = ActivityThread.getPackageManager();
5981
5982 final String authority = uri.getAuthority();
5983 ProviderInfo pi = null;
5984 ContentProviderRecord cpr
5985 = (ContentProviderRecord)mProvidersByName.get(authority);
5986 if (cpr != null) {
5987 pi = cpr.info;
5988 } else {
5989 try {
5990 pi = pm.resolveContentProvider(authority,
5991 PackageManager.GET_URI_PERMISSION_PATTERNS);
5992 } catch (RemoteException ex) {
5993 }
5994 }
5995 if (pi == null) {
5996 Log.w(TAG, "No content provider found for: " + authority);
5997 return;
5998 }
5999
6000 // Does the caller have this permission on the URI?
6001 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6002 // Right now, if you are not the original owner of the permission,
6003 // you are not allowed to revoke it.
6004 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6005 throw new SecurityException("Uid " + callingUid
6006 + " does not have permission to uri " + uri);
6007 //}
6008 }
6009
6010 // Go through all of the permissions and remove any that match.
6011 final List<String> SEGMENTS = uri.getPathSegments();
6012 if (SEGMENTS != null) {
6013 final int NS = SEGMENTS.size();
6014 int N = mGrantedUriPermissions.size();
6015 for (int i=0; i<N; i++) {
6016 HashMap<Uri, UriPermission> perms
6017 = mGrantedUriPermissions.valueAt(i);
6018 Iterator<UriPermission> it = perms.values().iterator();
6019 toploop:
6020 while (it.hasNext()) {
6021 UriPermission perm = it.next();
6022 Uri targetUri = perm.uri;
6023 if (!authority.equals(targetUri.getAuthority())) {
6024 continue;
6025 }
6026 List<String> targetSegments = targetUri.getPathSegments();
6027 if (targetSegments == null) {
6028 continue;
6029 }
6030 if (targetSegments.size() < NS) {
6031 continue;
6032 }
6033 for (int j=0; j<NS; j++) {
6034 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6035 continue toploop;
6036 }
6037 }
6038 perm.clearModes(modeFlags);
6039 if (perm.modeFlags == 0) {
6040 it.remove();
6041 }
6042 }
6043 if (perms.size() == 0) {
6044 mGrantedUriPermissions.remove(
6045 mGrantedUriPermissions.keyAt(i));
6046 N--;
6047 i--;
6048 }
6049 }
6050 }
6051 }
6052
6053 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6054 int modeFlags) {
6055 synchronized(this) {
6056 final ProcessRecord r = getRecordForAppLocked(caller);
6057 if (r == null) {
6058 throw new SecurityException("Unable to find app for caller "
6059 + caller
6060 + " when revoking permission to uri " + uri);
6061 }
6062 if (uri == null) {
6063 Log.w(TAG, "revokeUriPermission: null uri");
6064 return;
6065 }
6066
6067 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6068 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6069 if (modeFlags == 0) {
6070 return;
6071 }
6072
6073 final IPackageManager pm = ActivityThread.getPackageManager();
6074
6075 final String authority = uri.getAuthority();
6076 ProviderInfo pi = null;
6077 ContentProviderRecord cpr
6078 = (ContentProviderRecord)mProvidersByName.get(authority);
6079 if (cpr != null) {
6080 pi = cpr.info;
6081 } else {
6082 try {
6083 pi = pm.resolveContentProvider(authority,
6084 PackageManager.GET_URI_PERMISSION_PATTERNS);
6085 } catch (RemoteException ex) {
6086 }
6087 }
6088 if (pi == null) {
6089 Log.w(TAG, "No content provider found for: " + authority);
6090 return;
6091 }
6092
6093 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6094 }
6095 }
6096
6097 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6098 synchronized (this) {
6099 ProcessRecord app =
6100 who != null ? getRecordForAppLocked(who) : null;
6101 if (app == null) return;
6102
6103 Message msg = Message.obtain();
6104 msg.what = WAIT_FOR_DEBUGGER_MSG;
6105 msg.obj = app;
6106 msg.arg1 = waiting ? 1 : 0;
6107 mHandler.sendMessage(msg);
6108 }
6109 }
6110
6111 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6112 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006113 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006114 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006115 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006116 }
6117
6118 // =========================================================
6119 // TASK MANAGEMENT
6120 // =========================================================
6121
6122 public List getTasks(int maxNum, int flags,
6123 IThumbnailReceiver receiver) {
6124 ArrayList list = new ArrayList();
6125
6126 PendingThumbnailsRecord pending = null;
6127 IApplicationThread topThumbnail = null;
6128 HistoryRecord topRecord = null;
6129
6130 synchronized(this) {
6131 if (localLOGV) Log.v(
6132 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6133 + ", receiver=" + receiver);
6134
6135 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6136 != PackageManager.PERMISSION_GRANTED) {
6137 if (receiver != null) {
6138 // If the caller wants to wait for pending thumbnails,
6139 // it ain't gonna get them.
6140 try {
6141 receiver.finished();
6142 } catch (RemoteException ex) {
6143 }
6144 }
6145 String msg = "Permission Denial: getTasks() from pid="
6146 + Binder.getCallingPid()
6147 + ", uid=" + Binder.getCallingUid()
6148 + " requires " + android.Manifest.permission.GET_TASKS;
6149 Log.w(TAG, msg);
6150 throw new SecurityException(msg);
6151 }
6152
6153 int pos = mHistory.size()-1;
6154 HistoryRecord next =
6155 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6156 HistoryRecord top = null;
6157 CharSequence topDescription = null;
6158 TaskRecord curTask = null;
6159 int numActivities = 0;
6160 int numRunning = 0;
6161 while (pos >= 0 && maxNum > 0) {
6162 final HistoryRecord r = next;
6163 pos--;
6164 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6165
6166 // Initialize state for next task if needed.
6167 if (top == null ||
6168 (top.state == ActivityState.INITIALIZING
6169 && top.task == r.task)) {
6170 top = r;
6171 topDescription = r.description;
6172 curTask = r.task;
6173 numActivities = numRunning = 0;
6174 }
6175
6176 // Add 'r' into the current task.
6177 numActivities++;
6178 if (r.app != null && r.app.thread != null) {
6179 numRunning++;
6180 }
6181 if (topDescription == null) {
6182 topDescription = r.description;
6183 }
6184
6185 if (localLOGV) Log.v(
6186 TAG, r.intent.getComponent().flattenToShortString()
6187 + ": task=" + r.task);
6188
6189 // If the next one is a different task, generate a new
6190 // TaskInfo entry for what we have.
6191 if (next == null || next.task != curTask) {
6192 ActivityManager.RunningTaskInfo ci
6193 = new ActivityManager.RunningTaskInfo();
6194 ci.id = curTask.taskId;
6195 ci.baseActivity = r.intent.getComponent();
6196 ci.topActivity = top.intent.getComponent();
6197 ci.thumbnail = top.thumbnail;
6198 ci.description = topDescription;
6199 ci.numActivities = numActivities;
6200 ci.numRunning = numRunning;
6201 //System.out.println(
6202 // "#" + maxNum + ": " + " descr=" + ci.description);
6203 if (ci.thumbnail == null && receiver != null) {
6204 if (localLOGV) Log.v(
6205 TAG, "State=" + top.state + "Idle=" + top.idle
6206 + " app=" + top.app
6207 + " thr=" + (top.app != null ? top.app.thread : null));
6208 if (top.state == ActivityState.RESUMED
6209 || top.state == ActivityState.PAUSING) {
6210 if (top.idle && top.app != null
6211 && top.app.thread != null) {
6212 topRecord = top;
6213 topThumbnail = top.app.thread;
6214 } else {
6215 top.thumbnailNeeded = true;
6216 }
6217 }
6218 if (pending == null) {
6219 pending = new PendingThumbnailsRecord(receiver);
6220 }
6221 pending.pendingRecords.add(top);
6222 }
6223 list.add(ci);
6224 maxNum--;
6225 top = null;
6226 }
6227 }
6228
6229 if (pending != null) {
6230 mPendingThumbnails.add(pending);
6231 }
6232 }
6233
6234 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6235
6236 if (topThumbnail != null) {
6237 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6238 try {
6239 topThumbnail.requestThumbnail(topRecord);
6240 } catch (Exception e) {
6241 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6242 sendPendingThumbnail(null, topRecord, null, null, true);
6243 }
6244 }
6245
6246 if (pending == null && receiver != null) {
6247 // In this case all thumbnails were available and the client
6248 // is being asked to be told when the remaining ones come in...
6249 // which is unusually, since the top-most currently running
6250 // activity should never have a canned thumbnail! Oh well.
6251 try {
6252 receiver.finished();
6253 } catch (RemoteException ex) {
6254 }
6255 }
6256
6257 return list;
6258 }
6259
6260 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6261 int flags) {
6262 synchronized (this) {
6263 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6264 "getRecentTasks()");
6265
6266 final int N = mRecentTasks.size();
6267 ArrayList<ActivityManager.RecentTaskInfo> res
6268 = new ArrayList<ActivityManager.RecentTaskInfo>(
6269 maxNum < N ? maxNum : N);
6270 for (int i=0; i<N && maxNum > 0; i++) {
6271 TaskRecord tr = mRecentTasks.get(i);
6272 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6273 || (tr.intent == null)
6274 || ((tr.intent.getFlags()
6275 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6276 ActivityManager.RecentTaskInfo rti
6277 = new ActivityManager.RecentTaskInfo();
6278 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6279 rti.baseIntent = new Intent(
6280 tr.intent != null ? tr.intent : tr.affinityIntent);
6281 rti.origActivity = tr.origActivity;
6282 res.add(rti);
6283 maxNum--;
6284 }
6285 }
6286 return res;
6287 }
6288 }
6289
6290 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6291 int j;
6292 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6293 TaskRecord jt = startTask;
6294
6295 // First look backwards
6296 for (j=startIndex-1; j>=0; j--) {
6297 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6298 if (r.task != jt) {
6299 jt = r.task;
6300 if (affinity.equals(jt.affinity)) {
6301 return j;
6302 }
6303 }
6304 }
6305
6306 // Now look forwards
6307 final int N = mHistory.size();
6308 jt = startTask;
6309 for (j=startIndex+1; j<N; j++) {
6310 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6311 if (r.task != jt) {
6312 if (affinity.equals(jt.affinity)) {
6313 return j;
6314 }
6315 jt = r.task;
6316 }
6317 }
6318
6319 // Might it be at the top?
6320 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6321 return N-1;
6322 }
6323
6324 return -1;
6325 }
6326
6327 /**
6328 * Perform a reset of the given task, if needed as part of launching it.
6329 * Returns the new HistoryRecord at the top of the task.
6330 */
6331 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6332 HistoryRecord newActivity) {
6333 boolean forceReset = (newActivity.info.flags
6334 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6335 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6336 if ((newActivity.info.flags
6337 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6338 forceReset = true;
6339 }
6340 }
6341
6342 final TaskRecord task = taskTop.task;
6343
6344 // We are going to move through the history list so that we can look
6345 // at each activity 'target' with 'below' either the interesting
6346 // activity immediately below it in the stack or null.
6347 HistoryRecord target = null;
6348 int targetI = 0;
6349 int taskTopI = -1;
6350 int replyChainEnd = -1;
6351 int lastReparentPos = -1;
6352 for (int i=mHistory.size()-1; i>=-1; i--) {
6353 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6354
6355 if (below != null && below.finishing) {
6356 continue;
6357 }
6358 if (target == null) {
6359 target = below;
6360 targetI = i;
6361 // If we were in the middle of a reply chain before this
6362 // task, it doesn't appear like the root of the chain wants
6363 // anything interesting, so drop it.
6364 replyChainEnd = -1;
6365 continue;
6366 }
6367
6368 final int flags = target.info.flags;
6369
6370 final boolean finishOnTaskLaunch =
6371 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6372 final boolean allowTaskReparenting =
6373 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6374
6375 if (target.task == task) {
6376 // We are inside of the task being reset... we'll either
6377 // finish this activity, push it out for another task,
6378 // or leave it as-is. We only do this
6379 // for activities that are not the root of the task (since
6380 // if we finish the root, we may no longer have the task!).
6381 if (taskTopI < 0) {
6382 taskTopI = targetI;
6383 }
6384 if (below != null && below.task == task) {
6385 final boolean clearWhenTaskReset =
6386 (target.intent.getFlags()
6387 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006388 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006389 // If this activity is sending a reply to a previous
6390 // activity, we can't do anything with it now until
6391 // we reach the start of the reply chain.
6392 // XXX note that we are assuming the result is always
6393 // to the previous activity, which is almost always
6394 // the case but we really shouldn't count on.
6395 if (replyChainEnd < 0) {
6396 replyChainEnd = targetI;
6397 }
Ed Heyl73798232009-03-24 21:32:21 -07006398 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006399 && target.taskAffinity != null
6400 && !target.taskAffinity.equals(task.affinity)) {
6401 // If this activity has an affinity for another
6402 // task, then we need to move it out of here. We will
6403 // move it as far out of the way as possible, to the
6404 // bottom of the activity stack. This also keeps it
6405 // correctly ordered with any activities we previously
6406 // moved.
6407 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6408 if (target.taskAffinity != null
6409 && target.taskAffinity.equals(p.task.affinity)) {
6410 // If the activity currently at the bottom has the
6411 // same task affinity as the one we are moving,
6412 // then merge it into the same task.
6413 target.task = p.task;
6414 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6415 + " out to bottom task " + p.task);
6416 } else {
6417 mCurTask++;
6418 if (mCurTask <= 0) {
6419 mCurTask = 1;
6420 }
6421 target.task = new TaskRecord(mCurTask, target.info, null,
6422 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6423 target.task.affinityIntent = target.intent;
6424 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6425 + " out to new task " + target.task);
6426 }
6427 mWindowManager.setAppGroupId(target, task.taskId);
6428 if (replyChainEnd < 0) {
6429 replyChainEnd = targetI;
6430 }
6431 int dstPos = 0;
6432 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6433 p = (HistoryRecord)mHistory.get(srcPos);
6434 if (p.finishing) {
6435 continue;
6436 }
6437 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6438 + " out to target's task " + target.task);
6439 task.numActivities--;
6440 p.task = target.task;
6441 target.task.numActivities++;
6442 mHistory.remove(srcPos);
6443 mHistory.add(dstPos, p);
6444 mWindowManager.moveAppToken(dstPos, p);
6445 mWindowManager.setAppGroupId(p, p.task.taskId);
6446 dstPos++;
6447 if (VALIDATE_TOKENS) {
6448 mWindowManager.validateAppTokens(mHistory);
6449 }
6450 i++;
6451 }
6452 if (taskTop == p) {
6453 taskTop = below;
6454 }
6455 if (taskTopI == replyChainEnd) {
6456 taskTopI = -1;
6457 }
6458 replyChainEnd = -1;
6459 addRecentTask(target.task);
6460 } else if (forceReset || finishOnTaskLaunch
6461 || clearWhenTaskReset) {
6462 // If the activity should just be removed -- either
6463 // because it asks for it, or the task should be
6464 // cleared -- then finish it and anything that is
6465 // part of its reply chain.
6466 if (clearWhenTaskReset) {
6467 // In this case, we want to finish this activity
6468 // and everything above it, so be sneaky and pretend
6469 // like these are all in the reply chain.
6470 replyChainEnd = targetI+1;
6471 while (replyChainEnd < mHistory.size() &&
6472 ((HistoryRecord)mHistory.get(
6473 replyChainEnd)).task == task) {
6474 replyChainEnd++;
6475 }
6476 replyChainEnd--;
6477 } else if (replyChainEnd < 0) {
6478 replyChainEnd = targetI;
6479 }
6480 HistoryRecord p = null;
6481 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6482 p = (HistoryRecord)mHistory.get(srcPos);
6483 if (p.finishing) {
6484 continue;
6485 }
6486 if (finishActivityLocked(p, srcPos,
6487 Activity.RESULT_CANCELED, null, "reset")) {
6488 replyChainEnd--;
6489 srcPos--;
6490 }
6491 }
6492 if (taskTop == p) {
6493 taskTop = below;
6494 }
6495 if (taskTopI == replyChainEnd) {
6496 taskTopI = -1;
6497 }
6498 replyChainEnd = -1;
6499 } else {
6500 // If we were in the middle of a chain, well the
6501 // activity that started it all doesn't want anything
6502 // special, so leave it all as-is.
6503 replyChainEnd = -1;
6504 }
6505 } else {
6506 // Reached the bottom of the task -- any reply chain
6507 // should be left as-is.
6508 replyChainEnd = -1;
6509 }
6510
6511 } else if (target.resultTo != null) {
6512 // If this activity is sending a reply to a previous
6513 // activity, we can't do anything with it now until
6514 // we reach the start of the reply chain.
6515 // XXX note that we are assuming the result is always
6516 // to the previous activity, which is almost always
6517 // the case but we really shouldn't count on.
6518 if (replyChainEnd < 0) {
6519 replyChainEnd = targetI;
6520 }
6521
6522 } else if (taskTopI >= 0 && allowTaskReparenting
6523 && task.affinity != null
6524 && task.affinity.equals(target.taskAffinity)) {
6525 // We are inside of another task... if this activity has
6526 // an affinity for our task, then either remove it if we are
6527 // clearing or move it over to our task. Note that
6528 // we currently punt on the case where we are resetting a
6529 // task that is not at the top but who has activities above
6530 // with an affinity to it... this is really not a normal
6531 // case, and we will need to later pull that task to the front
6532 // and usually at that point we will do the reset and pick
6533 // up those remaining activities. (This only happens if
6534 // someone starts an activity in a new task from an activity
6535 // in a task that is not currently on top.)
6536 if (forceReset || finishOnTaskLaunch) {
6537 if (replyChainEnd < 0) {
6538 replyChainEnd = targetI;
6539 }
6540 HistoryRecord p = null;
6541 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6542 p = (HistoryRecord)mHistory.get(srcPos);
6543 if (p.finishing) {
6544 continue;
6545 }
6546 if (finishActivityLocked(p, srcPos,
6547 Activity.RESULT_CANCELED, null, "reset")) {
6548 taskTopI--;
6549 lastReparentPos--;
6550 replyChainEnd--;
6551 srcPos--;
6552 }
6553 }
6554 replyChainEnd = -1;
6555 } else {
6556 if (replyChainEnd < 0) {
6557 replyChainEnd = targetI;
6558 }
6559 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6560 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6561 if (p.finishing) {
6562 continue;
6563 }
6564 if (lastReparentPos < 0) {
6565 lastReparentPos = taskTopI;
6566 taskTop = p;
6567 } else {
6568 lastReparentPos--;
6569 }
6570 mHistory.remove(srcPos);
6571 p.task.numActivities--;
6572 p.task = task;
6573 mHistory.add(lastReparentPos, p);
6574 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6575 + " in to resetting task " + task);
6576 task.numActivities++;
6577 mWindowManager.moveAppToken(lastReparentPos, p);
6578 mWindowManager.setAppGroupId(p, p.task.taskId);
6579 if (VALIDATE_TOKENS) {
6580 mWindowManager.validateAppTokens(mHistory);
6581 }
6582 }
6583 replyChainEnd = -1;
6584
6585 // Now we've moved it in to place... but what if this is
6586 // a singleTop activity and we have put it on top of another
6587 // instance of the same activity? Then we drop the instance
6588 // below so it remains singleTop.
6589 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6590 for (int j=lastReparentPos-1; j>=0; j--) {
6591 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6592 if (p.finishing) {
6593 continue;
6594 }
6595 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6596 if (finishActivityLocked(p, j,
6597 Activity.RESULT_CANCELED, null, "replace")) {
6598 taskTopI--;
6599 lastReparentPos--;
6600 }
6601 }
6602 }
6603 }
6604 }
6605 }
6606
6607 target = below;
6608 targetI = i;
6609 }
6610
6611 return taskTop;
6612 }
6613
6614 /**
6615 * TODO: Add mWatcher hook
6616 */
6617 public void moveTaskToFront(int task) {
6618 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6619 "moveTaskToFront()");
6620
6621 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006622 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6623 Binder.getCallingUid(), "Task to front")) {
6624 return;
6625 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006626 final long origId = Binder.clearCallingIdentity();
6627 try {
6628 int N = mRecentTasks.size();
6629 for (int i=0; i<N; i++) {
6630 TaskRecord tr = mRecentTasks.get(i);
6631 if (tr.taskId == task) {
6632 moveTaskToFrontLocked(tr);
6633 return;
6634 }
6635 }
6636 for (int i=mHistory.size()-1; i>=0; i--) {
6637 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6638 if (hr.task.taskId == task) {
6639 moveTaskToFrontLocked(hr.task);
6640 return;
6641 }
6642 }
6643 } finally {
6644 Binder.restoreCallingIdentity(origId);
6645 }
6646 }
6647 }
6648
6649 private final void moveTaskToFrontLocked(TaskRecord tr) {
6650 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6651
6652 final int task = tr.taskId;
6653 int top = mHistory.size()-1;
6654
6655 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6656 // nothing to do!
6657 return;
6658 }
6659
6660 if (DEBUG_TRANSITION) Log.v(TAG,
6661 "Prepare to front transition: task=" + tr);
6662 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6663
6664 ArrayList moved = new ArrayList();
6665
6666 // Applying the affinities may have removed entries from the history,
6667 // so get the size again.
6668 top = mHistory.size()-1;
6669 int pos = top;
6670
6671 // Shift all activities with this task up to the top
6672 // of the stack, keeping them in the same internal order.
6673 while (pos >= 0) {
6674 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6675 if (localLOGV) Log.v(
6676 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6677 boolean first = true;
6678 if (r.task.taskId == task) {
6679 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6680 mHistory.remove(pos);
6681 mHistory.add(top, r);
6682 moved.add(0, r);
6683 top--;
6684 if (first) {
6685 addRecentTask(r.task);
6686 first = false;
6687 }
6688 }
6689 pos--;
6690 }
6691
6692 mWindowManager.moveAppTokensToTop(moved);
6693 if (VALIDATE_TOKENS) {
6694 mWindowManager.validateAppTokens(mHistory);
6695 }
6696
6697 finishTaskMove(task);
6698 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6699 }
6700
6701 private final void finishTaskMove(int task) {
6702 resumeTopActivityLocked(null);
6703 }
6704
6705 public void moveTaskToBack(int task) {
6706 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6707 "moveTaskToBack()");
6708
6709 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006710 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6711 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6712 Binder.getCallingUid(), "Task to back")) {
6713 return;
6714 }
6715 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006716 final long origId = Binder.clearCallingIdentity();
6717 moveTaskToBackLocked(task);
6718 Binder.restoreCallingIdentity(origId);
6719 }
6720 }
6721
6722 /**
6723 * Moves an activity, and all of the other activities within the same task, to the bottom
6724 * of the history stack. The activity's order within the task is unchanged.
6725 *
6726 * @param token A reference to the activity we wish to move
6727 * @param nonRoot If false then this only works if the activity is the root
6728 * of a task; if true it will work for any activity in a task.
6729 * @return Returns true if the move completed, false if not.
6730 */
6731 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6732 synchronized(this) {
6733 final long origId = Binder.clearCallingIdentity();
6734 int taskId = getTaskForActivityLocked(token, !nonRoot);
6735 if (taskId >= 0) {
6736 return moveTaskToBackLocked(taskId);
6737 }
6738 Binder.restoreCallingIdentity(origId);
6739 }
6740 return false;
6741 }
6742
6743 /**
6744 * Worker method for rearranging history stack. Implements the function of moving all
6745 * activities for a specific task (gathering them if disjoint) into a single group at the
6746 * bottom of the stack.
6747 *
6748 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6749 * to premeptively cancel the move.
6750 *
6751 * @param task The taskId to collect and move to the bottom.
6752 * @return Returns true if the move completed, false if not.
6753 */
6754 private final boolean moveTaskToBackLocked(int task) {
6755 Log.i(TAG, "moveTaskToBack: " + task);
6756
6757 // If we have a watcher, preflight the move before committing to it. First check
6758 // for *other* available tasks, but if none are available, then try again allowing the
6759 // current task to be selected.
6760 if (mWatcher != null) {
6761 HistoryRecord next = topRunningActivityLocked(null, task);
6762 if (next == null) {
6763 next = topRunningActivityLocked(null, 0);
6764 }
6765 if (next != null) {
6766 // ask watcher if this is allowed
6767 boolean moveOK = true;
6768 try {
6769 moveOK = mWatcher.activityResuming(next.packageName);
6770 } catch (RemoteException e) {
6771 mWatcher = null;
6772 }
6773 if (!moveOK) {
6774 return false;
6775 }
6776 }
6777 }
6778
6779 ArrayList moved = new ArrayList();
6780
6781 if (DEBUG_TRANSITION) Log.v(TAG,
6782 "Prepare to back transition: task=" + task);
6783 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6784
6785 final int N = mHistory.size();
6786 int bottom = 0;
6787 int pos = 0;
6788
6789 // Shift all activities with this task down to the bottom
6790 // of the stack, keeping them in the same internal order.
6791 while (pos < N) {
6792 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6793 if (localLOGV) Log.v(
6794 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6795 if (r.task.taskId == task) {
6796 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6797 mHistory.remove(pos);
6798 mHistory.add(bottom, r);
6799 moved.add(r);
6800 bottom++;
6801 }
6802 pos++;
6803 }
6804
6805 mWindowManager.moveAppTokensToBottom(moved);
6806 if (VALIDATE_TOKENS) {
6807 mWindowManager.validateAppTokens(mHistory);
6808 }
6809
6810 finishTaskMove(task);
6811 return true;
6812 }
6813
6814 public void moveTaskBackwards(int task) {
6815 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6816 "moveTaskBackwards()");
6817
6818 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006819 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6820 Binder.getCallingUid(), "Task backwards")) {
6821 return;
6822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006823 final long origId = Binder.clearCallingIdentity();
6824 moveTaskBackwardsLocked(task);
6825 Binder.restoreCallingIdentity(origId);
6826 }
6827 }
6828
6829 private final void moveTaskBackwardsLocked(int task) {
6830 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6831 }
6832
6833 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6834 synchronized(this) {
6835 return getTaskForActivityLocked(token, onlyRoot);
6836 }
6837 }
6838
6839 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6840 final int N = mHistory.size();
6841 TaskRecord lastTask = null;
6842 for (int i=0; i<N; i++) {
6843 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6844 if (r == token) {
6845 if (!onlyRoot || lastTask != r.task) {
6846 return r.task.taskId;
6847 }
6848 return -1;
6849 }
6850 lastTask = r.task;
6851 }
6852
6853 return -1;
6854 }
6855
6856 /**
6857 * Returns the top activity in any existing task matching the given
6858 * Intent. Returns null if no such task is found.
6859 */
6860 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6861 ComponentName cls = intent.getComponent();
6862 if (info.targetActivity != null) {
6863 cls = new ComponentName(info.packageName, info.targetActivity);
6864 }
6865
6866 TaskRecord cp = null;
6867
6868 final int N = mHistory.size();
6869 for (int i=(N-1); i>=0; i--) {
6870 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6871 if (!r.finishing && r.task != cp
6872 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6873 cp = r.task;
6874 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6875 // + "/aff=" + r.task.affinity + " to new cls="
6876 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6877 if (r.task.affinity != null) {
6878 if (r.task.affinity.equals(info.taskAffinity)) {
6879 //Log.i(TAG, "Found matching affinity!");
6880 return r;
6881 }
6882 } else if (r.task.intent != null
6883 && r.task.intent.getComponent().equals(cls)) {
6884 //Log.i(TAG, "Found matching class!");
6885 //dump();
6886 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6887 return r;
6888 } else if (r.task.affinityIntent != null
6889 && r.task.affinityIntent.getComponent().equals(cls)) {
6890 //Log.i(TAG, "Found matching class!");
6891 //dump();
6892 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6893 return r;
6894 }
6895 }
6896 }
6897
6898 return null;
6899 }
6900
6901 /**
6902 * Returns the first activity (starting from the top of the stack) that
6903 * is the same as the given activity. Returns null if no such activity
6904 * is found.
6905 */
6906 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6907 ComponentName cls = intent.getComponent();
6908 if (info.targetActivity != null) {
6909 cls = new ComponentName(info.packageName, info.targetActivity);
6910 }
6911
6912 final int N = mHistory.size();
6913 for (int i=(N-1); i>=0; i--) {
6914 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6915 if (!r.finishing) {
6916 if (r.intent.getComponent().equals(cls)) {
6917 //Log.i(TAG, "Found matching class!");
6918 //dump();
6919 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6920 return r;
6921 }
6922 }
6923 }
6924
6925 return null;
6926 }
6927
6928 public void finishOtherInstances(IBinder token, ComponentName className) {
6929 synchronized(this) {
6930 final long origId = Binder.clearCallingIdentity();
6931
6932 int N = mHistory.size();
6933 TaskRecord lastTask = null;
6934 for (int i=0; i<N; i++) {
6935 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6936 if (r.realActivity.equals(className)
6937 && r != token && lastTask != r.task) {
6938 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6939 null, "others")) {
6940 i--;
6941 N--;
6942 }
6943 }
6944 lastTask = r.task;
6945 }
6946
6947 Binder.restoreCallingIdentity(origId);
6948 }
6949 }
6950
6951 // =========================================================
6952 // THUMBNAILS
6953 // =========================================================
6954
6955 public void reportThumbnail(IBinder token,
6956 Bitmap thumbnail, CharSequence description) {
6957 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6958 final long origId = Binder.clearCallingIdentity();
6959 sendPendingThumbnail(null, token, thumbnail, description, true);
6960 Binder.restoreCallingIdentity(origId);
6961 }
6962
6963 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6964 Bitmap thumbnail, CharSequence description, boolean always) {
6965 TaskRecord task = null;
6966 ArrayList receivers = null;
6967
6968 //System.out.println("Send pending thumbnail: " + r);
6969
6970 synchronized(this) {
6971 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006972 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006973 if (index < 0) {
6974 return;
6975 }
6976 r = (HistoryRecord)mHistory.get(index);
6977 }
6978 if (thumbnail == null) {
6979 thumbnail = r.thumbnail;
6980 description = r.description;
6981 }
6982 if (thumbnail == null && !always) {
6983 // If there is no thumbnail, and this entry is not actually
6984 // going away, then abort for now and pick up the next
6985 // thumbnail we get.
6986 return;
6987 }
6988 task = r.task;
6989
6990 int N = mPendingThumbnails.size();
6991 int i=0;
6992 while (i<N) {
6993 PendingThumbnailsRecord pr =
6994 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6995 //System.out.println("Looking in " + pr.pendingRecords);
6996 if (pr.pendingRecords.remove(r)) {
6997 if (receivers == null) {
6998 receivers = new ArrayList();
6999 }
7000 receivers.add(pr);
7001 if (pr.pendingRecords.size() == 0) {
7002 pr.finished = true;
7003 mPendingThumbnails.remove(i);
7004 N--;
7005 continue;
7006 }
7007 }
7008 i++;
7009 }
7010 }
7011
7012 if (receivers != null) {
7013 final int N = receivers.size();
7014 for (int i=0; i<N; i++) {
7015 try {
7016 PendingThumbnailsRecord pr =
7017 (PendingThumbnailsRecord)receivers.get(i);
7018 pr.receiver.newThumbnail(
7019 task != null ? task.taskId : -1, thumbnail, description);
7020 if (pr.finished) {
7021 pr.receiver.finished();
7022 }
7023 } catch (Exception e) {
7024 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7025 }
7026 }
7027 }
7028 }
7029
7030 // =========================================================
7031 // CONTENT PROVIDERS
7032 // =========================================================
7033
7034 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7035 List providers = null;
7036 try {
7037 providers = ActivityThread.getPackageManager().
7038 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007039 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007040 } catch (RemoteException ex) {
7041 }
7042 if (providers != null) {
7043 final int N = providers.size();
7044 for (int i=0; i<N; i++) {
7045 ProviderInfo cpi =
7046 (ProviderInfo)providers.get(i);
7047 ContentProviderRecord cpr =
7048 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7049 if (cpr == null) {
7050 cpr = new ContentProviderRecord(cpi, app.info);
7051 mProvidersByClass.put(cpi.name, cpr);
7052 }
7053 app.pubProviders.put(cpi.name, cpr);
7054 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007055 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007056 }
7057 }
7058 return providers;
7059 }
7060
7061 private final String checkContentProviderPermissionLocked(
7062 ProviderInfo cpi, ProcessRecord r, int mode) {
7063 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7064 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7065 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7066 cpi.exported ? -1 : cpi.applicationInfo.uid)
7067 == PackageManager.PERMISSION_GRANTED
7068 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7069 return null;
7070 }
7071 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7072 cpi.exported ? -1 : cpi.applicationInfo.uid)
7073 == PackageManager.PERMISSION_GRANTED) {
7074 return null;
7075 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007076
7077 PathPermission[] pps = cpi.pathPermissions;
7078 if (pps != null) {
7079 int i = pps.length;
7080 while (i > 0) {
7081 i--;
7082 PathPermission pp = pps[i];
7083 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7084 cpi.exported ? -1 : cpi.applicationInfo.uid)
7085 == PackageManager.PERMISSION_GRANTED
7086 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7087 return null;
7088 }
7089 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7090 cpi.exported ? -1 : cpi.applicationInfo.uid)
7091 == PackageManager.PERMISSION_GRANTED) {
7092 return null;
7093 }
7094 }
7095 }
7096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007097 String msg = "Permission Denial: opening provider " + cpi.name
7098 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7099 + ", uid=" + callingUid + ") requires "
7100 + cpi.readPermission + " or " + cpi.writePermission;
7101 Log.w(TAG, msg);
7102 return msg;
7103 }
7104
7105 private final ContentProviderHolder getContentProviderImpl(
7106 IApplicationThread caller, String name) {
7107 ContentProviderRecord cpr;
7108 ProviderInfo cpi = null;
7109
7110 synchronized(this) {
7111 ProcessRecord r = null;
7112 if (caller != null) {
7113 r = getRecordForAppLocked(caller);
7114 if (r == null) {
7115 throw new SecurityException(
7116 "Unable to find app for caller " + caller
7117 + " (pid=" + Binder.getCallingPid()
7118 + ") when getting content provider " + name);
7119 }
7120 }
7121
7122 // First check if this content provider has been published...
7123 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7124 if (cpr != null) {
7125 cpi = cpr.info;
7126 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7127 return new ContentProviderHolder(cpi,
7128 cpi.readPermission != null
7129 ? cpi.readPermission : cpi.writePermission);
7130 }
7131
7132 if (r != null && cpr.canRunHere(r)) {
7133 // This provider has been published or is in the process
7134 // of being published... but it is also allowed to run
7135 // in the caller's process, so don't make a connection
7136 // and just let the caller instantiate its own instance.
7137 if (cpr.provider != null) {
7138 // don't give caller the provider object, it needs
7139 // to make its own.
7140 cpr = new ContentProviderRecord(cpr);
7141 }
7142 return cpr;
7143 }
7144
7145 final long origId = Binder.clearCallingIdentity();
7146
7147 // In this case the provider is a single instance, so we can
7148 // return it right away.
7149 if (r != null) {
7150 r.conProviders.add(cpr);
7151 cpr.clients.add(r);
7152 } else {
7153 cpr.externals++;
7154 }
7155
7156 if (cpr.app != null) {
7157 updateOomAdjLocked(cpr.app);
7158 }
7159
7160 Binder.restoreCallingIdentity(origId);
7161
7162 } else {
7163 try {
7164 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007165 resolveContentProvider(name,
7166 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007167 } catch (RemoteException ex) {
7168 }
7169 if (cpi == null) {
7170 return null;
7171 }
7172
7173 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7174 return new ContentProviderHolder(cpi,
7175 cpi.readPermission != null
7176 ? cpi.readPermission : cpi.writePermission);
7177 }
7178
7179 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7180 final boolean firstClass = cpr == null;
7181 if (firstClass) {
7182 try {
7183 ApplicationInfo ai =
7184 ActivityThread.getPackageManager().
7185 getApplicationInfo(
7186 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007187 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007188 if (ai == null) {
7189 Log.w(TAG, "No package info for content provider "
7190 + cpi.name);
7191 return null;
7192 }
7193 cpr = new ContentProviderRecord(cpi, ai);
7194 } catch (RemoteException ex) {
7195 // pm is in same process, this will never happen.
7196 }
7197 }
7198
7199 if (r != null && cpr.canRunHere(r)) {
7200 // If this is a multiprocess provider, then just return its
7201 // info and allow the caller to instantiate it. Only do
7202 // this if the provider is the same user as the caller's
7203 // process, or can run as root (so can be in any process).
7204 return cpr;
7205 }
7206
7207 if (false) {
7208 RuntimeException e = new RuntimeException("foo");
7209 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7210 // + " pruid " + ai.uid + "): " + cpi.className, e);
7211 }
7212
7213 // This is single process, and our app is now connecting to it.
7214 // See if we are already in the process of launching this
7215 // provider.
7216 final int N = mLaunchingProviders.size();
7217 int i;
7218 for (i=0; i<N; i++) {
7219 if (mLaunchingProviders.get(i) == cpr) {
7220 break;
7221 }
7222 if (false) {
7223 final ContentProviderRecord rec =
7224 (ContentProviderRecord)mLaunchingProviders.get(i);
7225 if (rec.info.name.equals(cpr.info.name)) {
7226 cpr = rec;
7227 break;
7228 }
7229 }
7230 }
7231
7232 // If the provider is not already being launched, then get it
7233 // started.
7234 if (i >= N) {
7235 final long origId = Binder.clearCallingIdentity();
7236 ProcessRecord proc = startProcessLocked(cpi.processName,
7237 cpr.appInfo, false, 0, "content provider",
7238 new ComponentName(cpi.applicationInfo.packageName,
7239 cpi.name));
7240 if (proc == null) {
7241 Log.w(TAG, "Unable to launch app "
7242 + cpi.applicationInfo.packageName + "/"
7243 + cpi.applicationInfo.uid + " for provider "
7244 + name + ": process is bad");
7245 return null;
7246 }
7247 cpr.launchingApp = proc;
7248 mLaunchingProviders.add(cpr);
7249 Binder.restoreCallingIdentity(origId);
7250 }
7251
7252 // Make sure the provider is published (the same provider class
7253 // may be published under multiple names).
7254 if (firstClass) {
7255 mProvidersByClass.put(cpi.name, cpr);
7256 }
7257 mProvidersByName.put(name, cpr);
7258
7259 if (r != null) {
7260 r.conProviders.add(cpr);
7261 cpr.clients.add(r);
7262 } else {
7263 cpr.externals++;
7264 }
7265 }
7266 }
7267
7268 // Wait for the provider to be published...
7269 synchronized (cpr) {
7270 while (cpr.provider == null) {
7271 if (cpr.launchingApp == null) {
7272 Log.w(TAG, "Unable to launch app "
7273 + cpi.applicationInfo.packageName + "/"
7274 + cpi.applicationInfo.uid + " for provider "
7275 + name + ": launching app became null");
7276 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7277 cpi.applicationInfo.packageName,
7278 cpi.applicationInfo.uid, name);
7279 return null;
7280 }
7281 try {
7282 cpr.wait();
7283 } catch (InterruptedException ex) {
7284 }
7285 }
7286 }
7287 return cpr;
7288 }
7289
7290 public final ContentProviderHolder getContentProvider(
7291 IApplicationThread caller, String name) {
7292 if (caller == null) {
7293 String msg = "null IApplicationThread when getting content provider "
7294 + name;
7295 Log.w(TAG, msg);
7296 throw new SecurityException(msg);
7297 }
7298
7299 return getContentProviderImpl(caller, name);
7300 }
7301
7302 private ContentProviderHolder getContentProviderExternal(String name) {
7303 return getContentProviderImpl(null, name);
7304 }
7305
7306 /**
7307 * Drop a content provider from a ProcessRecord's bookkeeping
7308 * @param cpr
7309 */
7310 public void removeContentProvider(IApplicationThread caller, String name) {
7311 synchronized (this) {
7312 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7313 if(cpr == null) {
7314 //remove from mProvidersByClass
7315 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7316 return;
7317 }
7318 final ProcessRecord r = getRecordForAppLocked(caller);
7319 if (r == null) {
7320 throw new SecurityException(
7321 "Unable to find app for caller " + caller +
7322 " when removing content provider " + name);
7323 }
7324 //update content provider record entry info
7325 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7326 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7327 r.info.processName+" from process "+localCpr.appInfo.processName);
7328 if(localCpr.appInfo.processName == r.info.processName) {
7329 //should not happen. taken care of as a local provider
7330 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7331 return;
7332 } else {
7333 localCpr.clients.remove(r);
7334 r.conProviders.remove(localCpr);
7335 }
7336 updateOomAdjLocked();
7337 }
7338 }
7339
7340 private void removeContentProviderExternal(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
7349 //update content provider record entry info
7350 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7351 localCpr.externals--;
7352 if (localCpr.externals < 0) {
7353 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7354 }
7355 updateOomAdjLocked();
7356 }
7357 }
7358
7359 public final void publishContentProviders(IApplicationThread caller,
7360 List<ContentProviderHolder> providers) {
7361 if (providers == null) {
7362 return;
7363 }
7364
7365 synchronized(this) {
7366 final ProcessRecord r = getRecordForAppLocked(caller);
7367 if (r == null) {
7368 throw new SecurityException(
7369 "Unable to find app for caller " + caller
7370 + " (pid=" + Binder.getCallingPid()
7371 + ") when publishing content providers");
7372 }
7373
7374 final long origId = Binder.clearCallingIdentity();
7375
7376 final int N = providers.size();
7377 for (int i=0; i<N; i++) {
7378 ContentProviderHolder src = providers.get(i);
7379 if (src == null || src.info == null || src.provider == null) {
7380 continue;
7381 }
7382 ContentProviderRecord dst =
7383 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7384 if (dst != null) {
7385 mProvidersByClass.put(dst.info.name, dst);
7386 String names[] = dst.info.authority.split(";");
7387 for (int j = 0; j < names.length; j++) {
7388 mProvidersByName.put(names[j], dst);
7389 }
7390
7391 int NL = mLaunchingProviders.size();
7392 int j;
7393 for (j=0; j<NL; j++) {
7394 if (mLaunchingProviders.get(j) == dst) {
7395 mLaunchingProviders.remove(j);
7396 j--;
7397 NL--;
7398 }
7399 }
7400 synchronized (dst) {
7401 dst.provider = src.provider;
7402 dst.app = r;
7403 dst.notifyAll();
7404 }
7405 updateOomAdjLocked(r);
7406 }
7407 }
7408
7409 Binder.restoreCallingIdentity(origId);
7410 }
7411 }
7412
7413 public static final void installSystemProviders() {
7414 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7415 List providers = mSelf.generateApplicationProvidersLocked(app);
7416 mSystemThread.installSystemProviders(providers);
7417 }
7418
7419 // =========================================================
7420 // GLOBAL MANAGEMENT
7421 // =========================================================
7422
7423 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7424 ApplicationInfo info, String customProcess) {
7425 String proc = customProcess != null ? customProcess : info.processName;
7426 BatteryStatsImpl.Uid.Proc ps = null;
7427 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7428 synchronized (stats) {
7429 ps = stats.getProcessStatsLocked(info.uid, proc);
7430 }
7431 return new ProcessRecord(ps, thread, info, proc);
7432 }
7433
7434 final ProcessRecord addAppLocked(ApplicationInfo info) {
7435 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7436
7437 if (app == null) {
7438 app = newProcessRecordLocked(null, info, null);
7439 mProcessNames.put(info.processName, info.uid, app);
7440 updateLRUListLocked(app, true);
7441 }
7442
7443 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7444 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7445 app.persistent = true;
7446 app.maxAdj = CORE_SERVER_ADJ;
7447 }
7448 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7449 mPersistentStartingProcesses.add(app);
7450 startProcessLocked(app, "added application", app.processName);
7451 }
7452
7453 return app;
7454 }
7455
7456 public void unhandledBack() {
7457 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7458 "unhandledBack()");
7459
7460 synchronized(this) {
7461 int count = mHistory.size();
7462 if (Config.LOGD) Log.d(
7463 TAG, "Performing unhandledBack(): stack size = " + count);
7464 if (count > 1) {
7465 final long origId = Binder.clearCallingIdentity();
7466 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7467 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7468 Binder.restoreCallingIdentity(origId);
7469 }
7470 }
7471 }
7472
7473 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7474 String name = uri.getAuthority();
7475 ContentProviderHolder cph = getContentProviderExternal(name);
7476 ParcelFileDescriptor pfd = null;
7477 if (cph != null) {
7478 // We record the binder invoker's uid in thread-local storage before
7479 // going to the content provider to open the file. Later, in the code
7480 // that handles all permissions checks, we look for this uid and use
7481 // that rather than the Activity Manager's own uid. The effect is that
7482 // we do the check against the caller's permissions even though it looks
7483 // to the content provider like the Activity Manager itself is making
7484 // the request.
7485 sCallerIdentity.set(new Identity(
7486 Binder.getCallingPid(), Binder.getCallingUid()));
7487 try {
7488 pfd = cph.provider.openFile(uri, "r");
7489 } catch (FileNotFoundException e) {
7490 // do nothing; pfd will be returned null
7491 } finally {
7492 // Ensure that whatever happens, we clean up the identity state
7493 sCallerIdentity.remove();
7494 }
7495
7496 // We've got the fd now, so we're done with the provider.
7497 removeContentProviderExternal(name);
7498 } else {
7499 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7500 }
7501 return pfd;
7502 }
7503
7504 public void goingToSleep() {
7505 synchronized(this) {
7506 mSleeping = true;
7507 mWindowManager.setEventDispatching(false);
7508
7509 if (mResumedActivity != null) {
7510 pauseIfSleepingLocked();
7511 } else {
7512 Log.w(TAG, "goingToSleep with no resumed activity!");
7513 }
7514 }
7515 }
7516
Dianne Hackborn55280a92009-05-07 15:53:46 -07007517 public boolean shutdown(int timeout) {
7518 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7519 != PackageManager.PERMISSION_GRANTED) {
7520 throw new SecurityException("Requires permission "
7521 + android.Manifest.permission.SHUTDOWN);
7522 }
7523
7524 boolean timedout = false;
7525
7526 synchronized(this) {
7527 mShuttingDown = true;
7528 mWindowManager.setEventDispatching(false);
7529
7530 if (mResumedActivity != null) {
7531 pauseIfSleepingLocked();
7532 final long endTime = System.currentTimeMillis() + timeout;
7533 while (mResumedActivity != null || mPausingActivity != null) {
7534 long delay = endTime - System.currentTimeMillis();
7535 if (delay <= 0) {
7536 Log.w(TAG, "Activity manager shutdown timed out");
7537 timedout = true;
7538 break;
7539 }
7540 try {
7541 this.wait();
7542 } catch (InterruptedException e) {
7543 }
7544 }
7545 }
7546 }
7547
7548 mUsageStatsService.shutdown();
7549 mBatteryStatsService.shutdown();
7550
7551 return timedout;
7552 }
7553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007554 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007555 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007556 if (!mGoingToSleep.isHeld()) {
7557 mGoingToSleep.acquire();
7558 if (mLaunchingActivity.isHeld()) {
7559 mLaunchingActivity.release();
7560 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7561 }
7562 }
7563
7564 // If we are not currently pausing an activity, get the current
7565 // one to pause. If we are pausing one, we will just let that stuff
7566 // run and release the wake lock when all done.
7567 if (mPausingActivity == null) {
7568 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7569 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7570 startPausingLocked(false, true);
7571 }
7572 }
7573 }
7574
7575 public void wakingUp() {
7576 synchronized(this) {
7577 if (mGoingToSleep.isHeld()) {
7578 mGoingToSleep.release();
7579 }
7580 mWindowManager.setEventDispatching(true);
7581 mSleeping = false;
7582 resumeTopActivityLocked(null);
7583 }
7584 }
7585
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007586 public void stopAppSwitches() {
7587 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7588 != PackageManager.PERMISSION_GRANTED) {
7589 throw new SecurityException("Requires permission "
7590 + android.Manifest.permission.STOP_APP_SWITCHES);
7591 }
7592
7593 synchronized(this) {
7594 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7595 + APP_SWITCH_DELAY_TIME;
7596 mDidAppSwitch = false;
7597 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7598 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7599 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7600 }
7601 }
7602
7603 public void resumeAppSwitches() {
7604 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7605 != PackageManager.PERMISSION_GRANTED) {
7606 throw new SecurityException("Requires permission "
7607 + android.Manifest.permission.STOP_APP_SWITCHES);
7608 }
7609
7610 synchronized(this) {
7611 // Note that we don't execute any pending app switches... we will
7612 // let those wait until either the timeout, or the next start
7613 // activity request.
7614 mAppSwitchesAllowedTime = 0;
7615 }
7616 }
7617
7618 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7619 String name) {
7620 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7621 return true;
7622 }
7623
7624 final int perm = checkComponentPermission(
7625 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7626 callingUid, -1);
7627 if (perm == PackageManager.PERMISSION_GRANTED) {
7628 return true;
7629 }
7630
7631 Log.w(TAG, name + " request from " + callingUid + " stopped");
7632 return false;
7633 }
7634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007635 public void setDebugApp(String packageName, boolean waitForDebugger,
7636 boolean persistent) {
7637 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7638 "setDebugApp()");
7639
7640 // Note that this is not really thread safe if there are multiple
7641 // callers into it at the same time, but that's not a situation we
7642 // care about.
7643 if (persistent) {
7644 final ContentResolver resolver = mContext.getContentResolver();
7645 Settings.System.putString(
7646 resolver, Settings.System.DEBUG_APP,
7647 packageName);
7648 Settings.System.putInt(
7649 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7650 waitForDebugger ? 1 : 0);
7651 }
7652
7653 synchronized (this) {
7654 if (!persistent) {
7655 mOrigDebugApp = mDebugApp;
7656 mOrigWaitForDebugger = mWaitForDebugger;
7657 }
7658 mDebugApp = packageName;
7659 mWaitForDebugger = waitForDebugger;
7660 mDebugTransient = !persistent;
7661 if (packageName != null) {
7662 final long origId = Binder.clearCallingIdentity();
7663 uninstallPackageLocked(packageName, -1, false);
7664 Binder.restoreCallingIdentity(origId);
7665 }
7666 }
7667 }
7668
7669 public void setAlwaysFinish(boolean enabled) {
7670 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7671 "setAlwaysFinish()");
7672
7673 Settings.System.putInt(
7674 mContext.getContentResolver(),
7675 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7676
7677 synchronized (this) {
7678 mAlwaysFinishActivities = enabled;
7679 }
7680 }
7681
7682 public void setActivityWatcher(IActivityWatcher watcher) {
7683 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7684 "setActivityWatcher()");
7685 synchronized (this) {
7686 mWatcher = watcher;
7687 }
7688 }
7689
7690 public final void enterSafeMode() {
7691 synchronized(this) {
7692 // It only makes sense to do this before the system is ready
7693 // and started launching other packages.
7694 if (!mSystemReady) {
7695 try {
7696 ActivityThread.getPackageManager().enterSafeMode();
7697 } catch (RemoteException e) {
7698 }
7699
7700 View v = LayoutInflater.from(mContext).inflate(
7701 com.android.internal.R.layout.safe_mode, null);
7702 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7703 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7704 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7705 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7706 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7707 lp.format = v.getBackground().getOpacity();
7708 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7709 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7710 ((WindowManager)mContext.getSystemService(
7711 Context.WINDOW_SERVICE)).addView(v, lp);
7712 }
7713 }
7714 }
7715
7716 public void noteWakeupAlarm(IIntentSender sender) {
7717 if (!(sender instanceof PendingIntentRecord)) {
7718 return;
7719 }
7720 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7721 synchronized (stats) {
7722 if (mBatteryStatsService.isOnBattery()) {
7723 mBatteryStatsService.enforceCallingPermission();
7724 PendingIntentRecord rec = (PendingIntentRecord)sender;
7725 int MY_UID = Binder.getCallingUid();
7726 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7727 BatteryStatsImpl.Uid.Pkg pkg =
7728 stats.getPackageStatsLocked(uid, rec.key.packageName);
7729 pkg.incWakeupsLocked();
7730 }
7731 }
7732 }
7733
7734 public boolean killPidsForMemory(int[] pids) {
7735 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7736 throw new SecurityException("killPidsForMemory only available to the system");
7737 }
7738
7739 // XXX Note: don't acquire main activity lock here, because the window
7740 // manager calls in with its locks held.
7741
7742 boolean killed = false;
7743 synchronized (mPidsSelfLocked) {
7744 int[] types = new int[pids.length];
7745 int worstType = 0;
7746 for (int i=0; i<pids.length; i++) {
7747 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7748 if (proc != null) {
7749 int type = proc.setAdj;
7750 types[i] = type;
7751 if (type > worstType) {
7752 worstType = type;
7753 }
7754 }
7755 }
7756
7757 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7758 // then constrain it so we will kill all hidden procs.
7759 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7760 worstType = HIDDEN_APP_MIN_ADJ;
7761 }
7762 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7763 for (int i=0; i<pids.length; i++) {
7764 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7765 if (proc == null) {
7766 continue;
7767 }
7768 int adj = proc.setAdj;
7769 if (adj >= worstType) {
7770 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7771 + adj + ")");
7772 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7773 proc.processName, adj);
7774 killed = true;
7775 Process.killProcess(pids[i]);
7776 }
7777 }
7778 }
7779 return killed;
7780 }
7781
7782 public void reportPss(IApplicationThread caller, int pss) {
7783 Watchdog.PssRequestor req;
7784 String name;
7785 ProcessRecord callerApp;
7786 synchronized (this) {
7787 if (caller == null) {
7788 return;
7789 }
7790 callerApp = getRecordForAppLocked(caller);
7791 if (callerApp == null) {
7792 return;
7793 }
7794 callerApp.lastPss = pss;
7795 req = callerApp;
7796 name = callerApp.processName;
7797 }
7798 Watchdog.getInstance().reportPss(req, name, pss);
7799 if (!callerApp.persistent) {
7800 removeRequestedPss(callerApp);
7801 }
7802 }
7803
7804 public void requestPss(Runnable completeCallback) {
7805 ArrayList<ProcessRecord> procs;
7806 synchronized (this) {
7807 mRequestPssCallback = completeCallback;
7808 mRequestPssList.clear();
7809 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7810 ProcessRecord proc = mLRUProcesses.get(i);
7811 if (!proc.persistent) {
7812 mRequestPssList.add(proc);
7813 }
7814 }
7815 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7816 }
7817
7818 int oldPri = Process.getThreadPriority(Process.myTid());
7819 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7820 for (int i=procs.size()-1; i>=0; i--) {
7821 ProcessRecord proc = procs.get(i);
7822 proc.lastPss = 0;
7823 proc.requestPss();
7824 }
7825 Process.setThreadPriority(oldPri);
7826 }
7827
7828 void removeRequestedPss(ProcessRecord proc) {
7829 Runnable callback = null;
7830 synchronized (this) {
7831 if (mRequestPssList.remove(proc)) {
7832 if (mRequestPssList.size() == 0) {
7833 callback = mRequestPssCallback;
7834 mRequestPssCallback = null;
7835 }
7836 }
7837 }
7838
7839 if (callback != null) {
7840 callback.run();
7841 }
7842 }
7843
7844 public void collectPss(Watchdog.PssStats stats) {
7845 stats.mEmptyPss = 0;
7846 stats.mEmptyCount = 0;
7847 stats.mBackgroundPss = 0;
7848 stats.mBackgroundCount = 0;
7849 stats.mServicePss = 0;
7850 stats.mServiceCount = 0;
7851 stats.mVisiblePss = 0;
7852 stats.mVisibleCount = 0;
7853 stats.mForegroundPss = 0;
7854 stats.mForegroundCount = 0;
7855 stats.mNoPssCount = 0;
7856 synchronized (this) {
7857 int i;
7858 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7859 ? mProcDeaths.length : stats.mProcDeaths.length;
7860 int aggr = 0;
7861 for (i=0; i<NPD; i++) {
7862 aggr += mProcDeaths[i];
7863 stats.mProcDeaths[i] = aggr;
7864 }
7865 while (i<stats.mProcDeaths.length) {
7866 stats.mProcDeaths[i] = 0;
7867 i++;
7868 }
7869
7870 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7871 ProcessRecord proc = mLRUProcesses.get(i);
7872 if (proc.persistent) {
7873 continue;
7874 }
7875 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7876 if (proc.lastPss == 0) {
7877 stats.mNoPssCount++;
7878 continue;
7879 }
7880 if (proc.setAdj == EMPTY_APP_ADJ) {
7881 stats.mEmptyPss += proc.lastPss;
7882 stats.mEmptyCount++;
7883 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7884 stats.mEmptyPss += proc.lastPss;
7885 stats.mEmptyCount++;
7886 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7887 stats.mBackgroundPss += proc.lastPss;
7888 stats.mBackgroundCount++;
7889 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7890 stats.mVisiblePss += proc.lastPss;
7891 stats.mVisibleCount++;
7892 } else {
7893 stats.mForegroundPss += proc.lastPss;
7894 stats.mForegroundCount++;
7895 }
7896 }
7897 }
7898 }
7899
7900 public final void startRunning(String pkg, String cls, String action,
7901 String data) {
7902 synchronized(this) {
7903 if (mStartRunning) {
7904 return;
7905 }
7906 mStartRunning = true;
7907 mTopComponent = pkg != null && cls != null
7908 ? new ComponentName(pkg, cls) : null;
7909 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7910 mTopData = data;
7911 if (!mSystemReady) {
7912 return;
7913 }
7914 }
7915
7916 systemReady();
7917 }
7918
7919 private void retrieveSettings() {
7920 final ContentResolver resolver = mContext.getContentResolver();
7921 String debugApp = Settings.System.getString(
7922 resolver, Settings.System.DEBUG_APP);
7923 boolean waitForDebugger = Settings.System.getInt(
7924 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7925 boolean alwaysFinishActivities = Settings.System.getInt(
7926 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7927
7928 Configuration configuration = new Configuration();
7929 Settings.System.getConfiguration(resolver, configuration);
7930
7931 synchronized (this) {
7932 mDebugApp = mOrigDebugApp = debugApp;
7933 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7934 mAlwaysFinishActivities = alwaysFinishActivities;
7935 // This happens before any activities are started, so we can
7936 // change mConfiguration in-place.
7937 mConfiguration.updateFrom(configuration);
7938 }
7939 }
7940
7941 public boolean testIsSystemReady() {
7942 // no need to synchronize(this) just to read & return the value
7943 return mSystemReady;
7944 }
7945
7946 public void systemReady() {
7947 // In the simulator, startRunning will never have been called, which
7948 // normally sets a few crucial variables. Do it here instead.
7949 if (!Process.supportsProcesses()) {
7950 mStartRunning = true;
7951 mTopAction = Intent.ACTION_MAIN;
7952 }
7953
7954 synchronized(this) {
7955 if (mSystemReady) {
7956 return;
7957 }
7958 mSystemReady = true;
7959 if (!mStartRunning) {
7960 return;
7961 }
7962 }
7963
7964 if (Config.LOGD) Log.d(TAG, "Start running!");
7965 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7966 SystemClock.uptimeMillis());
7967
7968 synchronized(this) {
7969 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7970 ResolveInfo ri = mContext.getPackageManager()
7971 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007972 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007973 CharSequence errorMsg = null;
7974 if (ri != null) {
7975 ActivityInfo ai = ri.activityInfo;
7976 ApplicationInfo app = ai.applicationInfo;
7977 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7978 mTopAction = Intent.ACTION_FACTORY_TEST;
7979 mTopData = null;
7980 mTopComponent = new ComponentName(app.packageName,
7981 ai.name);
7982 } else {
7983 errorMsg = mContext.getResources().getText(
7984 com.android.internal.R.string.factorytest_not_system);
7985 }
7986 } else {
7987 errorMsg = mContext.getResources().getText(
7988 com.android.internal.R.string.factorytest_no_action);
7989 }
7990 if (errorMsg != null) {
7991 mTopAction = null;
7992 mTopData = null;
7993 mTopComponent = null;
7994 Message msg = Message.obtain();
7995 msg.what = SHOW_FACTORY_ERROR_MSG;
7996 msg.getData().putCharSequence("msg", errorMsg);
7997 mHandler.sendMessage(msg);
7998 }
7999 }
8000 }
8001
8002 retrieveSettings();
8003
8004 synchronized (this) {
8005 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8006 try {
8007 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008008 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008009 if (apps != null) {
8010 int N = apps.size();
8011 int i;
8012 for (i=0; i<N; i++) {
8013 ApplicationInfo info
8014 = (ApplicationInfo)apps.get(i);
8015 if (info != null &&
8016 !info.packageName.equals("android")) {
8017 addAppLocked(info);
8018 }
8019 }
8020 }
8021 } catch (RemoteException ex) {
8022 // pm is in same process, this will never happen.
8023 }
8024 }
8025
8026 try {
8027 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8028 Message msg = Message.obtain();
8029 msg.what = SHOW_UID_ERROR_MSG;
8030 mHandler.sendMessage(msg);
8031 }
8032 } catch (RemoteException e) {
8033 }
8034
8035 // Start up initial activity.
8036 mBooting = true;
8037 resumeTopActivityLocked(null);
8038 }
8039 }
8040
8041 boolean makeAppCrashingLocked(ProcessRecord app,
8042 String tag, String shortMsg, String longMsg, byte[] crashData) {
8043 app.crashing = true;
8044 app.crashingReport = generateProcessError(app,
8045 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8046 startAppProblemLocked(app);
8047 app.stopFreezingAllLocked();
8048 return handleAppCrashLocked(app);
8049 }
8050
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008051 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8052 IPackageManager pm = ActivityThread.getPackageManager();
8053 try {
8054 // was an installer package name specified when this app was
8055 // installed?
8056 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8057 if (installerPackageName == null) {
8058 return null;
8059 }
8060
8061 // is there an Activity in this package that handles ACTION_APP_ERROR?
8062 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008063 intent.setPackage(installerPackageName);
8064 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008065 if (info == null || info.activityInfo == null) {
8066 return null;
8067 }
8068
8069 return new ComponentName(installerPackageName, info.activityInfo.name);
8070 } catch (RemoteException e) {
8071 // will return null and no error report will be delivered
8072 }
8073 return null;
8074 }
8075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008076 void makeAppNotRespondingLocked(ProcessRecord app,
8077 String tag, String shortMsg, String longMsg, byte[] crashData) {
8078 app.notResponding = true;
8079 app.notRespondingReport = generateProcessError(app,
8080 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8081 crashData);
8082 startAppProblemLocked(app);
8083 app.stopFreezingAllLocked();
8084 }
8085
8086 /**
8087 * Generate a process error record, suitable for attachment to a ProcessRecord.
8088 *
8089 * @param app The ProcessRecord in which the error occurred.
8090 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8091 * ActivityManager.AppErrorStateInfo
8092 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8093 * @param shortMsg Short message describing the crash.
8094 * @param longMsg Long message describing the crash.
8095 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8096 *
8097 * @return Returns a fully-formed AppErrorStateInfo record.
8098 */
8099 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8100 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8101 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8102
8103 report.condition = condition;
8104 report.processName = app.processName;
8105 report.pid = app.pid;
8106 report.uid = app.info.uid;
8107 report.tag = tag;
8108 report.shortMsg = shortMsg;
8109 report.longMsg = longMsg;
8110 report.crashData = crashData;
8111
8112 return report;
8113 }
8114
8115 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8116 boolean crashed) {
8117 synchronized (this) {
8118 app.crashing = false;
8119 app.crashingReport = null;
8120 app.notResponding = false;
8121 app.notRespondingReport = null;
8122 if (app.anrDialog == fromDialog) {
8123 app.anrDialog = null;
8124 }
8125 if (app.waitDialog == fromDialog) {
8126 app.waitDialog = null;
8127 }
8128 if (app.pid > 0 && app.pid != MY_PID) {
8129 if (crashed) {
8130 handleAppCrashLocked(app);
8131 }
8132 Log.i(ActivityManagerService.TAG, "Killing process "
8133 + app.processName
8134 + " (pid=" + app.pid + ") at user's request");
8135 Process.killProcess(app.pid);
8136 }
8137
8138 }
8139 }
8140
8141 boolean handleAppCrashLocked(ProcessRecord app) {
8142 long now = SystemClock.uptimeMillis();
8143
8144 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8145 app.info.uid);
8146 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8147 // This process loses!
8148 Log.w(TAG, "Process " + app.info.processName
8149 + " has crashed too many times: killing!");
8150 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8151 app.info.processName, app.info.uid);
8152 killServicesLocked(app, false);
8153 for (int i=mHistory.size()-1; i>=0; i--) {
8154 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8155 if (r.app == app) {
8156 if (Config.LOGD) Log.d(
8157 TAG, " Force finishing activity "
8158 + r.intent.getComponent().flattenToShortString());
8159 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8160 }
8161 }
8162 if (!app.persistent) {
8163 // We don't want to start this process again until the user
8164 // explicitly does so... but for persistent process, we really
8165 // need to keep it running. If a persistent process is actually
8166 // repeatedly crashing, then badness for everyone.
8167 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8168 app.info.processName);
8169 mBadProcesses.put(app.info.processName, app.info.uid, now);
8170 app.bad = true;
8171 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8172 app.removed = true;
8173 removeProcessLocked(app, false);
8174 return false;
8175 }
8176 }
8177
8178 // Bump up the crash count of any services currently running in the proc.
8179 if (app.services.size() != 0) {
8180 // Any services running in the application need to be placed
8181 // back in the pending list.
8182 Iterator it = app.services.iterator();
8183 while (it.hasNext()) {
8184 ServiceRecord sr = (ServiceRecord)it.next();
8185 sr.crashCount++;
8186 }
8187 }
8188
8189 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8190 return true;
8191 }
8192
8193 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008194 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008195 skipCurrentReceiverLocked(app);
8196 }
8197
8198 void skipCurrentReceiverLocked(ProcessRecord app) {
8199 boolean reschedule = false;
8200 BroadcastRecord r = app.curReceiver;
8201 if (r != null) {
8202 // The current broadcast is waiting for this app's receiver
8203 // to be finished. Looks like that's not going to happen, so
8204 // let the broadcast continue.
8205 logBroadcastReceiverDiscard(r);
8206 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8207 r.resultExtras, r.resultAbort, true);
8208 reschedule = true;
8209 }
8210 r = mPendingBroadcast;
8211 if (r != null && r.curApp == app) {
8212 if (DEBUG_BROADCAST) Log.v(TAG,
8213 "skip & discard pending app " + r);
8214 logBroadcastReceiverDiscard(r);
8215 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8216 r.resultExtras, r.resultAbort, true);
8217 reschedule = true;
8218 }
8219 if (reschedule) {
8220 scheduleBroadcastsLocked();
8221 }
8222 }
8223
8224 public int handleApplicationError(IBinder app, int flags,
8225 String tag, String shortMsg, String longMsg, byte[] crashData) {
8226 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008227 ProcessRecord r = null;
8228 synchronized (this) {
8229 if (app != null) {
8230 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8231 final int NA = apps.size();
8232 for (int ia=0; ia<NA; ia++) {
8233 ProcessRecord p = apps.valueAt(ia);
8234 if (p.thread != null && p.thread.asBinder() == app) {
8235 r = p;
8236 break;
8237 }
8238 }
8239 }
8240 }
8241
8242 if (r != null) {
8243 // The application has crashed. Send the SIGQUIT to the process so
8244 // that it can dump its state.
8245 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8246 //Log.i(TAG, "Current system threads:");
8247 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8248 }
8249
8250 if (mWatcher != null) {
8251 try {
8252 String name = r != null ? r.processName : null;
8253 int pid = r != null ? r.pid : Binder.getCallingPid();
8254 if (!mWatcher.appCrashed(name, pid,
8255 shortMsg, longMsg, crashData)) {
8256 Log.w(TAG, "Force-killing crashed app " + name
8257 + " at watcher's request");
8258 Process.killProcess(pid);
8259 return 0;
8260 }
8261 } catch (RemoteException e) {
8262 mWatcher = null;
8263 }
8264 }
8265
8266 final long origId = Binder.clearCallingIdentity();
8267
8268 // If this process is running instrumentation, finish it.
8269 if (r != null && r.instrumentationClass != null) {
8270 Log.w(TAG, "Error in app " + r.processName
8271 + " running instrumentation " + r.instrumentationClass + ":");
8272 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8273 if (longMsg != null) Log.w(TAG, " " + longMsg);
8274 Bundle info = new Bundle();
8275 info.putString("shortMsg", shortMsg);
8276 info.putString("longMsg", longMsg);
8277 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8278 Binder.restoreCallingIdentity(origId);
8279 return 0;
8280 }
8281
8282 if (r != null) {
8283 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8284 return 0;
8285 }
8286 } else {
8287 Log.w(TAG, "Some application object " + app + " tag " + tag
8288 + " has crashed, but I don't know who it is.");
8289 Log.w(TAG, "ShortMsg:" + shortMsg);
8290 Log.w(TAG, "LongMsg:" + longMsg);
8291 Binder.restoreCallingIdentity(origId);
8292 return 0;
8293 }
8294
8295 Message msg = Message.obtain();
8296 msg.what = SHOW_ERROR_MSG;
8297 HashMap data = new HashMap();
8298 data.put("result", result);
8299 data.put("app", r);
8300 data.put("flags", flags);
8301 data.put("shortMsg", shortMsg);
8302 data.put("longMsg", longMsg);
8303 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8304 // For system processes, submit crash data to the server.
8305 data.put("crashData", crashData);
8306 }
8307 msg.obj = data;
8308 mHandler.sendMessage(msg);
8309
8310 Binder.restoreCallingIdentity(origId);
8311 }
8312
8313 int res = result.get();
8314
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008315 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008316 synchronized (this) {
8317 if (r != null) {
8318 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8319 SystemClock.uptimeMillis());
8320 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008321 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8322 appErrorIntent = createAppErrorIntentLocked(r);
8323 res = AppErrorDialog.FORCE_QUIT;
8324 }
8325 }
8326
8327 if (appErrorIntent != null) {
8328 try {
8329 mContext.startActivity(appErrorIntent);
8330 } catch (ActivityNotFoundException e) {
8331 Log.w(TAG, "bug report receiver dissappeared", e);
8332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008333 }
8334
8335 return res;
8336 }
8337
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008338 Intent createAppErrorIntentLocked(ProcessRecord r) {
8339 ApplicationErrorReport report = createAppErrorReportLocked(r);
8340 if (report == null) {
8341 return null;
8342 }
8343 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8344 result.setComponent(r.errorReportReceiver);
8345 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8346 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8347 return result;
8348 }
8349
8350 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8351 if (r.errorReportReceiver == null) {
8352 return null;
8353 }
8354
8355 if (!r.crashing && !r.notResponding) {
8356 return null;
8357 }
8358
8359 try {
8360 ApplicationErrorReport report = new ApplicationErrorReport();
8361 report.packageName = r.info.packageName;
8362 report.installerPackageName = r.errorReportReceiver.getPackageName();
8363 report.processName = r.processName;
8364
8365 if (r.crashing) {
8366 report.type = ApplicationErrorReport.TYPE_CRASH;
8367 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8368
8369 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8370 r.crashingReport.crashData);
8371 DataInputStream dataStream = new DataInputStream(byteStream);
8372 CrashData crashData = new CrashData(dataStream);
8373 ThrowableData throwData = crashData.getThrowableData();
8374
8375 report.time = crashData.getTime();
8376 report.crashInfo.stackTrace = throwData.toString();
8377
Jacek Surazskif829a782009-06-11 22:47:02 +02008378 // Extract the source of the exception, useful for report
8379 // clustering. Also extract the "deepest" non-null exception
8380 // message.
8381 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008382 while (throwData.getCause() != null) {
8383 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008384 String msg = throwData.getMessage();
8385 if (msg != null && msg.length() > 0) {
8386 exceptionMessage = msg;
8387 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008388 }
8389 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008390 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008391 report.crashInfo.exceptionClassName = throwData.getType();
8392 report.crashInfo.throwFileName = trace.getFileName();
8393 report.crashInfo.throwClassName = trace.getClassName();
8394 report.crashInfo.throwMethodName = trace.getMethodName();
8395 } else if (r.notResponding) {
8396 report.type = ApplicationErrorReport.TYPE_ANR;
8397 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8398
8399 report.anrInfo.activity = r.notRespondingReport.tag;
8400 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8401 report.anrInfo.info = r.notRespondingReport.longMsg;
8402 }
8403
8404 return report;
8405 } catch (IOException e) {
8406 // we don't send it
8407 }
8408
8409 return null;
8410 }
8411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008412 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8413 // assume our apps are happy - lazy create the list
8414 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8415
8416 synchronized (this) {
8417
8418 // iterate across all processes
8419 final int N = mLRUProcesses.size();
8420 for (int i = 0; i < N; i++) {
8421 ProcessRecord app = mLRUProcesses.get(i);
8422 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8423 // This one's in trouble, so we'll generate a report for it
8424 // crashes are higher priority (in case there's a crash *and* an anr)
8425 ActivityManager.ProcessErrorStateInfo report = null;
8426 if (app.crashing) {
8427 report = app.crashingReport;
8428 } else if (app.notResponding) {
8429 report = app.notRespondingReport;
8430 }
8431
8432 if (report != null) {
8433 if (errList == null) {
8434 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8435 }
8436 errList.add(report);
8437 } else {
8438 Log.w(TAG, "Missing app error report, app = " + app.processName +
8439 " crashing = " + app.crashing +
8440 " notResponding = " + app.notResponding);
8441 }
8442 }
8443 }
8444 }
8445
8446 return errList;
8447 }
8448
8449 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8450 // Lazy instantiation of list
8451 List<ActivityManager.RunningAppProcessInfo> runList = null;
8452 synchronized (this) {
8453 // Iterate across all processes
8454 final int N = mLRUProcesses.size();
8455 for (int i = 0; i < N; i++) {
8456 ProcessRecord app = mLRUProcesses.get(i);
8457 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8458 // Generate process state info for running application
8459 ActivityManager.RunningAppProcessInfo currApp =
8460 new ActivityManager.RunningAppProcessInfo(app.processName,
8461 app.pid, app.getPackageList());
8462 int adj = app.curAdj;
8463 if (adj >= CONTENT_PROVIDER_ADJ) {
8464 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8465 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8466 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008467 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8468 } else if (adj >= HOME_APP_ADJ) {
8469 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8470 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008471 } else if (adj >= SECONDARY_SERVER_ADJ) {
8472 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8473 } else if (adj >= VISIBLE_APP_ADJ) {
8474 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8475 } else {
8476 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8477 }
8478 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8479 // + " lru=" + currApp.lru);
8480 if (runList == null) {
8481 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8482 }
8483 runList.add(currApp);
8484 }
8485 }
8486 }
8487 return runList;
8488 }
8489
8490 @Override
8491 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8492 synchronized (this) {
8493 if (checkCallingPermission(android.Manifest.permission.DUMP)
8494 != PackageManager.PERMISSION_GRANTED) {
8495 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8496 + Binder.getCallingPid()
8497 + ", uid=" + Binder.getCallingUid()
8498 + " without permission "
8499 + android.Manifest.permission.DUMP);
8500 return;
8501 }
8502 if (args.length != 0 && "service".equals(args[0])) {
8503 dumpService(fd, pw, args);
8504 return;
8505 }
8506 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008507 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008508 pw.println(" ");
8509 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008510 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 if (mWaitingVisibleActivities.size() > 0) {
8512 pw.println(" ");
8513 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008514 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008515 }
8516 if (mStoppingActivities.size() > 0) {
8517 pw.println(" ");
8518 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008519 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 }
8521 if (mFinishingActivities.size() > 0) {
8522 pw.println(" ");
8523 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008524 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008525 }
8526
8527 pw.println(" ");
8528 pw.println(" mPausingActivity: " + mPausingActivity);
8529 pw.println(" mResumedActivity: " + mResumedActivity);
8530 pw.println(" mFocusedActivity: " + mFocusedActivity);
8531 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8532
8533 if (mRecentTasks.size() > 0) {
8534 pw.println(" ");
8535 pw.println("Recent tasks in Current Activity Manager State:");
8536
8537 final int N = mRecentTasks.size();
8538 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008539 TaskRecord tr = mRecentTasks.get(i);
8540 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8541 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008542 mRecentTasks.get(i).dump(pw, " ");
8543 }
8544 }
8545
8546 pw.println(" ");
8547 pw.println(" mCurTask: " + mCurTask);
8548
8549 pw.println(" ");
8550 pw.println("Processes in Current Activity Manager State:");
8551
8552 boolean needSep = false;
8553 int numPers = 0;
8554
8555 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8556 final int NA = procs.size();
8557 for (int ia=0; ia<NA; ia++) {
8558 if (!needSep) {
8559 pw.println(" All known processes:");
8560 needSep = true;
8561 }
8562 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008563 pw.print(r.persistent ? " *PERS*" : " *APP*");
8564 pw.print(" UID "); pw.print(procs.keyAt(ia));
8565 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 r.dump(pw, " ");
8567 if (r.persistent) {
8568 numPers++;
8569 }
8570 }
8571 }
8572
8573 if (mLRUProcesses.size() > 0) {
8574 if (needSep) pw.println(" ");
8575 needSep = true;
8576 pw.println(" Running processes (most recent first):");
8577 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008578 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008579 needSep = true;
8580 }
8581
8582 synchronized (mPidsSelfLocked) {
8583 if (mPidsSelfLocked.size() > 0) {
8584 if (needSep) pw.println(" ");
8585 needSep = true;
8586 pw.println(" PID mappings:");
8587 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008588 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8589 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008590 }
8591 }
8592 }
8593
8594 if (mForegroundProcesses.size() > 0) {
8595 if (needSep) pw.println(" ");
8596 needSep = true;
8597 pw.println(" Foreground Processes:");
8598 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008599 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8600 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008601 }
8602 }
8603
8604 if (mPersistentStartingProcesses.size() > 0) {
8605 if (needSep) pw.println(" ");
8606 needSep = true;
8607 pw.println(" Persisent processes that are starting:");
8608 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008609 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008610 }
8611
8612 if (mStartingProcesses.size() > 0) {
8613 if (needSep) pw.println(" ");
8614 needSep = true;
8615 pw.println(" Processes that are starting:");
8616 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008617 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008618 }
8619
8620 if (mRemovedProcesses.size() > 0) {
8621 if (needSep) pw.println(" ");
8622 needSep = true;
8623 pw.println(" Processes that are being removed:");
8624 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008625 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008626 }
8627
8628 if (mProcessesOnHold.size() > 0) {
8629 if (needSep) pw.println(" ");
8630 needSep = true;
8631 pw.println(" Processes that are on old until the system is ready:");
8632 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008633 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008634 }
8635
8636 if (mProcessCrashTimes.getMap().size() > 0) {
8637 if (needSep) pw.println(" ");
8638 needSep = true;
8639 pw.println(" Time since processes crashed:");
8640 long now = SystemClock.uptimeMillis();
8641 for (Map.Entry<String, SparseArray<Long>> procs
8642 : mProcessCrashTimes.getMap().entrySet()) {
8643 SparseArray<Long> uids = procs.getValue();
8644 final int N = uids.size();
8645 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008646 pw.print(" Process "); pw.print(procs.getKey());
8647 pw.print(" uid "); pw.print(uids.keyAt(i));
8648 pw.print(": last crashed ");
8649 pw.print((now-uids.valueAt(i)));
8650 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008651 }
8652 }
8653 }
8654
8655 if (mBadProcesses.getMap().size() > 0) {
8656 if (needSep) pw.println(" ");
8657 needSep = true;
8658 pw.println(" Bad processes:");
8659 for (Map.Entry<String, SparseArray<Long>> procs
8660 : mBadProcesses.getMap().entrySet()) {
8661 SparseArray<Long> uids = procs.getValue();
8662 final int N = uids.size();
8663 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008664 pw.print(" Bad process "); pw.print(procs.getKey());
8665 pw.print(" uid "); pw.print(uids.keyAt(i));
8666 pw.print(": crashed at time ");
8667 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008668 }
8669 }
8670 }
8671
8672 pw.println(" ");
8673 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008674 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 pw.println(" mConfiguration: " + mConfiguration);
8676 pw.println(" mStartRunning=" + mStartRunning
8677 + " mSystemReady=" + mSystemReady
8678 + " mBooting=" + mBooting
8679 + " mBooted=" + mBooted
8680 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008681 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008682 pw.println(" mGoingToSleep=" + mGoingToSleep);
8683 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8684 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8685 + " mDebugTransient=" + mDebugTransient
8686 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8687 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8688 + " mWatcher=" + mWatcher);
8689 }
8690 }
8691
8692 /**
8693 * There are three ways to call this:
8694 * - no service specified: dump all the services
8695 * - a flattened component name that matched an existing service was specified as the
8696 * first arg: dump that one service
8697 * - the first arg isn't the flattened component name of an existing service:
8698 * dump all services whose component contains the first arg as a substring
8699 */
8700 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8701 String[] newArgs;
8702 String componentNameString;
8703 ServiceRecord r;
8704 if (args.length == 1) {
8705 componentNameString = null;
8706 newArgs = EMPTY_STRING_ARRAY;
8707 r = null;
8708 } else {
8709 componentNameString = args[1];
8710 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8711 r = componentName != null ? mServices.get(componentName) : null;
8712 newArgs = new String[args.length - 2];
8713 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8714 }
8715
8716 if (r != null) {
8717 dumpService(fd, pw, r, newArgs);
8718 } else {
8719 for (ServiceRecord r1 : mServices.values()) {
8720 if (componentNameString == null
8721 || r1.name.flattenToString().contains(componentNameString)) {
8722 dumpService(fd, pw, r1, newArgs);
8723 }
8724 }
8725 }
8726 }
8727
8728 /**
8729 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8730 * there is a thread associated with the service.
8731 */
8732 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8733 pw.println(" Service " + r.name.flattenToString());
8734 if (r.app != null && r.app.thread != null) {
8735 try {
8736 // flush anything that is already in the PrintWriter since the thread is going
8737 // to write to the file descriptor directly
8738 pw.flush();
8739 r.app.thread.dumpService(fd, r, args);
8740 pw.print("\n");
8741 } catch (RemoteException e) {
8742 pw.println("got a RemoteException while dumping the service");
8743 }
8744 }
8745 }
8746
8747 void dumpBroadcasts(PrintWriter pw) {
8748 synchronized (this) {
8749 if (checkCallingPermission(android.Manifest.permission.DUMP)
8750 != PackageManager.PERMISSION_GRANTED) {
8751 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8752 + Binder.getCallingPid()
8753 + ", uid=" + Binder.getCallingUid()
8754 + " without permission "
8755 + android.Manifest.permission.DUMP);
8756 return;
8757 }
8758 pw.println("Broadcasts in Current Activity Manager State:");
8759
8760 if (mRegisteredReceivers.size() > 0) {
8761 pw.println(" ");
8762 pw.println(" Registered Receivers:");
8763 Iterator it = mRegisteredReceivers.values().iterator();
8764 while (it.hasNext()) {
8765 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008766 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008767 r.dump(pw, " ");
8768 }
8769 }
8770
8771 pw.println(" ");
8772 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008773 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008774
8775 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8776 || mPendingBroadcast != null) {
8777 if (mParallelBroadcasts.size() > 0) {
8778 pw.println(" ");
8779 pw.println(" Active broadcasts:");
8780 }
8781 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8782 pw.println(" Broadcast #" + i + ":");
8783 mParallelBroadcasts.get(i).dump(pw, " ");
8784 }
8785 if (mOrderedBroadcasts.size() > 0) {
8786 pw.println(" ");
8787 pw.println(" Active serialized broadcasts:");
8788 }
8789 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8790 pw.println(" Serialized Broadcast #" + i + ":");
8791 mOrderedBroadcasts.get(i).dump(pw, " ");
8792 }
8793 pw.println(" ");
8794 pw.println(" Pending broadcast:");
8795 if (mPendingBroadcast != null) {
8796 mPendingBroadcast.dump(pw, " ");
8797 } else {
8798 pw.println(" (null)");
8799 }
8800 }
8801
8802 pw.println(" ");
8803 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8804 if (mStickyBroadcasts != null) {
8805 pw.println(" ");
8806 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008807 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 for (Map.Entry<String, ArrayList<Intent>> ent
8809 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008810 pw.print(" * Sticky action "); pw.print(ent.getKey());
8811 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008812 ArrayList<Intent> intents = ent.getValue();
8813 final int N = intents.size();
8814 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008815 sb.setLength(0);
8816 sb.append(" Intent: ");
8817 intents.get(i).toShortString(sb, true, false);
8818 pw.println(sb.toString());
8819 Bundle bundle = intents.get(i).getExtras();
8820 if (bundle != null) {
8821 pw.print(" ");
8822 pw.println(bundle.toString());
8823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008824 }
8825 }
8826 }
8827
8828 pw.println(" ");
8829 pw.println(" mHandler:");
8830 mHandler.dump(new PrintWriterPrinter(pw), " ");
8831 }
8832 }
8833
8834 void dumpServices(PrintWriter pw) {
8835 synchronized (this) {
8836 if (checkCallingPermission(android.Manifest.permission.DUMP)
8837 != PackageManager.PERMISSION_GRANTED) {
8838 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8839 + Binder.getCallingPid()
8840 + ", uid=" + Binder.getCallingUid()
8841 + " without permission "
8842 + android.Manifest.permission.DUMP);
8843 return;
8844 }
8845 pw.println("Services in Current Activity Manager State:");
8846
8847 boolean needSep = false;
8848
8849 if (mServices.size() > 0) {
8850 pw.println(" Active services:");
8851 Iterator<ServiceRecord> it = mServices.values().iterator();
8852 while (it.hasNext()) {
8853 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008854 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008855 r.dump(pw, " ");
8856 }
8857 needSep = true;
8858 }
8859
8860 if (mPendingServices.size() > 0) {
8861 if (needSep) pw.println(" ");
8862 pw.println(" Pending services:");
8863 for (int i=0; i<mPendingServices.size(); i++) {
8864 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008865 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008866 r.dump(pw, " ");
8867 }
8868 needSep = true;
8869 }
8870
8871 if (mRestartingServices.size() > 0) {
8872 if (needSep) pw.println(" ");
8873 pw.println(" Restarting services:");
8874 for (int i=0; i<mRestartingServices.size(); i++) {
8875 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008876 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008877 r.dump(pw, " ");
8878 }
8879 needSep = true;
8880 }
8881
8882 if (mStoppingServices.size() > 0) {
8883 if (needSep) pw.println(" ");
8884 pw.println(" Stopping services:");
8885 for (int i=0; i<mStoppingServices.size(); i++) {
8886 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008887 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008888 r.dump(pw, " ");
8889 }
8890 needSep = true;
8891 }
8892
8893 if (mServiceConnections.size() > 0) {
8894 if (needSep) pw.println(" ");
8895 pw.println(" Connection bindings to services:");
8896 Iterator<ConnectionRecord> it
8897 = mServiceConnections.values().iterator();
8898 while (it.hasNext()) {
8899 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008900 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008901 r.dump(pw, " ");
8902 }
8903 }
8904 }
8905 }
8906
8907 void dumpProviders(PrintWriter pw) {
8908 synchronized (this) {
8909 if (checkCallingPermission(android.Manifest.permission.DUMP)
8910 != PackageManager.PERMISSION_GRANTED) {
8911 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8912 + Binder.getCallingPid()
8913 + ", uid=" + Binder.getCallingUid()
8914 + " without permission "
8915 + android.Manifest.permission.DUMP);
8916 return;
8917 }
8918
8919 pw.println("Content Providers in Current Activity Manager State:");
8920
8921 boolean needSep = false;
8922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008923 if (mProvidersByClass.size() > 0) {
8924 if (needSep) pw.println(" ");
8925 pw.println(" Published content providers (by class):");
8926 Iterator it = mProvidersByClass.entrySet().iterator();
8927 while (it.hasNext()) {
8928 Map.Entry e = (Map.Entry)it.next();
8929 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008930 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 r.dump(pw, " ");
8932 }
8933 needSep = true;
8934 }
8935
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008936 if (mProvidersByName.size() > 0) {
8937 pw.println(" ");
8938 pw.println(" Authority to provider mappings:");
8939 Iterator it = mProvidersByName.entrySet().iterator();
8940 while (it.hasNext()) {
8941 Map.Entry e = (Map.Entry)it.next();
8942 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8943 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8944 pw.println(r);
8945 }
8946 needSep = true;
8947 }
8948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008949 if (mLaunchingProviders.size() > 0) {
8950 if (needSep) pw.println(" ");
8951 pw.println(" Launching content providers:");
8952 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008953 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8954 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008955 }
8956 needSep = true;
8957 }
8958
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008959 if (mGrantedUriPermissions.size() > 0) {
8960 pw.println();
8961 pw.println("Granted Uri Permissions:");
8962 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8963 int uid = mGrantedUriPermissions.keyAt(i);
8964 HashMap<Uri, UriPermission> perms
8965 = mGrantedUriPermissions.valueAt(i);
8966 pw.print(" * UID "); pw.print(uid);
8967 pw.println(" holds:");
8968 for (UriPermission perm : perms.values()) {
8969 pw.print(" "); pw.println(perm);
8970 perm.dump(pw, " ");
8971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 }
8973 }
8974 }
8975 }
8976
8977 void dumpSenders(PrintWriter pw) {
8978 synchronized (this) {
8979 if (checkCallingPermission(android.Manifest.permission.DUMP)
8980 != PackageManager.PERMISSION_GRANTED) {
8981 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8982 + Binder.getCallingPid()
8983 + ", uid=" + Binder.getCallingUid()
8984 + " without permission "
8985 + android.Manifest.permission.DUMP);
8986 return;
8987 }
8988
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008989 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008990
8991 if (this.mIntentSenderRecords.size() > 0) {
8992 Iterator<WeakReference<PendingIntentRecord>> it
8993 = mIntentSenderRecords.values().iterator();
8994 while (it.hasNext()) {
8995 WeakReference<PendingIntentRecord> ref = it.next();
8996 PendingIntentRecord rec = ref != null ? ref.get(): null;
8997 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008998 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008999 rec.dump(pw, " ");
9000 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009001 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009002 }
9003 }
9004 }
9005 }
9006 }
9007
9008 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009009 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009010 TaskRecord lastTask = null;
9011 for (int i=list.size()-1; i>=0; i--) {
9012 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009013 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009014 if (lastTask != r.task) {
9015 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009016 pw.print(prefix);
9017 pw.print(full ? "* " : " ");
9018 pw.println(lastTask);
9019 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009020 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009021 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009022 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009023 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9024 pw.print(" #"); pw.print(i); pw.print(": ");
9025 pw.println(r);
9026 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009027 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009029 }
9030 }
9031
9032 private static final int dumpProcessList(PrintWriter pw, List list,
9033 String prefix, String normalLabel, String persistentLabel,
9034 boolean inclOomAdj) {
9035 int numPers = 0;
9036 for (int i=list.size()-1; i>=0; i--) {
9037 ProcessRecord r = (ProcessRecord)list.get(i);
9038 if (false) {
9039 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9040 + " #" + i + ":");
9041 r.dump(pw, prefix + " ");
9042 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009043 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009044 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009045 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009046 } else {
9047 pw.println(String.format("%s%s #%2d: %s",
9048 prefix, (r.persistent ? persistentLabel : normalLabel),
9049 i, r.toString()));
9050 }
9051 if (r.persistent) {
9052 numPers++;
9053 }
9054 }
9055 return numPers;
9056 }
9057
9058 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9059 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009060 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 long uptime = SystemClock.uptimeMillis();
9062 long realtime = SystemClock.elapsedRealtime();
9063
9064 if (isCheckinRequest) {
9065 // short checkin version
9066 pw.println(uptime + "," + realtime);
9067 pw.flush();
9068 } else {
9069 pw.println("Applications Memory Usage (kB):");
9070 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9071 }
9072 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9073 ProcessRecord r = (ProcessRecord)list.get(i);
9074 if (r.thread != null) {
9075 if (!isCheckinRequest) {
9076 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9077 pw.flush();
9078 }
9079 try {
9080 r.thread.asBinder().dump(fd, args);
9081 } catch (RemoteException e) {
9082 if (!isCheckinRequest) {
9083 pw.println("Got RemoteException!");
9084 pw.flush();
9085 }
9086 }
9087 }
9088 }
9089 }
9090
9091 /**
9092 * Searches array of arguments for the specified string
9093 * @param args array of argument strings
9094 * @param value value to search for
9095 * @return true if the value is contained in the array
9096 */
9097 private static boolean scanArgs(String[] args, String value) {
9098 if (args != null) {
9099 for (String arg : args) {
9100 if (value.equals(arg)) {
9101 return true;
9102 }
9103 }
9104 }
9105 return false;
9106 }
9107
Dianne Hackborn75b03852009-06-12 15:43:26 -07009108 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009109 int count = mHistory.size();
9110
9111 // convert the token to an entry in the history.
9112 HistoryRecord r = null;
9113 int index = -1;
9114 for (int i=count-1; i>=0; i--) {
9115 Object o = mHistory.get(i);
9116 if (o == token) {
9117 r = (HistoryRecord)o;
9118 index = i;
9119 break;
9120 }
9121 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009122
9123 return index;
9124 }
9125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009126 private final void killServicesLocked(ProcessRecord app,
9127 boolean allowRestart) {
9128 // Report disconnected services.
9129 if (false) {
9130 // XXX we are letting the client link to the service for
9131 // death notifications.
9132 if (app.services.size() > 0) {
9133 Iterator it = app.services.iterator();
9134 while (it.hasNext()) {
9135 ServiceRecord r = (ServiceRecord)it.next();
9136 if (r.connections.size() > 0) {
9137 Iterator<ConnectionRecord> jt
9138 = r.connections.values().iterator();
9139 while (jt.hasNext()) {
9140 ConnectionRecord c = jt.next();
9141 if (c.binding.client != app) {
9142 try {
9143 //c.conn.connected(r.className, null);
9144 } catch (Exception e) {
9145 // todo: this should be asynchronous!
9146 Log.w(TAG, "Exception thrown disconnected servce "
9147 + r.shortName
9148 + " from app " + app.processName, e);
9149 }
9150 }
9151 }
9152 }
9153 }
9154 }
9155 }
9156
9157 // Clean up any connections this application has to other services.
9158 if (app.connections.size() > 0) {
9159 Iterator<ConnectionRecord> it = app.connections.iterator();
9160 while (it.hasNext()) {
9161 ConnectionRecord r = it.next();
9162 removeConnectionLocked(r, app, null);
9163 }
9164 }
9165 app.connections.clear();
9166
9167 if (app.services.size() != 0) {
9168 // Any services running in the application need to be placed
9169 // back in the pending list.
9170 Iterator it = app.services.iterator();
9171 while (it.hasNext()) {
9172 ServiceRecord sr = (ServiceRecord)it.next();
9173 synchronized (sr.stats.getBatteryStats()) {
9174 sr.stats.stopLaunchedLocked();
9175 }
9176 sr.app = null;
9177 sr.executeNesting = 0;
9178 mStoppingServices.remove(sr);
9179 if (sr.bindings.size() > 0) {
9180 Iterator<IntentBindRecord> bindings
9181 = sr.bindings.values().iterator();
9182 while (bindings.hasNext()) {
9183 IntentBindRecord b = bindings.next();
9184 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9185 + ": shouldUnbind=" + b.hasBound);
9186 b.binder = null;
9187 b.requested = b.received = b.hasBound = false;
9188 }
9189 }
9190
9191 if (sr.crashCount >= 2) {
9192 Log.w(TAG, "Service crashed " + sr.crashCount
9193 + " times, stopping: " + sr);
9194 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9195 sr.crashCount, sr.shortName, app.pid);
9196 bringDownServiceLocked(sr, true);
9197 } else if (!allowRestart) {
9198 bringDownServiceLocked(sr, true);
9199 } else {
9200 scheduleServiceRestartLocked(sr);
9201 }
9202 }
9203
9204 if (!allowRestart) {
9205 app.services.clear();
9206 }
9207 }
9208
9209 app.executingServices.clear();
9210 }
9211
9212 private final void removeDyingProviderLocked(ProcessRecord proc,
9213 ContentProviderRecord cpr) {
9214 synchronized (cpr) {
9215 cpr.launchingApp = null;
9216 cpr.notifyAll();
9217 }
9218
9219 mProvidersByClass.remove(cpr.info.name);
9220 String names[] = cpr.info.authority.split(";");
9221 for (int j = 0; j < names.length; j++) {
9222 mProvidersByName.remove(names[j]);
9223 }
9224
9225 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9226 while (cit.hasNext()) {
9227 ProcessRecord capp = cit.next();
9228 if (!capp.persistent && capp.thread != null
9229 && capp.pid != 0
9230 && capp.pid != MY_PID) {
9231 Log.i(TAG, "Killing app " + capp.processName
9232 + " (pid " + capp.pid
9233 + ") because provider " + cpr.info.name
9234 + " is in dying process " + proc.processName);
9235 Process.killProcess(capp.pid);
9236 }
9237 }
9238
9239 mLaunchingProviders.remove(cpr);
9240 }
9241
9242 /**
9243 * Main code for cleaning up a process when it has gone away. This is
9244 * called both as a result of the process dying, or directly when stopping
9245 * a process when running in single process mode.
9246 */
9247 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9248 boolean restarting, int index) {
9249 if (index >= 0) {
9250 mLRUProcesses.remove(index);
9251 }
9252
9253 // Dismiss any open dialogs.
9254 if (app.crashDialog != null) {
9255 app.crashDialog.dismiss();
9256 app.crashDialog = null;
9257 }
9258 if (app.anrDialog != null) {
9259 app.anrDialog.dismiss();
9260 app.anrDialog = null;
9261 }
9262 if (app.waitDialog != null) {
9263 app.waitDialog.dismiss();
9264 app.waitDialog = null;
9265 }
9266
9267 app.crashing = false;
9268 app.notResponding = false;
9269
9270 app.resetPackageList();
9271 app.thread = null;
9272 app.forcingToForeground = null;
9273 app.foregroundServices = false;
9274
9275 killServicesLocked(app, true);
9276
9277 boolean restart = false;
9278
9279 int NL = mLaunchingProviders.size();
9280
9281 // Remove published content providers.
9282 if (!app.pubProviders.isEmpty()) {
9283 Iterator it = app.pubProviders.values().iterator();
9284 while (it.hasNext()) {
9285 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9286 cpr.provider = null;
9287 cpr.app = null;
9288
9289 // See if someone is waiting for this provider... in which
9290 // case we don't remove it, but just let it restart.
9291 int i = 0;
9292 if (!app.bad) {
9293 for (; i<NL; i++) {
9294 if (mLaunchingProviders.get(i) == cpr) {
9295 restart = true;
9296 break;
9297 }
9298 }
9299 } else {
9300 i = NL;
9301 }
9302
9303 if (i >= NL) {
9304 removeDyingProviderLocked(app, cpr);
9305 NL = mLaunchingProviders.size();
9306 }
9307 }
9308 app.pubProviders.clear();
9309 }
9310
9311 // Look through the content providers we are waiting to have launched,
9312 // and if any run in this process then either schedule a restart of
9313 // the process or kill the client waiting for it if this process has
9314 // gone bad.
9315 for (int i=0; i<NL; i++) {
9316 ContentProviderRecord cpr = (ContentProviderRecord)
9317 mLaunchingProviders.get(i);
9318 if (cpr.launchingApp == app) {
9319 if (!app.bad) {
9320 restart = true;
9321 } else {
9322 removeDyingProviderLocked(app, cpr);
9323 NL = mLaunchingProviders.size();
9324 }
9325 }
9326 }
9327
9328 // Unregister from connected content providers.
9329 if (!app.conProviders.isEmpty()) {
9330 Iterator it = app.conProviders.iterator();
9331 while (it.hasNext()) {
9332 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9333 cpr.clients.remove(app);
9334 }
9335 app.conProviders.clear();
9336 }
9337
9338 skipCurrentReceiverLocked(app);
9339
9340 // Unregister any receivers.
9341 if (app.receivers.size() > 0) {
9342 Iterator<ReceiverList> it = app.receivers.iterator();
9343 while (it.hasNext()) {
9344 removeReceiverLocked(it.next());
9345 }
9346 app.receivers.clear();
9347 }
9348
Christopher Tate181fafa2009-05-14 11:12:14 -07009349 // If the app is undergoing backup, tell the backup manager about it
9350 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9351 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9352 try {
9353 IBackupManager bm = IBackupManager.Stub.asInterface(
9354 ServiceManager.getService(Context.BACKUP_SERVICE));
9355 bm.agentDisconnected(app.info.packageName);
9356 } catch (RemoteException e) {
9357 // can't happen; backup manager is local
9358 }
9359 }
9360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009361 // If the caller is restarting this app, then leave it in its
9362 // current lists and let the caller take care of it.
9363 if (restarting) {
9364 return;
9365 }
9366
9367 if (!app.persistent) {
9368 if (DEBUG_PROCESSES) Log.v(TAG,
9369 "Removing non-persistent process during cleanup: " + app);
9370 mProcessNames.remove(app.processName, app.info.uid);
9371 } else if (!app.removed) {
9372 // This app is persistent, so we need to keep its record around.
9373 // If it is not already on the pending app list, add it there
9374 // and start a new process for it.
9375 app.thread = null;
9376 app.forcingToForeground = null;
9377 app.foregroundServices = false;
9378 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9379 mPersistentStartingProcesses.add(app);
9380 restart = true;
9381 }
9382 }
9383 mProcessesOnHold.remove(app);
9384
The Android Open Source Project4df24232009-03-05 14:34:35 -08009385 if (app == mHomeProcess) {
9386 mHomeProcess = null;
9387 }
9388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009389 if (restart) {
9390 // We have components that still need to be running in the
9391 // process, so re-launch it.
9392 mProcessNames.put(app.processName, app.info.uid, app);
9393 startProcessLocked(app, "restart", app.processName);
9394 } else if (app.pid > 0 && app.pid != MY_PID) {
9395 // Goodbye!
9396 synchronized (mPidsSelfLocked) {
9397 mPidsSelfLocked.remove(app.pid);
9398 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9399 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009400 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009401 }
9402 }
9403
9404 // =========================================================
9405 // SERVICES
9406 // =========================================================
9407
9408 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9409 ActivityManager.RunningServiceInfo info =
9410 new ActivityManager.RunningServiceInfo();
9411 info.service = r.name;
9412 if (r.app != null) {
9413 info.pid = r.app.pid;
9414 }
9415 info.process = r.processName;
9416 info.foreground = r.isForeground;
9417 info.activeSince = r.createTime;
9418 info.started = r.startRequested;
9419 info.clientCount = r.connections.size();
9420 info.crashCount = r.crashCount;
9421 info.lastActivityTime = r.lastActivity;
9422 return info;
9423 }
9424
9425 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9426 int flags) {
9427 synchronized (this) {
9428 ArrayList<ActivityManager.RunningServiceInfo> res
9429 = new ArrayList<ActivityManager.RunningServiceInfo>();
9430
9431 if (mServices.size() > 0) {
9432 Iterator<ServiceRecord> it = mServices.values().iterator();
9433 while (it.hasNext() && res.size() < maxNum) {
9434 res.add(makeRunningServiceInfoLocked(it.next()));
9435 }
9436 }
9437
9438 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9439 ServiceRecord r = mRestartingServices.get(i);
9440 ActivityManager.RunningServiceInfo info =
9441 makeRunningServiceInfoLocked(r);
9442 info.restarting = r.nextRestartTime;
9443 res.add(info);
9444 }
9445
9446 return res;
9447 }
9448 }
9449
9450 private final ServiceRecord findServiceLocked(ComponentName name,
9451 IBinder token) {
9452 ServiceRecord r = mServices.get(name);
9453 return r == token ? r : null;
9454 }
9455
9456 private final class ServiceLookupResult {
9457 final ServiceRecord record;
9458 final String permission;
9459
9460 ServiceLookupResult(ServiceRecord _record, String _permission) {
9461 record = _record;
9462 permission = _permission;
9463 }
9464 };
9465
9466 private ServiceLookupResult findServiceLocked(Intent service,
9467 String resolvedType) {
9468 ServiceRecord r = null;
9469 if (service.getComponent() != null) {
9470 r = mServices.get(service.getComponent());
9471 }
9472 if (r == null) {
9473 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9474 r = mServicesByIntent.get(filter);
9475 }
9476
9477 if (r == null) {
9478 try {
9479 ResolveInfo rInfo =
9480 ActivityThread.getPackageManager().resolveService(
9481 service, resolvedType, 0);
9482 ServiceInfo sInfo =
9483 rInfo != null ? rInfo.serviceInfo : null;
9484 if (sInfo == null) {
9485 return null;
9486 }
9487
9488 ComponentName name = new ComponentName(
9489 sInfo.applicationInfo.packageName, sInfo.name);
9490 r = mServices.get(name);
9491 } catch (RemoteException ex) {
9492 // pm is in same process, this will never happen.
9493 }
9494 }
9495 if (r != null) {
9496 int callingPid = Binder.getCallingPid();
9497 int callingUid = Binder.getCallingUid();
9498 if (checkComponentPermission(r.permission,
9499 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9500 != PackageManager.PERMISSION_GRANTED) {
9501 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9502 + " from pid=" + callingPid
9503 + ", uid=" + callingUid
9504 + " requires " + r.permission);
9505 return new ServiceLookupResult(null, r.permission);
9506 }
9507 return new ServiceLookupResult(r, null);
9508 }
9509 return null;
9510 }
9511
9512 private class ServiceRestarter implements Runnable {
9513 private ServiceRecord mService;
9514
9515 void setService(ServiceRecord service) {
9516 mService = service;
9517 }
9518
9519 public void run() {
9520 synchronized(ActivityManagerService.this) {
9521 performServiceRestartLocked(mService);
9522 }
9523 }
9524 }
9525
9526 private ServiceLookupResult retrieveServiceLocked(Intent service,
9527 String resolvedType, int callingPid, int callingUid) {
9528 ServiceRecord r = null;
9529 if (service.getComponent() != null) {
9530 r = mServices.get(service.getComponent());
9531 }
9532 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9533 r = mServicesByIntent.get(filter);
9534 if (r == null) {
9535 try {
9536 ResolveInfo rInfo =
9537 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009538 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009539 ServiceInfo sInfo =
9540 rInfo != null ? rInfo.serviceInfo : null;
9541 if (sInfo == null) {
9542 Log.w(TAG, "Unable to start service " + service +
9543 ": not found");
9544 return null;
9545 }
9546
9547 ComponentName name = new ComponentName(
9548 sInfo.applicationInfo.packageName, sInfo.name);
9549 r = mServices.get(name);
9550 if (r == null) {
9551 filter = new Intent.FilterComparison(service.cloneFilter());
9552 ServiceRestarter res = new ServiceRestarter();
9553 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9554 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9555 synchronized (stats) {
9556 ss = stats.getServiceStatsLocked(
9557 sInfo.applicationInfo.uid, sInfo.packageName,
9558 sInfo.name);
9559 }
9560 r = new ServiceRecord(ss, name, filter, sInfo, res);
9561 res.setService(r);
9562 mServices.put(name, r);
9563 mServicesByIntent.put(filter, r);
9564
9565 // Make sure this component isn't in the pending list.
9566 int N = mPendingServices.size();
9567 for (int i=0; i<N; i++) {
9568 ServiceRecord pr = mPendingServices.get(i);
9569 if (pr.name.equals(name)) {
9570 mPendingServices.remove(i);
9571 i--;
9572 N--;
9573 }
9574 }
9575 }
9576 } catch (RemoteException ex) {
9577 // pm is in same process, this will never happen.
9578 }
9579 }
9580 if (r != null) {
9581 if (checkComponentPermission(r.permission,
9582 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9583 != PackageManager.PERMISSION_GRANTED) {
9584 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9585 + " from pid=" + Binder.getCallingPid()
9586 + ", uid=" + Binder.getCallingUid()
9587 + " requires " + r.permission);
9588 return new ServiceLookupResult(null, r.permission);
9589 }
9590 return new ServiceLookupResult(r, null);
9591 }
9592 return null;
9593 }
9594
9595 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9596 long now = SystemClock.uptimeMillis();
9597 if (r.executeNesting == 0 && r.app != null) {
9598 if (r.app.executingServices.size() == 0) {
9599 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9600 msg.obj = r.app;
9601 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9602 }
9603 r.app.executingServices.add(r);
9604 }
9605 r.executeNesting++;
9606 r.executingStart = now;
9607 }
9608
9609 private final void sendServiceArgsLocked(ServiceRecord r,
9610 boolean oomAdjusted) {
9611 final int N = r.startArgs.size();
9612 if (N == 0) {
9613 return;
9614 }
9615
9616 final int BASEID = r.lastStartId - N + 1;
9617 int i = 0;
9618 while (i < N) {
9619 try {
9620 Intent args = r.startArgs.get(i);
9621 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9622 + r.name + " " + r.intent + " args=" + args);
9623 bumpServiceExecutingLocked(r);
9624 if (!oomAdjusted) {
9625 oomAdjusted = true;
9626 updateOomAdjLocked(r.app);
9627 }
9628 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9629 i++;
9630 } catch (Exception e) {
9631 break;
9632 }
9633 }
9634 if (i == N) {
9635 r.startArgs.clear();
9636 } else {
9637 while (i > 0) {
9638 r.startArgs.remove(0);
9639 i--;
9640 }
9641 }
9642 }
9643
9644 private final boolean requestServiceBindingLocked(ServiceRecord r,
9645 IntentBindRecord i, boolean rebind) {
9646 if (r.app == null || r.app.thread == null) {
9647 // If service is not currently running, can't yet bind.
9648 return false;
9649 }
9650 if ((!i.requested || rebind) && i.apps.size() > 0) {
9651 try {
9652 bumpServiceExecutingLocked(r);
9653 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9654 + ": shouldUnbind=" + i.hasBound);
9655 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9656 if (!rebind) {
9657 i.requested = true;
9658 }
9659 i.hasBound = true;
9660 i.doRebind = false;
9661 } catch (RemoteException e) {
9662 return false;
9663 }
9664 }
9665 return true;
9666 }
9667
9668 private final void requestServiceBindingsLocked(ServiceRecord r) {
9669 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9670 while (bindings.hasNext()) {
9671 IntentBindRecord i = bindings.next();
9672 if (!requestServiceBindingLocked(r, i, false)) {
9673 break;
9674 }
9675 }
9676 }
9677
9678 private final void realStartServiceLocked(ServiceRecord r,
9679 ProcessRecord app) throws RemoteException {
9680 if (app.thread == null) {
9681 throw new RemoteException();
9682 }
9683
9684 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009685 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009686
9687 app.services.add(r);
9688 bumpServiceExecutingLocked(r);
9689 updateLRUListLocked(app, true);
9690
9691 boolean created = false;
9692 try {
9693 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9694 + r.name + " " + r.intent);
9695 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9696 System.identityHashCode(r), r.shortName,
9697 r.intent.getIntent().toString(), r.app.pid);
9698 synchronized (r.stats.getBatteryStats()) {
9699 r.stats.startLaunchedLocked();
9700 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009701 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009702 app.thread.scheduleCreateService(r, r.serviceInfo);
9703 created = true;
9704 } finally {
9705 if (!created) {
9706 app.services.remove(r);
9707 scheduleServiceRestartLocked(r);
9708 }
9709 }
9710
9711 requestServiceBindingsLocked(r);
9712 sendServiceArgsLocked(r, true);
9713 }
9714
9715 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9716 r.totalRestartCount++;
9717 if (r.restartDelay == 0) {
9718 r.restartCount++;
9719 r.restartDelay = SERVICE_RESTART_DURATION;
9720 } else {
9721 // If it has been a "reasonably long time" since the service
9722 // was started, then reset our restart duration back to
9723 // the beginning, so we don't infinitely increase the duration
9724 // on a service that just occasionally gets killed (which is
9725 // a normal case, due to process being killed to reclaim memory).
9726 long now = SystemClock.uptimeMillis();
9727 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9728 r.restartCount = 1;
9729 r.restartDelay = SERVICE_RESTART_DURATION;
9730 } else {
9731 r.restartDelay *= 2;
9732 }
9733 }
9734 if (!mRestartingServices.contains(r)) {
9735 mRestartingServices.add(r);
9736 }
9737 mHandler.removeCallbacks(r.restarter);
9738 mHandler.postDelayed(r.restarter, r.restartDelay);
9739 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9740 Log.w(TAG, "Scheduling restart of crashed service "
9741 + r.shortName + " in " + r.restartDelay + "ms");
9742 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9743 r.shortName, r.restartDelay);
9744
9745 Message msg = Message.obtain();
9746 msg.what = SERVICE_ERROR_MSG;
9747 msg.obj = r;
9748 mHandler.sendMessage(msg);
9749 }
9750
9751 final void performServiceRestartLocked(ServiceRecord r) {
9752 if (!mRestartingServices.contains(r)) {
9753 return;
9754 }
9755 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9756 }
9757
9758 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9759 if (r.restartDelay == 0) {
9760 return false;
9761 }
9762 r.resetRestartCounter();
9763 mRestartingServices.remove(r);
9764 mHandler.removeCallbacks(r.restarter);
9765 return true;
9766 }
9767
9768 private final boolean bringUpServiceLocked(ServiceRecord r,
9769 int intentFlags, boolean whileRestarting) {
9770 //Log.i(TAG, "Bring up service:");
9771 //r.dump(" ");
9772
9773 if (r.app != null) {
9774 sendServiceArgsLocked(r, false);
9775 return true;
9776 }
9777
9778 if (!whileRestarting && r.restartDelay > 0) {
9779 // If waiting for a restart, then do nothing.
9780 return true;
9781 }
9782
9783 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9784 + " " + r.intent);
9785
9786 final String appName = r.processName;
9787 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9788 if (app != null && app.thread != null) {
9789 try {
9790 realStartServiceLocked(r, app);
9791 return true;
9792 } catch (RemoteException e) {
9793 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9794 }
9795
9796 // If a dead object exception was thrown -- fall through to
9797 // restart the application.
9798 }
9799
9800 if (!mPendingServices.contains(r)) {
9801 // Not running -- get it started, and enqueue this service record
9802 // to be executed when the app comes up.
9803 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9804 "service", r.name) == null) {
9805 Log.w(TAG, "Unable to launch app "
9806 + r.appInfo.packageName + "/"
9807 + r.appInfo.uid + " for service "
9808 + r.intent.getIntent() + ": process is bad");
9809 bringDownServiceLocked(r, true);
9810 return false;
9811 }
9812 mPendingServices.add(r);
9813 }
9814 return true;
9815 }
9816
9817 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9818 //Log.i(TAG, "Bring down service:");
9819 //r.dump(" ");
9820
9821 // Does it still need to run?
9822 if (!force && r.startRequested) {
9823 return;
9824 }
9825 if (r.connections.size() > 0) {
9826 if (!force) {
9827 // XXX should probably keep a count of the number of auto-create
9828 // connections directly in the service.
9829 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9830 while (it.hasNext()) {
9831 ConnectionRecord cr = it.next();
9832 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9833 return;
9834 }
9835 }
9836 }
9837
9838 // Report to all of the connections that the service is no longer
9839 // available.
9840 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9841 while (it.hasNext()) {
9842 ConnectionRecord c = it.next();
9843 try {
9844 // todo: shouldn't be a synchronous call!
9845 c.conn.connected(r.name, null);
9846 } catch (Exception e) {
9847 Log.w(TAG, "Failure disconnecting service " + r.name +
9848 " to connection " + c.conn.asBinder() +
9849 " (in " + c.binding.client.processName + ")", e);
9850 }
9851 }
9852 }
9853
9854 // Tell the service that it has been unbound.
9855 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9856 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9857 while (it.hasNext()) {
9858 IntentBindRecord ibr = it.next();
9859 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9860 + ": hasBound=" + ibr.hasBound);
9861 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9862 try {
9863 bumpServiceExecutingLocked(r);
9864 updateOomAdjLocked(r.app);
9865 ibr.hasBound = false;
9866 r.app.thread.scheduleUnbindService(r,
9867 ibr.intent.getIntent());
9868 } catch (Exception e) {
9869 Log.w(TAG, "Exception when unbinding service "
9870 + r.shortName, e);
9871 serviceDoneExecutingLocked(r, true);
9872 }
9873 }
9874 }
9875 }
9876
9877 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9878 + " " + r.intent);
9879 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9880 System.identityHashCode(r), r.shortName,
9881 (r.app != null) ? r.app.pid : -1);
9882
9883 mServices.remove(r.name);
9884 mServicesByIntent.remove(r.intent);
9885 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9886 r.totalRestartCount = 0;
9887 unscheduleServiceRestartLocked(r);
9888
9889 // Also make sure it is not on the pending list.
9890 int N = mPendingServices.size();
9891 for (int i=0; i<N; i++) {
9892 if (mPendingServices.get(i) == r) {
9893 mPendingServices.remove(i);
9894 if (DEBUG_SERVICE) Log.v(
9895 TAG, "Removed pending service: " + r.shortName);
9896 i--;
9897 N--;
9898 }
9899 }
9900
9901 if (r.app != null) {
9902 synchronized (r.stats.getBatteryStats()) {
9903 r.stats.stopLaunchedLocked();
9904 }
9905 r.app.services.remove(r);
9906 if (r.app.thread != null) {
9907 updateServiceForegroundLocked(r.app, false);
9908 try {
9909 Log.i(TAG, "Stopping service: " + r.shortName);
9910 bumpServiceExecutingLocked(r);
9911 mStoppingServices.add(r);
9912 updateOomAdjLocked(r.app);
9913 r.app.thread.scheduleStopService(r);
9914 } catch (Exception e) {
9915 Log.w(TAG, "Exception when stopping service "
9916 + r.shortName, e);
9917 serviceDoneExecutingLocked(r, true);
9918 }
9919 } else {
9920 if (DEBUG_SERVICE) Log.v(
9921 TAG, "Removed service that has no process: " + r.shortName);
9922 }
9923 } else {
9924 if (DEBUG_SERVICE) Log.v(
9925 TAG, "Removed service that is not running: " + r.shortName);
9926 }
9927 }
9928
9929 ComponentName startServiceLocked(IApplicationThread caller,
9930 Intent service, String resolvedType,
9931 int callingPid, int callingUid) {
9932 synchronized(this) {
9933 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9934 + " type=" + resolvedType + " args=" + service.getExtras());
9935
9936 if (caller != null) {
9937 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9938 if (callerApp == null) {
9939 throw new SecurityException(
9940 "Unable to find app for caller " + caller
9941 + " (pid=" + Binder.getCallingPid()
9942 + ") when starting service " + service);
9943 }
9944 }
9945
9946 ServiceLookupResult res =
9947 retrieveServiceLocked(service, resolvedType,
9948 callingPid, callingUid);
9949 if (res == null) {
9950 return null;
9951 }
9952 if (res.record == null) {
9953 return new ComponentName("!", res.permission != null
9954 ? res.permission : "private to package");
9955 }
9956 ServiceRecord r = res.record;
9957 if (unscheduleServiceRestartLocked(r)) {
9958 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9959 + r.shortName);
9960 }
9961 r.startRequested = true;
9962 r.startArgs.add(service);
9963 r.lastStartId++;
9964 if (r.lastStartId < 1) {
9965 r.lastStartId = 1;
9966 }
9967 r.lastActivity = SystemClock.uptimeMillis();
9968 synchronized (r.stats.getBatteryStats()) {
9969 r.stats.startRunningLocked();
9970 }
9971 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9972 return new ComponentName("!", "Service process is bad");
9973 }
9974 return r.name;
9975 }
9976 }
9977
9978 public ComponentName startService(IApplicationThread caller, Intent service,
9979 String resolvedType) {
9980 // Refuse possible leaked file descriptors
9981 if (service != null && service.hasFileDescriptors() == true) {
9982 throw new IllegalArgumentException("File descriptors passed in Intent");
9983 }
9984
9985 synchronized(this) {
9986 final int callingPid = Binder.getCallingPid();
9987 final int callingUid = Binder.getCallingUid();
9988 final long origId = Binder.clearCallingIdentity();
9989 ComponentName res = startServiceLocked(caller, service,
9990 resolvedType, callingPid, callingUid);
9991 Binder.restoreCallingIdentity(origId);
9992 return res;
9993 }
9994 }
9995
9996 ComponentName startServiceInPackage(int uid,
9997 Intent service, String resolvedType) {
9998 synchronized(this) {
9999 final long origId = Binder.clearCallingIdentity();
10000 ComponentName res = startServiceLocked(null, service,
10001 resolvedType, -1, uid);
10002 Binder.restoreCallingIdentity(origId);
10003 return res;
10004 }
10005 }
10006
10007 public int stopService(IApplicationThread caller, Intent service,
10008 String resolvedType) {
10009 // Refuse possible leaked file descriptors
10010 if (service != null && service.hasFileDescriptors() == true) {
10011 throw new IllegalArgumentException("File descriptors passed in Intent");
10012 }
10013
10014 synchronized(this) {
10015 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10016 + " type=" + resolvedType);
10017
10018 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10019 if (caller != null && callerApp == null) {
10020 throw new SecurityException(
10021 "Unable to find app for caller " + caller
10022 + " (pid=" + Binder.getCallingPid()
10023 + ") when stopping service " + service);
10024 }
10025
10026 // If this service is active, make sure it is stopped.
10027 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10028 if (r != null) {
10029 if (r.record != null) {
10030 synchronized (r.record.stats.getBatteryStats()) {
10031 r.record.stats.stopRunningLocked();
10032 }
10033 r.record.startRequested = false;
10034 final long origId = Binder.clearCallingIdentity();
10035 bringDownServiceLocked(r.record, false);
10036 Binder.restoreCallingIdentity(origId);
10037 return 1;
10038 }
10039 return -1;
10040 }
10041 }
10042
10043 return 0;
10044 }
10045
10046 public IBinder peekService(Intent service, 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 IBinder ret = null;
10053
10054 synchronized(this) {
10055 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10056
10057 if (r != null) {
10058 // r.record is null if findServiceLocked() failed the caller permission check
10059 if (r.record == null) {
10060 throw new SecurityException(
10061 "Permission Denial: Accessing service " + r.record.name
10062 + " from pid=" + Binder.getCallingPid()
10063 + ", uid=" + Binder.getCallingUid()
10064 + " requires " + r.permission);
10065 }
10066 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10067 if (ib != null) {
10068 ret = ib.binder;
10069 }
10070 }
10071 }
10072
10073 return ret;
10074 }
10075
10076 public boolean stopServiceToken(ComponentName className, IBinder token,
10077 int startId) {
10078 synchronized(this) {
10079 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10080 + " " + token + " startId=" + startId);
10081 ServiceRecord r = findServiceLocked(className, token);
10082 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10083 synchronized (r.stats.getBatteryStats()) {
10084 r.stats.stopRunningLocked();
10085 r.startRequested = false;
10086 }
10087 final long origId = Binder.clearCallingIdentity();
10088 bringDownServiceLocked(r, false);
10089 Binder.restoreCallingIdentity(origId);
10090 return true;
10091 }
10092 }
10093 return false;
10094 }
10095
10096 public void setServiceForeground(ComponentName className, IBinder token,
10097 boolean isForeground) {
10098 synchronized(this) {
10099 ServiceRecord r = findServiceLocked(className, token);
10100 if (r != null) {
10101 if (r.isForeground != isForeground) {
10102 final long origId = Binder.clearCallingIdentity();
10103 r.isForeground = isForeground;
10104 if (r.app != null) {
10105 updateServiceForegroundLocked(r.app, true);
10106 }
10107 Binder.restoreCallingIdentity(origId);
10108 }
10109 }
10110 }
10111 }
10112
10113 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10114 boolean anyForeground = false;
10115 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10116 if (sr.isForeground) {
10117 anyForeground = true;
10118 break;
10119 }
10120 }
10121 if (anyForeground != proc.foregroundServices) {
10122 proc.foregroundServices = anyForeground;
10123 if (oomAdj) {
10124 updateOomAdjLocked();
10125 }
10126 }
10127 }
10128
10129 public int bindService(IApplicationThread caller, IBinder token,
10130 Intent service, String resolvedType,
10131 IServiceConnection connection, int flags) {
10132 // Refuse possible leaked file descriptors
10133 if (service != null && service.hasFileDescriptors() == true) {
10134 throw new IllegalArgumentException("File descriptors passed in Intent");
10135 }
10136
10137 synchronized(this) {
10138 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10139 + " type=" + resolvedType + " conn=" + connection.asBinder()
10140 + " flags=0x" + Integer.toHexString(flags));
10141 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10142 if (callerApp == null) {
10143 throw new SecurityException(
10144 "Unable to find app for caller " + caller
10145 + " (pid=" + Binder.getCallingPid()
10146 + ") when binding service " + service);
10147 }
10148
10149 HistoryRecord activity = null;
10150 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010151 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010152 if (aindex < 0) {
10153 Log.w(TAG, "Binding with unknown activity: " + token);
10154 return 0;
10155 }
10156 activity = (HistoryRecord)mHistory.get(aindex);
10157 }
10158
10159 ServiceLookupResult res =
10160 retrieveServiceLocked(service, resolvedType,
10161 Binder.getCallingPid(), Binder.getCallingUid());
10162 if (res == null) {
10163 return 0;
10164 }
10165 if (res.record == null) {
10166 return -1;
10167 }
10168 ServiceRecord s = res.record;
10169
10170 final long origId = Binder.clearCallingIdentity();
10171
10172 if (unscheduleServiceRestartLocked(s)) {
10173 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10174 + s.shortName);
10175 }
10176
10177 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10178 ConnectionRecord c = new ConnectionRecord(b, activity,
10179 connection, flags);
10180
10181 IBinder binder = connection.asBinder();
10182 s.connections.put(binder, c);
10183 b.connections.add(c);
10184 if (activity != null) {
10185 if (activity.connections == null) {
10186 activity.connections = new HashSet<ConnectionRecord>();
10187 }
10188 activity.connections.add(c);
10189 }
10190 b.client.connections.add(c);
10191 mServiceConnections.put(binder, c);
10192
10193 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10194 s.lastActivity = SystemClock.uptimeMillis();
10195 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10196 return 0;
10197 }
10198 }
10199
10200 if (s.app != null) {
10201 // This could have made the service more important.
10202 updateOomAdjLocked(s.app);
10203 }
10204
10205 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10206 + ": received=" + b.intent.received
10207 + " apps=" + b.intent.apps.size()
10208 + " doRebind=" + b.intent.doRebind);
10209
10210 if (s.app != null && b.intent.received) {
10211 // Service is already running, so we can immediately
10212 // publish the connection.
10213 try {
10214 c.conn.connected(s.name, b.intent.binder);
10215 } catch (Exception e) {
10216 Log.w(TAG, "Failure sending service " + s.shortName
10217 + " to connection " + c.conn.asBinder()
10218 + " (in " + c.binding.client.processName + ")", e);
10219 }
10220
10221 // If this is the first app connected back to this binding,
10222 // and the service had previously asked to be told when
10223 // rebound, then do so.
10224 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10225 requestServiceBindingLocked(s, b.intent, true);
10226 }
10227 } else if (!b.intent.requested) {
10228 requestServiceBindingLocked(s, b.intent, false);
10229 }
10230
10231 Binder.restoreCallingIdentity(origId);
10232 }
10233
10234 return 1;
10235 }
10236
10237 private void removeConnectionLocked(
10238 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10239 IBinder binder = c.conn.asBinder();
10240 AppBindRecord b = c.binding;
10241 ServiceRecord s = b.service;
10242 s.connections.remove(binder);
10243 b.connections.remove(c);
10244 if (c.activity != null && c.activity != skipAct) {
10245 if (c.activity.connections != null) {
10246 c.activity.connections.remove(c);
10247 }
10248 }
10249 if (b.client != skipApp) {
10250 b.client.connections.remove(c);
10251 }
10252 mServiceConnections.remove(binder);
10253
10254 if (b.connections.size() == 0) {
10255 b.intent.apps.remove(b.client);
10256 }
10257
10258 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10259 + ": shouldUnbind=" + b.intent.hasBound);
10260 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10261 && b.intent.hasBound) {
10262 try {
10263 bumpServiceExecutingLocked(s);
10264 updateOomAdjLocked(s.app);
10265 b.intent.hasBound = false;
10266 // Assume the client doesn't want to know about a rebind;
10267 // we will deal with that later if it asks for one.
10268 b.intent.doRebind = false;
10269 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10270 } catch (Exception e) {
10271 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10272 serviceDoneExecutingLocked(s, true);
10273 }
10274 }
10275
10276 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10277 bringDownServiceLocked(s, false);
10278 }
10279 }
10280
10281 public boolean unbindService(IServiceConnection connection) {
10282 synchronized (this) {
10283 IBinder binder = connection.asBinder();
10284 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10285 ConnectionRecord r = mServiceConnections.get(binder);
10286 if (r == null) {
10287 Log.w(TAG, "Unbind failed: could not find connection for "
10288 + connection.asBinder());
10289 return false;
10290 }
10291
10292 final long origId = Binder.clearCallingIdentity();
10293
10294 removeConnectionLocked(r, null, null);
10295
10296 if (r.binding.service.app != null) {
10297 // This could have made the service less important.
10298 updateOomAdjLocked(r.binding.service.app);
10299 }
10300
10301 Binder.restoreCallingIdentity(origId);
10302 }
10303
10304 return true;
10305 }
10306
10307 public void publishService(IBinder token, Intent intent, IBinder service) {
10308 // Refuse possible leaked file descriptors
10309 if (intent != null && intent.hasFileDescriptors() == true) {
10310 throw new IllegalArgumentException("File descriptors passed in Intent");
10311 }
10312
10313 synchronized(this) {
10314 if (!(token instanceof ServiceRecord)) {
10315 throw new IllegalArgumentException("Invalid service token");
10316 }
10317 ServiceRecord r = (ServiceRecord)token;
10318
10319 final long origId = Binder.clearCallingIdentity();
10320
10321 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10322 + " " + intent + ": " + service);
10323 if (r != null) {
10324 Intent.FilterComparison filter
10325 = new Intent.FilterComparison(intent);
10326 IntentBindRecord b = r.bindings.get(filter);
10327 if (b != null && !b.received) {
10328 b.binder = service;
10329 b.requested = true;
10330 b.received = true;
10331 if (r.connections.size() > 0) {
10332 Iterator<ConnectionRecord> it
10333 = r.connections.values().iterator();
10334 while (it.hasNext()) {
10335 ConnectionRecord c = it.next();
10336 if (!filter.equals(c.binding.intent.intent)) {
10337 if (DEBUG_SERVICE) Log.v(
10338 TAG, "Not publishing to: " + c);
10339 if (DEBUG_SERVICE) Log.v(
10340 TAG, "Bound intent: " + c.binding.intent.intent);
10341 if (DEBUG_SERVICE) Log.v(
10342 TAG, "Published intent: " + intent);
10343 continue;
10344 }
10345 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10346 try {
10347 c.conn.connected(r.name, service);
10348 } catch (Exception e) {
10349 Log.w(TAG, "Failure sending service " + r.name +
10350 " to connection " + c.conn.asBinder() +
10351 " (in " + c.binding.client.processName + ")", e);
10352 }
10353 }
10354 }
10355 }
10356
10357 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10358
10359 Binder.restoreCallingIdentity(origId);
10360 }
10361 }
10362 }
10363
10364 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10365 // Refuse possible leaked file descriptors
10366 if (intent != null && intent.hasFileDescriptors() == true) {
10367 throw new IllegalArgumentException("File descriptors passed in Intent");
10368 }
10369
10370 synchronized(this) {
10371 if (!(token instanceof ServiceRecord)) {
10372 throw new IllegalArgumentException("Invalid service token");
10373 }
10374 ServiceRecord r = (ServiceRecord)token;
10375
10376 final long origId = Binder.clearCallingIdentity();
10377
10378 if (r != null) {
10379 Intent.FilterComparison filter
10380 = new Intent.FilterComparison(intent);
10381 IntentBindRecord b = r.bindings.get(filter);
10382 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10383 + " at " + b + ": apps="
10384 + (b != null ? b.apps.size() : 0));
10385 if (b != null) {
10386 if (b.apps.size() > 0) {
10387 // Applications have already bound since the last
10388 // unbind, so just rebind right here.
10389 requestServiceBindingLocked(r, b, true);
10390 } else {
10391 // Note to tell the service the next time there is
10392 // a new client.
10393 b.doRebind = true;
10394 }
10395 }
10396
10397 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10398
10399 Binder.restoreCallingIdentity(origId);
10400 }
10401 }
10402 }
10403
10404 public void serviceDoneExecuting(IBinder token) {
10405 synchronized(this) {
10406 if (!(token instanceof ServiceRecord)) {
10407 throw new IllegalArgumentException("Invalid service token");
10408 }
10409 ServiceRecord r = (ServiceRecord)token;
10410 boolean inStopping = mStoppingServices.contains(token);
10411 if (r != null) {
10412 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10413 + ": nesting=" + r.executeNesting
10414 + ", inStopping=" + inStopping);
10415 if (r != token) {
10416 Log.w(TAG, "Done executing service " + r.name
10417 + " with incorrect token: given " + token
10418 + ", expected " + r);
10419 return;
10420 }
10421
10422 final long origId = Binder.clearCallingIdentity();
10423 serviceDoneExecutingLocked(r, inStopping);
10424 Binder.restoreCallingIdentity(origId);
10425 } else {
10426 Log.w(TAG, "Done executing unknown service " + r.name
10427 + " with token " + token);
10428 }
10429 }
10430 }
10431
10432 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10433 r.executeNesting--;
10434 if (r.executeNesting <= 0 && r.app != null) {
10435 r.app.executingServices.remove(r);
10436 if (r.app.executingServices.size() == 0) {
10437 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10438 }
10439 if (inStopping) {
10440 mStoppingServices.remove(r);
10441 }
10442 updateOomAdjLocked(r.app);
10443 }
10444 }
10445
10446 void serviceTimeout(ProcessRecord proc) {
10447 synchronized(this) {
10448 if (proc.executingServices.size() == 0 || proc.thread == null) {
10449 return;
10450 }
10451 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10452 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10453 ServiceRecord timeout = null;
10454 long nextTime = 0;
10455 while (it.hasNext()) {
10456 ServiceRecord sr = it.next();
10457 if (sr.executingStart < maxTime) {
10458 timeout = sr;
10459 break;
10460 }
10461 if (sr.executingStart > nextTime) {
10462 nextTime = sr.executingStart;
10463 }
10464 }
10465 if (timeout != null && mLRUProcesses.contains(proc)) {
10466 Log.w(TAG, "Timeout executing service: " + timeout);
10467 appNotRespondingLocked(proc, null, "Executing service "
10468 + timeout.name);
10469 } else {
10470 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10471 msg.obj = proc;
10472 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10473 }
10474 }
10475 }
10476
10477 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010478 // BACKUP AND RESTORE
10479 // =========================================================
10480
10481 // Cause the target app to be launched if necessary and its backup agent
10482 // instantiated. The backup agent will invoke backupAgentCreated() on the
10483 // activity manager to announce its creation.
10484 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10485 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10486 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10487
10488 synchronized(this) {
10489 // !!! TODO: currently no check here that we're already bound
10490 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10491 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10492 synchronized (stats) {
10493 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10494 }
10495
10496 BackupRecord r = new BackupRecord(ss, app, backupMode);
10497 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10498 // startProcessLocked() returns existing proc's record if it's already running
10499 ProcessRecord proc = startProcessLocked(app.processName, app,
10500 false, 0, "backup", hostingName);
10501 if (proc == null) {
10502 Log.e(TAG, "Unable to start backup agent process " + r);
10503 return false;
10504 }
10505
10506 r.app = proc;
10507 mBackupTarget = r;
10508 mBackupAppName = app.packageName;
10509
Christopher Tate6fa95972009-06-05 18:43:55 -070010510 // Try not to kill the process during backup
10511 updateOomAdjLocked(proc);
10512
Christopher Tate181fafa2009-05-14 11:12:14 -070010513 // If the process is already attached, schedule the creation of the backup agent now.
10514 // If it is not yet live, this will be done when it attaches to the framework.
10515 if (proc.thread != null) {
10516 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10517 try {
10518 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10519 } catch (RemoteException e) {
10520 // !!! TODO: notify the backup manager that we crashed, or rely on
10521 // death notices, or...?
10522 }
10523 } else {
10524 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10525 }
10526 // Invariants: at this point, the target app process exists and the application
10527 // is either already running or in the process of coming up. mBackupTarget and
10528 // mBackupAppName describe the app, so that when it binds back to the AM we
10529 // know that it's scheduled for a backup-agent operation.
10530 }
10531
10532 return true;
10533 }
10534
10535 // A backup agent has just come up
10536 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10537 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10538 + " = " + agent);
10539
10540 synchronized(this) {
10541 if (!agentPackageName.equals(mBackupAppName)) {
10542 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10543 return;
10544 }
10545
Christopher Tate043dadc2009-06-02 16:11:00 -070010546 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010547 try {
10548 IBackupManager bm = IBackupManager.Stub.asInterface(
10549 ServiceManager.getService(Context.BACKUP_SERVICE));
10550 bm.agentConnected(agentPackageName, agent);
10551 } catch (RemoteException e) {
10552 // can't happen; the backup manager service is local
10553 } catch (Exception e) {
10554 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10555 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010556 } finally {
10557 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010558 }
10559 }
10560 }
10561
10562 // done with this agent
10563 public void unbindBackupAgent(ApplicationInfo appInfo) {
10564 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010565 if (appInfo == null) {
10566 Log.w(TAG, "unbind backup agent for null app");
10567 return;
10568 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010569
10570 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010571 if (mBackupAppName == null) {
10572 Log.w(TAG, "Unbinding backup agent with no active backup");
10573 return;
10574 }
10575
Christopher Tate181fafa2009-05-14 11:12:14 -070010576 if (!mBackupAppName.equals(appInfo.packageName)) {
10577 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10578 return;
10579 }
10580
Christopher Tate6fa95972009-06-05 18:43:55 -070010581 ProcessRecord proc = mBackupTarget.app;
10582 mBackupTarget = null;
10583 mBackupAppName = null;
10584
10585 // Not backing this app up any more; reset its OOM adjustment
10586 updateOomAdjLocked(proc);
10587
Christopher Tatec7b31e32009-06-10 15:49:30 -070010588 // If the app crashed during backup, 'thread' will be null here
10589 if (proc.thread != null) {
10590 try {
10591 proc.thread.scheduleDestroyBackupAgent(appInfo);
10592 } catch (Exception e) {
10593 Log.e(TAG, "Exception when unbinding backup agent:");
10594 e.printStackTrace();
10595 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010596 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010597 }
10598 }
10599 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010600 // BROADCASTS
10601 // =========================================================
10602
10603 private final List getStickies(String action, IntentFilter filter,
10604 List cur) {
10605 final ContentResolver resolver = mContext.getContentResolver();
10606 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10607 if (list == null) {
10608 return cur;
10609 }
10610 int N = list.size();
10611 for (int i=0; i<N; i++) {
10612 Intent intent = list.get(i);
10613 if (filter.match(resolver, intent, true, TAG) >= 0) {
10614 if (cur == null) {
10615 cur = new ArrayList<Intent>();
10616 }
10617 cur.add(intent);
10618 }
10619 }
10620 return cur;
10621 }
10622
10623 private final void scheduleBroadcastsLocked() {
10624 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10625 + mBroadcastsScheduled);
10626
10627 if (mBroadcastsScheduled) {
10628 return;
10629 }
10630 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10631 mBroadcastsScheduled = true;
10632 }
10633
10634 public Intent registerReceiver(IApplicationThread caller,
10635 IIntentReceiver receiver, IntentFilter filter, String permission) {
10636 synchronized(this) {
10637 ProcessRecord callerApp = null;
10638 if (caller != null) {
10639 callerApp = getRecordForAppLocked(caller);
10640 if (callerApp == null) {
10641 throw new SecurityException(
10642 "Unable to find app for caller " + caller
10643 + " (pid=" + Binder.getCallingPid()
10644 + ") when registering receiver " + receiver);
10645 }
10646 }
10647
10648 List allSticky = null;
10649
10650 // Look for any matching sticky broadcasts...
10651 Iterator actions = filter.actionsIterator();
10652 if (actions != null) {
10653 while (actions.hasNext()) {
10654 String action = (String)actions.next();
10655 allSticky = getStickies(action, filter, allSticky);
10656 }
10657 } else {
10658 allSticky = getStickies(null, filter, allSticky);
10659 }
10660
10661 // The first sticky in the list is returned directly back to
10662 // the client.
10663 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10664
10665 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10666 + ": " + sticky);
10667
10668 if (receiver == null) {
10669 return sticky;
10670 }
10671
10672 ReceiverList rl
10673 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10674 if (rl == null) {
10675 rl = new ReceiverList(this, callerApp,
10676 Binder.getCallingPid(),
10677 Binder.getCallingUid(), receiver);
10678 if (rl.app != null) {
10679 rl.app.receivers.add(rl);
10680 } else {
10681 try {
10682 receiver.asBinder().linkToDeath(rl, 0);
10683 } catch (RemoteException e) {
10684 return sticky;
10685 }
10686 rl.linkedToDeath = true;
10687 }
10688 mRegisteredReceivers.put(receiver.asBinder(), rl);
10689 }
10690 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10691 rl.add(bf);
10692 if (!bf.debugCheck()) {
10693 Log.w(TAG, "==> For Dynamic broadast");
10694 }
10695 mReceiverResolver.addFilter(bf);
10696
10697 // Enqueue broadcasts for all existing stickies that match
10698 // this filter.
10699 if (allSticky != null) {
10700 ArrayList receivers = new ArrayList();
10701 receivers.add(bf);
10702
10703 int N = allSticky.size();
10704 for (int i=0; i<N; i++) {
10705 Intent intent = (Intent)allSticky.get(i);
10706 BroadcastRecord r = new BroadcastRecord(intent, null,
10707 null, -1, -1, null, receivers, null, 0, null, null,
10708 false);
10709 if (mParallelBroadcasts.size() == 0) {
10710 scheduleBroadcastsLocked();
10711 }
10712 mParallelBroadcasts.add(r);
10713 }
10714 }
10715
10716 return sticky;
10717 }
10718 }
10719
10720 public void unregisterReceiver(IIntentReceiver receiver) {
10721 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10722
10723 boolean doNext = false;
10724
10725 synchronized(this) {
10726 ReceiverList rl
10727 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10728 if (rl != null) {
10729 if (rl.curBroadcast != null) {
10730 BroadcastRecord r = rl.curBroadcast;
10731 doNext = finishReceiverLocked(
10732 receiver.asBinder(), r.resultCode, r.resultData,
10733 r.resultExtras, r.resultAbort, true);
10734 }
10735
10736 if (rl.app != null) {
10737 rl.app.receivers.remove(rl);
10738 }
10739 removeReceiverLocked(rl);
10740 if (rl.linkedToDeath) {
10741 rl.linkedToDeath = false;
10742 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10743 }
10744 }
10745 }
10746
10747 if (!doNext) {
10748 return;
10749 }
10750
10751 final long origId = Binder.clearCallingIdentity();
10752 processNextBroadcast(false);
10753 trimApplications();
10754 Binder.restoreCallingIdentity(origId);
10755 }
10756
10757 void removeReceiverLocked(ReceiverList rl) {
10758 mRegisteredReceivers.remove(rl.receiver.asBinder());
10759 int N = rl.size();
10760 for (int i=0; i<N; i++) {
10761 mReceiverResolver.removeFilter(rl.get(i));
10762 }
10763 }
10764
10765 private final int broadcastIntentLocked(ProcessRecord callerApp,
10766 String callerPackage, Intent intent, String resolvedType,
10767 IIntentReceiver resultTo, int resultCode, String resultData,
10768 Bundle map, String requiredPermission,
10769 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10770 intent = new Intent(intent);
10771
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010772 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010773 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10774 + " ordered=" + ordered);
10775 if ((resultTo != null) && !ordered) {
10776 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10777 }
10778
10779 // Handle special intents: if this broadcast is from the package
10780 // manager about a package being removed, we need to remove all of
10781 // its activities from the history stack.
10782 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10783 intent.getAction());
10784 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10785 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10786 || uidRemoved) {
10787 if (checkComponentPermission(
10788 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10789 callingPid, callingUid, -1)
10790 == PackageManager.PERMISSION_GRANTED) {
10791 if (uidRemoved) {
10792 final Bundle intentExtras = intent.getExtras();
10793 final int uid = intentExtras != null
10794 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10795 if (uid >= 0) {
10796 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10797 synchronized (bs) {
10798 bs.removeUidStatsLocked(uid);
10799 }
10800 }
10801 } else {
10802 Uri data = intent.getData();
10803 String ssp;
10804 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10805 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10806 uninstallPackageLocked(ssp,
10807 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010808 AttributeCache ac = AttributeCache.instance();
10809 if (ac != null) {
10810 ac.removePackage(ssp);
10811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010812 }
10813 }
10814 }
10815 } else {
10816 String msg = "Permission Denial: " + intent.getAction()
10817 + " broadcast from " + callerPackage + " (pid=" + callingPid
10818 + ", uid=" + callingUid + ")"
10819 + " requires "
10820 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10821 Log.w(TAG, msg);
10822 throw new SecurityException(msg);
10823 }
10824 }
10825
10826 /*
10827 * If this is the time zone changed action, queue up a message that will reset the timezone
10828 * of all currently running processes. This message will get queued up before the broadcast
10829 * happens.
10830 */
10831 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10832 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10833 }
10834
10835 // Add to the sticky list if requested.
10836 if (sticky) {
10837 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10838 callingPid, callingUid)
10839 != PackageManager.PERMISSION_GRANTED) {
10840 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10841 + callingPid + ", uid=" + callingUid
10842 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10843 Log.w(TAG, msg);
10844 throw new SecurityException(msg);
10845 }
10846 if (requiredPermission != null) {
10847 Log.w(TAG, "Can't broadcast sticky intent " + intent
10848 + " and enforce permission " + requiredPermission);
10849 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10850 }
10851 if (intent.getComponent() != null) {
10852 throw new SecurityException(
10853 "Sticky broadcasts can't target a specific component");
10854 }
10855 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10856 if (list == null) {
10857 list = new ArrayList<Intent>();
10858 mStickyBroadcasts.put(intent.getAction(), list);
10859 }
10860 int N = list.size();
10861 int i;
10862 for (i=0; i<N; i++) {
10863 if (intent.filterEquals(list.get(i))) {
10864 // This sticky already exists, replace it.
10865 list.set(i, new Intent(intent));
10866 break;
10867 }
10868 }
10869 if (i >= N) {
10870 list.add(new Intent(intent));
10871 }
10872 }
10873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010874 // Figure out who all will receive this broadcast.
10875 List receivers = null;
10876 List<BroadcastFilter> registeredReceivers = null;
10877 try {
10878 if (intent.getComponent() != null) {
10879 // Broadcast is going to one specific receiver class...
10880 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010881 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010882 if (ai != null) {
10883 receivers = new ArrayList();
10884 ResolveInfo ri = new ResolveInfo();
10885 ri.activityInfo = ai;
10886 receivers.add(ri);
10887 }
10888 } else {
10889 // Need to resolve the intent to interested receivers...
10890 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10891 == 0) {
10892 receivers =
10893 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010894 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010895 }
Mihai Preda074edef2009-05-18 17:13:31 +020010896 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010897 }
10898 } catch (RemoteException ex) {
10899 // pm is in same process, this will never happen.
10900 }
10901
10902 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10903 if (!ordered && NR > 0) {
10904 // If we are not serializing this broadcast, then send the
10905 // registered receivers separately so they don't wait for the
10906 // components to be launched.
10907 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10908 callerPackage, callingPid, callingUid, requiredPermission,
10909 registeredReceivers, resultTo, resultCode, resultData, map,
10910 ordered);
10911 if (DEBUG_BROADCAST) Log.v(
10912 TAG, "Enqueueing parallel broadcast " + r
10913 + ": prev had " + mParallelBroadcasts.size());
10914 mParallelBroadcasts.add(r);
10915 scheduleBroadcastsLocked();
10916 registeredReceivers = null;
10917 NR = 0;
10918 }
10919
10920 // Merge into one list.
10921 int ir = 0;
10922 if (receivers != null) {
10923 // A special case for PACKAGE_ADDED: do not allow the package
10924 // being added to see this broadcast. This prevents them from
10925 // using this as a back door to get run as soon as they are
10926 // installed. Maybe in the future we want to have a special install
10927 // broadcast or such for apps, but we'd like to deliberately make
10928 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010929 boolean skip = false;
10930 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010931 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010932 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10933 skip = true;
10934 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10935 skip = true;
10936 }
10937 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010938 ? intent.getData().getSchemeSpecificPart()
10939 : null;
10940 if (skipPackage != null && receivers != null) {
10941 int NT = receivers.size();
10942 for (int it=0; it<NT; it++) {
10943 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10944 if (curt.activityInfo.packageName.equals(skipPackage)) {
10945 receivers.remove(it);
10946 it--;
10947 NT--;
10948 }
10949 }
10950 }
10951
10952 int NT = receivers != null ? receivers.size() : 0;
10953 int it = 0;
10954 ResolveInfo curt = null;
10955 BroadcastFilter curr = null;
10956 while (it < NT && ir < NR) {
10957 if (curt == null) {
10958 curt = (ResolveInfo)receivers.get(it);
10959 }
10960 if (curr == null) {
10961 curr = registeredReceivers.get(ir);
10962 }
10963 if (curr.getPriority() >= curt.priority) {
10964 // Insert this broadcast record into the final list.
10965 receivers.add(it, curr);
10966 ir++;
10967 curr = null;
10968 it++;
10969 NT++;
10970 } else {
10971 // Skip to the next ResolveInfo in the final list.
10972 it++;
10973 curt = null;
10974 }
10975 }
10976 }
10977 while (ir < NR) {
10978 if (receivers == null) {
10979 receivers = new ArrayList();
10980 }
10981 receivers.add(registeredReceivers.get(ir));
10982 ir++;
10983 }
10984
10985 if ((receivers != null && receivers.size() > 0)
10986 || resultTo != null) {
10987 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10988 callerPackage, callingPid, callingUid, requiredPermission,
10989 receivers, resultTo, resultCode, resultData, map, ordered);
10990 if (DEBUG_BROADCAST) Log.v(
10991 TAG, "Enqueueing ordered broadcast " + r
10992 + ": prev had " + mOrderedBroadcasts.size());
10993 if (DEBUG_BROADCAST) {
10994 int seq = r.intent.getIntExtra("seq", -1);
10995 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10996 }
10997 mOrderedBroadcasts.add(r);
10998 scheduleBroadcastsLocked();
10999 }
11000
11001 return BROADCAST_SUCCESS;
11002 }
11003
11004 public final int broadcastIntent(IApplicationThread caller,
11005 Intent intent, String resolvedType, IIntentReceiver resultTo,
11006 int resultCode, String resultData, Bundle map,
11007 String requiredPermission, boolean serialized, boolean sticky) {
11008 // Refuse possible leaked file descriptors
11009 if (intent != null && intent.hasFileDescriptors() == true) {
11010 throw new IllegalArgumentException("File descriptors passed in Intent");
11011 }
11012
11013 synchronized(this) {
11014 if (!mSystemReady) {
11015 // if the caller really truly claims to know what they're doing, go
11016 // ahead and allow the broadcast without launching any receivers
11017 int flags = intent.getFlags();
11018 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11019 intent = new Intent(intent);
11020 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11021 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11022 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11023 + " before boot completion");
11024 throw new IllegalStateException("Cannot broadcast before boot completed");
11025 }
11026 }
11027
11028 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11029 final int callingPid = Binder.getCallingPid();
11030 final int callingUid = Binder.getCallingUid();
11031 final long origId = Binder.clearCallingIdentity();
11032 int res = broadcastIntentLocked(callerApp,
11033 callerApp != null ? callerApp.info.packageName : null,
11034 intent, resolvedType, resultTo,
11035 resultCode, resultData, map, requiredPermission, serialized,
11036 sticky, callingPid, callingUid);
11037 Binder.restoreCallingIdentity(origId);
11038 return res;
11039 }
11040 }
11041
11042 int broadcastIntentInPackage(String packageName, int uid,
11043 Intent intent, String resolvedType, IIntentReceiver resultTo,
11044 int resultCode, String resultData, Bundle map,
11045 String requiredPermission, boolean serialized, boolean sticky) {
11046 synchronized(this) {
11047 final long origId = Binder.clearCallingIdentity();
11048 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11049 resultTo, resultCode, resultData, map, requiredPermission,
11050 serialized, sticky, -1, uid);
11051 Binder.restoreCallingIdentity(origId);
11052 return res;
11053 }
11054 }
11055
11056 public final void unbroadcastIntent(IApplicationThread caller,
11057 Intent intent) {
11058 // Refuse possible leaked file descriptors
11059 if (intent != null && intent.hasFileDescriptors() == true) {
11060 throw new IllegalArgumentException("File descriptors passed in Intent");
11061 }
11062
11063 synchronized(this) {
11064 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11065 != PackageManager.PERMISSION_GRANTED) {
11066 String msg = "Permission Denial: unbroadcastIntent() from pid="
11067 + Binder.getCallingPid()
11068 + ", uid=" + Binder.getCallingUid()
11069 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11070 Log.w(TAG, msg);
11071 throw new SecurityException(msg);
11072 }
11073 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11074 if (list != null) {
11075 int N = list.size();
11076 int i;
11077 for (i=0; i<N; i++) {
11078 if (intent.filterEquals(list.get(i))) {
11079 list.remove(i);
11080 break;
11081 }
11082 }
11083 }
11084 }
11085 }
11086
11087 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11088 String resultData, Bundle resultExtras, boolean resultAbort,
11089 boolean explicit) {
11090 if (mOrderedBroadcasts.size() == 0) {
11091 if (explicit) {
11092 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11093 }
11094 return false;
11095 }
11096 BroadcastRecord r = mOrderedBroadcasts.get(0);
11097 if (r.receiver == null) {
11098 if (explicit) {
11099 Log.w(TAG, "finishReceiver called but none active");
11100 }
11101 return false;
11102 }
11103 if (r.receiver != receiver) {
11104 Log.w(TAG, "finishReceiver called but active receiver is different");
11105 return false;
11106 }
11107 int state = r.state;
11108 r.state = r.IDLE;
11109 if (state == r.IDLE) {
11110 if (explicit) {
11111 Log.w(TAG, "finishReceiver called but state is IDLE");
11112 }
11113 }
11114 r.receiver = null;
11115 r.intent.setComponent(null);
11116 if (r.curApp != null) {
11117 r.curApp.curReceiver = null;
11118 }
11119 if (r.curFilter != null) {
11120 r.curFilter.receiverList.curBroadcast = null;
11121 }
11122 r.curFilter = null;
11123 r.curApp = null;
11124 r.curComponent = null;
11125 r.curReceiver = null;
11126 mPendingBroadcast = null;
11127
11128 r.resultCode = resultCode;
11129 r.resultData = resultData;
11130 r.resultExtras = resultExtras;
11131 r.resultAbort = resultAbort;
11132
11133 // We will process the next receiver right now if this is finishing
11134 // an app receiver (which is always asynchronous) or after we have
11135 // come back from calling a receiver.
11136 return state == BroadcastRecord.APP_RECEIVE
11137 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11138 }
11139
11140 public void finishReceiver(IBinder who, int resultCode, String resultData,
11141 Bundle resultExtras, boolean resultAbort) {
11142 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11143
11144 // Refuse possible leaked file descriptors
11145 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11146 throw new IllegalArgumentException("File descriptors passed in Bundle");
11147 }
11148
11149 boolean doNext;
11150
11151 final long origId = Binder.clearCallingIdentity();
11152
11153 synchronized(this) {
11154 doNext = finishReceiverLocked(
11155 who, resultCode, resultData, resultExtras, resultAbort, true);
11156 }
11157
11158 if (doNext) {
11159 processNextBroadcast(false);
11160 }
11161 trimApplications();
11162
11163 Binder.restoreCallingIdentity(origId);
11164 }
11165
11166 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11167 if (r.nextReceiver > 0) {
11168 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11169 if (curReceiver instanceof BroadcastFilter) {
11170 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11171 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11172 System.identityHashCode(r),
11173 r.intent.getAction(),
11174 r.nextReceiver - 1,
11175 System.identityHashCode(bf));
11176 } else {
11177 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11178 System.identityHashCode(r),
11179 r.intent.getAction(),
11180 r.nextReceiver - 1,
11181 ((ResolveInfo)curReceiver).toString());
11182 }
11183 } else {
11184 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11185 + r);
11186 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11187 System.identityHashCode(r),
11188 r.intent.getAction(),
11189 r.nextReceiver,
11190 "NONE");
11191 }
11192 }
11193
11194 private final void broadcastTimeout() {
11195 synchronized (this) {
11196 if (mOrderedBroadcasts.size() == 0) {
11197 return;
11198 }
11199 long now = SystemClock.uptimeMillis();
11200 BroadcastRecord r = mOrderedBroadcasts.get(0);
11201 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11202 if (DEBUG_BROADCAST) Log.v(TAG,
11203 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11204 + (r.startTime + BROADCAST_TIMEOUT));
11205 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11206 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11207 return;
11208 }
11209
11210 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11211 r.startTime = now;
11212 r.anrCount++;
11213
11214 // Current receiver has passed its expiration date.
11215 if (r.nextReceiver <= 0) {
11216 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11217 return;
11218 }
11219
11220 ProcessRecord app = null;
11221
11222 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11223 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11224 logBroadcastReceiverDiscard(r);
11225 if (curReceiver instanceof BroadcastFilter) {
11226 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11227 if (bf.receiverList.pid != 0
11228 && bf.receiverList.pid != MY_PID) {
11229 synchronized (this.mPidsSelfLocked) {
11230 app = this.mPidsSelfLocked.get(
11231 bf.receiverList.pid);
11232 }
11233 }
11234 } else {
11235 app = r.curApp;
11236 }
11237
11238 if (app != null) {
11239 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11240 }
11241
11242 if (mPendingBroadcast == r) {
11243 mPendingBroadcast = null;
11244 }
11245
11246 // Move on to the next receiver.
11247 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11248 r.resultExtras, r.resultAbort, true);
11249 scheduleBroadcastsLocked();
11250 }
11251 }
11252
11253 private final void processCurBroadcastLocked(BroadcastRecord r,
11254 ProcessRecord app) throws RemoteException {
11255 if (app.thread == null) {
11256 throw new RemoteException();
11257 }
11258 r.receiver = app.thread.asBinder();
11259 r.curApp = app;
11260 app.curReceiver = r;
11261 updateLRUListLocked(app, true);
11262
11263 // Tell the application to launch this receiver.
11264 r.intent.setComponent(r.curComponent);
11265
11266 boolean started = false;
11267 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011268 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011269 "Delivering to component " + r.curComponent
11270 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011271 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011272 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11273 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11274 started = true;
11275 } finally {
11276 if (!started) {
11277 r.receiver = null;
11278 r.curApp = null;
11279 app.curReceiver = null;
11280 }
11281 }
11282
11283 }
11284
11285 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11286 Intent intent, int resultCode, String data,
11287 Bundle extras, boolean ordered) throws RemoteException {
11288 if (app != null && app.thread != null) {
11289 // If we have an app thread, do the call through that so it is
11290 // correctly ordered with other one-way calls.
11291 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11292 data, extras, ordered);
11293 } else {
11294 receiver.performReceive(intent, resultCode, data, extras, ordered);
11295 }
11296 }
11297
11298 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11299 BroadcastFilter filter, boolean ordered) {
11300 boolean skip = false;
11301 if (filter.requiredPermission != null) {
11302 int perm = checkComponentPermission(filter.requiredPermission,
11303 r.callingPid, r.callingUid, -1);
11304 if (perm != PackageManager.PERMISSION_GRANTED) {
11305 Log.w(TAG, "Permission Denial: broadcasting "
11306 + r.intent.toString()
11307 + " from " + r.callerPackage + " (pid="
11308 + r.callingPid + ", uid=" + r.callingUid + ")"
11309 + " requires " + filter.requiredPermission
11310 + " due to registered receiver " + filter);
11311 skip = true;
11312 }
11313 }
11314 if (r.requiredPermission != null) {
11315 int perm = checkComponentPermission(r.requiredPermission,
11316 filter.receiverList.pid, filter.receiverList.uid, -1);
11317 if (perm != PackageManager.PERMISSION_GRANTED) {
11318 Log.w(TAG, "Permission Denial: receiving "
11319 + r.intent.toString()
11320 + " to " + filter.receiverList.app
11321 + " (pid=" + filter.receiverList.pid
11322 + ", uid=" + filter.receiverList.uid + ")"
11323 + " requires " + r.requiredPermission
11324 + " due to sender " + r.callerPackage
11325 + " (uid " + r.callingUid + ")");
11326 skip = true;
11327 }
11328 }
11329
11330 if (!skip) {
11331 // If this is not being sent as an ordered broadcast, then we
11332 // don't want to touch the fields that keep track of the current
11333 // state of ordered broadcasts.
11334 if (ordered) {
11335 r.receiver = filter.receiverList.receiver.asBinder();
11336 r.curFilter = filter;
11337 filter.receiverList.curBroadcast = r;
11338 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011339 if (filter.receiverList.app != null) {
11340 // Bump hosting application to no longer be in background
11341 // scheduling class. Note that we can't do that if there
11342 // isn't an app... but we can only be in that case for
11343 // things that directly call the IActivityManager API, which
11344 // are already core system stuff so don't matter for this.
11345 r.curApp = filter.receiverList.app;
11346 filter.receiverList.app.curReceiver = r;
11347 updateOomAdjLocked();
11348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011349 }
11350 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011351 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011352 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011353 Log.i(TAG, "Delivering to " + filter.receiverList.app
11354 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011355 }
11356 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11357 new Intent(r.intent), r.resultCode,
11358 r.resultData, r.resultExtras, r.ordered);
11359 if (ordered) {
11360 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11361 }
11362 } catch (RemoteException e) {
11363 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11364 if (ordered) {
11365 r.receiver = null;
11366 r.curFilter = null;
11367 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011368 if (filter.receiverList.app != null) {
11369 filter.receiverList.app.curReceiver = null;
11370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011371 }
11372 }
11373 }
11374 }
11375
11376 private final void processNextBroadcast(boolean fromMsg) {
11377 synchronized(this) {
11378 BroadcastRecord r;
11379
11380 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11381 + mParallelBroadcasts.size() + " broadcasts, "
11382 + mOrderedBroadcasts.size() + " serialized broadcasts");
11383
11384 updateCpuStats();
11385
11386 if (fromMsg) {
11387 mBroadcastsScheduled = false;
11388 }
11389
11390 // First, deliver any non-serialized broadcasts right away.
11391 while (mParallelBroadcasts.size() > 0) {
11392 r = mParallelBroadcasts.remove(0);
11393 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011394 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11395 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011396 for (int i=0; i<N; i++) {
11397 Object target = r.receivers.get(i);
11398 if (DEBUG_BROADCAST) Log.v(TAG,
11399 "Delivering non-serialized to registered "
11400 + target + ": " + r);
11401 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11402 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011403 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11404 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011405 }
11406
11407 // Now take care of the next serialized one...
11408
11409 // If we are waiting for a process to come up to handle the next
11410 // broadcast, then do nothing at this point. Just in case, we
11411 // check that the process we're waiting for still exists.
11412 if (mPendingBroadcast != null) {
11413 Log.i(TAG, "processNextBroadcast: waiting for "
11414 + mPendingBroadcast.curApp);
11415
11416 boolean isDead;
11417 synchronized (mPidsSelfLocked) {
11418 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11419 }
11420 if (!isDead) {
11421 // It's still alive, so keep waiting
11422 return;
11423 } else {
11424 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11425 + " died before responding to broadcast");
11426 mPendingBroadcast = null;
11427 }
11428 }
11429
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011430 boolean looped = false;
11431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011432 do {
11433 if (mOrderedBroadcasts.size() == 0) {
11434 // No more broadcasts pending, so all done!
11435 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011436 if (looped) {
11437 // If we had finished the last ordered broadcast, then
11438 // make sure all processes have correct oom and sched
11439 // adjustments.
11440 updateOomAdjLocked();
11441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011442 return;
11443 }
11444 r = mOrderedBroadcasts.get(0);
11445 boolean forceReceive = false;
11446
11447 // Ensure that even if something goes awry with the timeout
11448 // detection, we catch "hung" broadcasts here, discard them,
11449 // and continue to make progress.
11450 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11451 long now = SystemClock.uptimeMillis();
11452 if (r.dispatchTime > 0) {
11453 if ((numReceivers > 0) &&
11454 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11455 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11456 + " now=" + now
11457 + " dispatchTime=" + r.dispatchTime
11458 + " startTime=" + r.startTime
11459 + " intent=" + r.intent
11460 + " numReceivers=" + numReceivers
11461 + " nextReceiver=" + r.nextReceiver
11462 + " state=" + r.state);
11463 broadcastTimeout(); // forcibly finish this broadcast
11464 forceReceive = true;
11465 r.state = BroadcastRecord.IDLE;
11466 }
11467 }
11468
11469 if (r.state != BroadcastRecord.IDLE) {
11470 if (DEBUG_BROADCAST) Log.d(TAG,
11471 "processNextBroadcast() called when not idle (state="
11472 + r.state + ")");
11473 return;
11474 }
11475
11476 if (r.receivers == null || r.nextReceiver >= numReceivers
11477 || r.resultAbort || forceReceive) {
11478 // No more receivers for this broadcast! Send the final
11479 // result if requested...
11480 if (r.resultTo != null) {
11481 try {
11482 if (DEBUG_BROADCAST) {
11483 int seq = r.intent.getIntExtra("seq", -1);
11484 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11485 + " seq=" + seq + " app=" + r.callerApp);
11486 }
11487 performReceive(r.callerApp, r.resultTo,
11488 new Intent(r.intent), r.resultCode,
11489 r.resultData, r.resultExtras, false);
11490 } catch (RemoteException e) {
11491 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11492 }
11493 }
11494
11495 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11496 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11497
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011498 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11499 + r);
11500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011501 // ... and on to the next...
11502 mOrderedBroadcasts.remove(0);
11503 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011504 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011505 continue;
11506 }
11507 } while (r == null);
11508
11509 // Get the next receiver...
11510 int recIdx = r.nextReceiver++;
11511
11512 // Keep track of when this receiver started, and make sure there
11513 // is a timeout message pending to kill it if need be.
11514 r.startTime = SystemClock.uptimeMillis();
11515 if (recIdx == 0) {
11516 r.dispatchTime = r.startTime;
11517
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011518 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11519 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011520 if (DEBUG_BROADCAST) Log.v(TAG,
11521 "Submitting BROADCAST_TIMEOUT_MSG for "
11522 + (r.startTime + BROADCAST_TIMEOUT));
11523 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11524 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11525 }
11526
11527 Object nextReceiver = r.receivers.get(recIdx);
11528 if (nextReceiver instanceof BroadcastFilter) {
11529 // Simple case: this is a registered receiver who gets
11530 // a direct call.
11531 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11532 if (DEBUG_BROADCAST) Log.v(TAG,
11533 "Delivering serialized to registered "
11534 + filter + ": " + r);
11535 deliverToRegisteredReceiver(r, filter, r.ordered);
11536 if (r.receiver == null || !r.ordered) {
11537 // The receiver has already finished, so schedule to
11538 // process the next one.
11539 r.state = BroadcastRecord.IDLE;
11540 scheduleBroadcastsLocked();
11541 }
11542 return;
11543 }
11544
11545 // Hard case: need to instantiate the receiver, possibly
11546 // starting its application process to host it.
11547
11548 ResolveInfo info =
11549 (ResolveInfo)nextReceiver;
11550
11551 boolean skip = false;
11552 int perm = checkComponentPermission(info.activityInfo.permission,
11553 r.callingPid, r.callingUid,
11554 info.activityInfo.exported
11555 ? -1 : info.activityInfo.applicationInfo.uid);
11556 if (perm != PackageManager.PERMISSION_GRANTED) {
11557 Log.w(TAG, "Permission Denial: broadcasting "
11558 + r.intent.toString()
11559 + " from " + r.callerPackage + " (pid=" + r.callingPid
11560 + ", uid=" + r.callingUid + ")"
11561 + " requires " + info.activityInfo.permission
11562 + " due to receiver " + info.activityInfo.packageName
11563 + "/" + info.activityInfo.name);
11564 skip = true;
11565 }
11566 if (r.callingUid != Process.SYSTEM_UID &&
11567 r.requiredPermission != null) {
11568 try {
11569 perm = ActivityThread.getPackageManager().
11570 checkPermission(r.requiredPermission,
11571 info.activityInfo.applicationInfo.packageName);
11572 } catch (RemoteException e) {
11573 perm = PackageManager.PERMISSION_DENIED;
11574 }
11575 if (perm != PackageManager.PERMISSION_GRANTED) {
11576 Log.w(TAG, "Permission Denial: receiving "
11577 + r.intent + " to "
11578 + info.activityInfo.applicationInfo.packageName
11579 + " requires " + r.requiredPermission
11580 + " due to sender " + r.callerPackage
11581 + " (uid " + r.callingUid + ")");
11582 skip = true;
11583 }
11584 }
11585 if (r.curApp != null && r.curApp.crashing) {
11586 // If the target process is crashing, just skip it.
11587 skip = true;
11588 }
11589
11590 if (skip) {
11591 r.receiver = null;
11592 r.curFilter = null;
11593 r.state = BroadcastRecord.IDLE;
11594 scheduleBroadcastsLocked();
11595 return;
11596 }
11597
11598 r.state = BroadcastRecord.APP_RECEIVE;
11599 String targetProcess = info.activityInfo.processName;
11600 r.curComponent = new ComponentName(
11601 info.activityInfo.applicationInfo.packageName,
11602 info.activityInfo.name);
11603 r.curReceiver = info.activityInfo;
11604
11605 // Is this receiver's application already running?
11606 ProcessRecord app = getProcessRecordLocked(targetProcess,
11607 info.activityInfo.applicationInfo.uid);
11608 if (app != null && app.thread != null) {
11609 try {
11610 processCurBroadcastLocked(r, app);
11611 return;
11612 } catch (RemoteException e) {
11613 Log.w(TAG, "Exception when sending broadcast to "
11614 + r.curComponent, e);
11615 }
11616
11617 // If a dead object exception was thrown -- fall through to
11618 // restart the application.
11619 }
11620
11621 // Not running -- get it started, and enqueue this history record
11622 // to be executed when the app comes up.
11623 if ((r.curApp=startProcessLocked(targetProcess,
11624 info.activityInfo.applicationInfo, true,
11625 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11626 "broadcast", r.curComponent)) == null) {
11627 // Ah, this recipient is unavailable. Finish it if necessary,
11628 // and mark the broadcast record as ready for the next.
11629 Log.w(TAG, "Unable to launch app "
11630 + info.activityInfo.applicationInfo.packageName + "/"
11631 + info.activityInfo.applicationInfo.uid + " for broadcast "
11632 + r.intent + ": process is bad");
11633 logBroadcastReceiverDiscard(r);
11634 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11635 r.resultExtras, r.resultAbort, true);
11636 scheduleBroadcastsLocked();
11637 r.state = BroadcastRecord.IDLE;
11638 return;
11639 }
11640
11641 mPendingBroadcast = r;
11642 }
11643 }
11644
11645 // =========================================================
11646 // INSTRUMENTATION
11647 // =========================================================
11648
11649 public boolean startInstrumentation(ComponentName className,
11650 String profileFile, int flags, Bundle arguments,
11651 IInstrumentationWatcher watcher) {
11652 // Refuse possible leaked file descriptors
11653 if (arguments != null && arguments.hasFileDescriptors()) {
11654 throw new IllegalArgumentException("File descriptors passed in Bundle");
11655 }
11656
11657 synchronized(this) {
11658 InstrumentationInfo ii = null;
11659 ApplicationInfo ai = null;
11660 try {
11661 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011662 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011663 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011664 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011665 } catch (PackageManager.NameNotFoundException e) {
11666 }
11667 if (ii == null) {
11668 reportStartInstrumentationFailure(watcher, className,
11669 "Unable to find instrumentation info for: " + className);
11670 return false;
11671 }
11672 if (ai == null) {
11673 reportStartInstrumentationFailure(watcher, className,
11674 "Unable to find instrumentation target package: " + ii.targetPackage);
11675 return false;
11676 }
11677
11678 int match = mContext.getPackageManager().checkSignatures(
11679 ii.targetPackage, ii.packageName);
11680 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11681 String msg = "Permission Denial: starting instrumentation "
11682 + className + " from pid="
11683 + Binder.getCallingPid()
11684 + ", uid=" + Binder.getCallingPid()
11685 + " not allowed because package " + ii.packageName
11686 + " does not have a signature matching the target "
11687 + ii.targetPackage;
11688 reportStartInstrumentationFailure(watcher, className, msg);
11689 throw new SecurityException(msg);
11690 }
11691
11692 final long origId = Binder.clearCallingIdentity();
11693 uninstallPackageLocked(ii.targetPackage, -1, true);
11694 ProcessRecord app = addAppLocked(ai);
11695 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011696 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011697 app.instrumentationProfileFile = profileFile;
11698 app.instrumentationArguments = arguments;
11699 app.instrumentationWatcher = watcher;
11700 app.instrumentationResultClass = className;
11701 Binder.restoreCallingIdentity(origId);
11702 }
11703
11704 return true;
11705 }
11706
11707 /**
11708 * Report errors that occur while attempting to start Instrumentation. Always writes the
11709 * error to the logs, but if somebody is watching, send the report there too. This enables
11710 * the "am" command to report errors with more information.
11711 *
11712 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11713 * @param cn The component name of the instrumentation.
11714 * @param report The error report.
11715 */
11716 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11717 ComponentName cn, String report) {
11718 Log.w(TAG, report);
11719 try {
11720 if (watcher != null) {
11721 Bundle results = new Bundle();
11722 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11723 results.putString("Error", report);
11724 watcher.instrumentationStatus(cn, -1, results);
11725 }
11726 } catch (RemoteException e) {
11727 Log.w(TAG, e);
11728 }
11729 }
11730
11731 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11732 if (app.instrumentationWatcher != null) {
11733 try {
11734 // NOTE: IInstrumentationWatcher *must* be oneway here
11735 app.instrumentationWatcher.instrumentationFinished(
11736 app.instrumentationClass,
11737 resultCode,
11738 results);
11739 } catch (RemoteException e) {
11740 }
11741 }
11742 app.instrumentationWatcher = null;
11743 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011744 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011745 app.instrumentationProfileFile = null;
11746 app.instrumentationArguments = null;
11747
11748 uninstallPackageLocked(app.processName, -1, false);
11749 }
11750
11751 public void finishInstrumentation(IApplicationThread target,
11752 int resultCode, Bundle results) {
11753 // Refuse possible leaked file descriptors
11754 if (results != null && results.hasFileDescriptors()) {
11755 throw new IllegalArgumentException("File descriptors passed in Intent");
11756 }
11757
11758 synchronized(this) {
11759 ProcessRecord app = getRecordForAppLocked(target);
11760 if (app == null) {
11761 Log.w(TAG, "finishInstrumentation: no app for " + target);
11762 return;
11763 }
11764 final long origId = Binder.clearCallingIdentity();
11765 finishInstrumentationLocked(app, resultCode, results);
11766 Binder.restoreCallingIdentity(origId);
11767 }
11768 }
11769
11770 // =========================================================
11771 // CONFIGURATION
11772 // =========================================================
11773
11774 public ConfigurationInfo getDeviceConfigurationInfo() {
11775 ConfigurationInfo config = new ConfigurationInfo();
11776 synchronized (this) {
11777 config.reqTouchScreen = mConfiguration.touchscreen;
11778 config.reqKeyboardType = mConfiguration.keyboard;
11779 config.reqNavigation = mConfiguration.navigation;
11780 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11781 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11782 }
11783 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11784 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11785 }
11786 }
11787 return config;
11788 }
11789
11790 public Configuration getConfiguration() {
11791 Configuration ci;
11792 synchronized(this) {
11793 ci = new Configuration(mConfiguration);
11794 }
11795 return ci;
11796 }
11797
11798 public void updateConfiguration(Configuration values) {
11799 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11800 "updateConfiguration()");
11801
11802 synchronized(this) {
11803 if (values == null && mWindowManager != null) {
11804 // sentinel: fetch the current configuration from the window manager
11805 values = mWindowManager.computeNewConfiguration();
11806 }
11807
11808 final long origId = Binder.clearCallingIdentity();
11809 updateConfigurationLocked(values, null);
11810 Binder.restoreCallingIdentity(origId);
11811 }
11812 }
11813
11814 /**
11815 * Do either or both things: (1) change the current configuration, and (2)
11816 * make sure the given activity is running with the (now) current
11817 * configuration. Returns true if the activity has been left running, or
11818 * false if <var>starting</var> is being destroyed to match the new
11819 * configuration.
11820 */
11821 public boolean updateConfigurationLocked(Configuration values,
11822 HistoryRecord starting) {
11823 int changes = 0;
11824
11825 boolean kept = true;
11826
11827 if (values != null) {
11828 Configuration newConfig = new Configuration(mConfiguration);
11829 changes = newConfig.updateFrom(values);
11830 if (changes != 0) {
11831 if (DEBUG_SWITCH) {
11832 Log.i(TAG, "Updating configuration to: " + values);
11833 }
11834
11835 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11836
11837 if (values.locale != null) {
11838 saveLocaleLocked(values.locale,
11839 !values.locale.equals(mConfiguration.locale),
11840 values.userSetLocale);
11841 }
11842
11843 mConfiguration = newConfig;
11844
11845 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11846 msg.obj = new Configuration(mConfiguration);
11847 mHandler.sendMessage(msg);
11848
11849 final int N = mLRUProcesses.size();
11850 for (int i=0; i<N; i++) {
11851 ProcessRecord app = mLRUProcesses.get(i);
11852 try {
11853 if (app.thread != null) {
11854 app.thread.scheduleConfigurationChanged(mConfiguration);
11855 }
11856 } catch (Exception e) {
11857 }
11858 }
11859 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11860 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11861 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011862
11863 AttributeCache ac = AttributeCache.instance();
11864 if (ac != null) {
11865 ac.updateConfiguration(mConfiguration);
11866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011867 }
11868 }
11869
11870 if (changes != 0 && starting == null) {
11871 // If the configuration changed, and the caller is not already
11872 // in the process of starting an activity, then find the top
11873 // activity to check if its configuration needs to change.
11874 starting = topRunningActivityLocked(null);
11875 }
11876
11877 if (starting != null) {
11878 kept = ensureActivityConfigurationLocked(starting, changes);
11879 if (kept) {
11880 // If this didn't result in the starting activity being
11881 // destroyed, then we need to make sure at this point that all
11882 // other activities are made visible.
11883 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11884 + ", ensuring others are correct.");
11885 ensureActivitiesVisibleLocked(starting, changes);
11886 }
11887 }
11888
11889 return kept;
11890 }
11891
11892 private final boolean relaunchActivityLocked(HistoryRecord r,
11893 int changes, boolean andResume) {
11894 List<ResultInfo> results = null;
11895 List<Intent> newIntents = null;
11896 if (andResume) {
11897 results = r.results;
11898 newIntents = r.newIntents;
11899 }
11900 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11901 + " with results=" + results + " newIntents=" + newIntents
11902 + " andResume=" + andResume);
11903 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11904 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11905 r.task.taskId, r.shortComponentName);
11906
11907 r.startFreezingScreenLocked(r.app, 0);
11908
11909 try {
11910 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11911 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11912 changes, !andResume);
11913 // Note: don't need to call pauseIfSleepingLocked() here, because
11914 // the caller will only pass in 'andResume' if this activity is
11915 // currently resumed, which implies we aren't sleeping.
11916 } catch (RemoteException e) {
11917 return false;
11918 }
11919
11920 if (andResume) {
11921 r.results = null;
11922 r.newIntents = null;
11923 }
11924
11925 return true;
11926 }
11927
11928 /**
11929 * Make sure the given activity matches the current configuration. Returns
11930 * false if the activity had to be destroyed. Returns true if the
11931 * configuration is the same, or the activity will remain running as-is
11932 * for whatever reason. Ensures the HistoryRecord is updated with the
11933 * correct configuration and all other bookkeeping is handled.
11934 */
11935 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11936 int globalChanges) {
11937 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11938
11939 // Short circuit: if the two configurations are the exact same
11940 // object (the common case), then there is nothing to do.
11941 Configuration newConfig = mConfiguration;
11942 if (r.configuration == newConfig) {
11943 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11944 return true;
11945 }
11946
11947 // We don't worry about activities that are finishing.
11948 if (r.finishing) {
11949 if (DEBUG_SWITCH) Log.i(TAG,
11950 "Configuration doesn't matter in finishing " + r);
11951 r.stopFreezingScreenLocked(false);
11952 return true;
11953 }
11954
11955 // Okay we now are going to make this activity have the new config.
11956 // But then we need to figure out how it needs to deal with that.
11957 Configuration oldConfig = r.configuration;
11958 r.configuration = newConfig;
11959
11960 // If the activity isn't currently running, just leave the new
11961 // configuration and it will pick that up next time it starts.
11962 if (r.app == null || r.app.thread == null) {
11963 if (DEBUG_SWITCH) Log.i(TAG,
11964 "Configuration doesn't matter not running " + r);
11965 r.stopFreezingScreenLocked(false);
11966 return true;
11967 }
11968
11969 // If the activity isn't persistent, there is a chance we will
11970 // need to restart it.
11971 if (!r.persistent) {
11972
11973 // Figure out what has changed between the two configurations.
11974 int changes = oldConfig.diff(newConfig);
11975 if (DEBUG_SWITCH) {
11976 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11977 + Integer.toHexString(changes) + ", handles=0x"
11978 + Integer.toHexString(r.info.configChanges));
11979 }
11980 if ((changes&(~r.info.configChanges)) != 0) {
11981 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11982 r.configChangeFlags |= changes;
11983 r.startFreezingScreenLocked(r.app, globalChanges);
11984 if (r.app == null || r.app.thread == null) {
11985 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11986 destroyActivityLocked(r, true);
11987 } else if (r.state == ActivityState.PAUSING) {
11988 // A little annoying: we are waiting for this activity to
11989 // finish pausing. Let's not do anything now, but just
11990 // flag that it needs to be restarted when done pausing.
11991 r.configDestroy = true;
11992 return true;
11993 } else if (r.state == ActivityState.RESUMED) {
11994 // Try to optimize this case: the configuration is changing
11995 // and we need to restart the top, resumed activity.
11996 // Instead of doing the normal handshaking, just say
11997 // "restart!".
11998 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11999 relaunchActivityLocked(r, r.configChangeFlags, true);
12000 r.configChangeFlags = 0;
12001 } else {
12002 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12003 relaunchActivityLocked(r, r.configChangeFlags, false);
12004 r.configChangeFlags = 0;
12005 }
12006
12007 // All done... tell the caller we weren't able to keep this
12008 // activity around.
12009 return false;
12010 }
12011 }
12012
12013 // Default case: the activity can handle this new configuration, so
12014 // hand it over. Note that we don't need to give it the new
12015 // configuration, since we always send configuration changes to all
12016 // process when they happen so it can just use whatever configuration
12017 // it last got.
12018 if (r.app != null && r.app.thread != null) {
12019 try {
12020 r.app.thread.scheduleActivityConfigurationChanged(r);
12021 } catch (RemoteException e) {
12022 // If process died, whatever.
12023 }
12024 }
12025 r.stopFreezingScreenLocked(false);
12026
12027 return true;
12028 }
12029
12030 /**
12031 * Save the locale. You must be inside a synchronized (this) block.
12032 */
12033 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12034 if(isDiff) {
12035 SystemProperties.set("user.language", l.getLanguage());
12036 SystemProperties.set("user.region", l.getCountry());
12037 }
12038
12039 if(isPersist) {
12040 SystemProperties.set("persist.sys.language", l.getLanguage());
12041 SystemProperties.set("persist.sys.country", l.getCountry());
12042 SystemProperties.set("persist.sys.localevar", l.getVariant());
12043 }
12044 }
12045
12046 // =========================================================
12047 // LIFETIME MANAGEMENT
12048 // =========================================================
12049
12050 private final int computeOomAdjLocked(
12051 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12052 if (mAdjSeq == app.adjSeq) {
12053 // This adjustment has already been computed.
12054 return app.curAdj;
12055 }
12056
12057 if (app.thread == null) {
12058 app.adjSeq = mAdjSeq;
12059 return (app.curAdj=EMPTY_APP_ADJ);
12060 }
12061
12062 app.isForeground = false;
12063
The Android Open Source Project4df24232009-03-05 14:34:35 -080012064 // Determine the importance of the process, starting with most
12065 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012066 int adj;
12067 int N;
12068 if (app == TOP_APP || app.instrumentationClass != null
12069 || app.persistentActivities > 0) {
12070 // The last app on the list is the foreground app.
12071 adj = FOREGROUND_APP_ADJ;
12072 app.isForeground = true;
12073 } else if (app.curReceiver != null ||
12074 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12075 // An app that is currently receiving a broadcast also
12076 // counts as being in the foreground.
12077 adj = FOREGROUND_APP_ADJ;
12078 } else if (app.executingServices.size() > 0) {
12079 // An app that is currently executing a service callback also
12080 // counts as being in the foreground.
12081 adj = FOREGROUND_APP_ADJ;
12082 } else if (app.foregroundServices || app.forcingToForeground != null) {
12083 // The user is aware of this app, so make it visible.
12084 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012085 } else if (app == mHomeProcess) {
12086 // This process is hosting what we currently consider to be the
12087 // home app, so we don't want to let it go into the background.
12088 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012089 } else if ((N=app.activities.size()) != 0) {
12090 // This app is in the background with paused activities.
12091 adj = hiddenAdj;
12092 for (int j=0; j<N; j++) {
12093 if (((HistoryRecord)app.activities.get(j)).visible) {
12094 // This app has a visible activity!
12095 adj = VISIBLE_APP_ADJ;
12096 break;
12097 }
12098 }
12099 } else {
12100 // A very not-needed process.
12101 adj = EMPTY_APP_ADJ;
12102 }
12103
The Android Open Source Project4df24232009-03-05 14:34:35 -080012104 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012105 // there are applications dependent on our services or providers, but
12106 // this gives us a baseline and makes sure we don't get into an
12107 // infinite recursion.
12108 app.adjSeq = mAdjSeq;
12109 app.curRawAdj = adj;
12110 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12111
Christopher Tate6fa95972009-06-05 18:43:55 -070012112 if (mBackupTarget != null && app == mBackupTarget.app) {
12113 // If possible we want to avoid killing apps while they're being backed up
12114 if (adj > BACKUP_APP_ADJ) {
12115 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12116 adj = BACKUP_APP_ADJ;
12117 }
12118 }
12119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012120 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12121 // If this process has active services running in it, we would
12122 // like to avoid killing it unless it would prevent the current
12123 // application from running.
12124 if (adj > hiddenAdj) {
12125 adj = hiddenAdj;
12126 }
12127 final long now = SystemClock.uptimeMillis();
12128 // This process is more important if the top activity is
12129 // bound to the service.
12130 Iterator jt = app.services.iterator();
12131 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12132 ServiceRecord s = (ServiceRecord)jt.next();
12133 if (s.startRequested) {
12134 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12135 // This service has seen some activity within
12136 // recent memory, so we will keep its process ahead
12137 // of the background processes.
12138 if (adj > SECONDARY_SERVER_ADJ) {
12139 adj = SECONDARY_SERVER_ADJ;
12140 }
12141 } else {
12142 // This service has been inactive for too long, just
12143 // put it with the rest of the background processes.
12144 if (adj > hiddenAdj) {
12145 adj = hiddenAdj;
12146 }
12147 }
12148 }
12149 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12150 Iterator<ConnectionRecord> kt
12151 = s.connections.values().iterator();
12152 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12153 // XXX should compute this based on the max of
12154 // all connected clients.
12155 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012156 if (cr.binding.client == app) {
12157 // Binding to ourself is not interesting.
12158 continue;
12159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012160 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12161 ProcessRecord client = cr.binding.client;
12162 int myHiddenAdj = hiddenAdj;
12163 if (myHiddenAdj > client.hiddenAdj) {
12164 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12165 myHiddenAdj = client.hiddenAdj;
12166 } else {
12167 myHiddenAdj = VISIBLE_APP_ADJ;
12168 }
12169 }
12170 int clientAdj = computeOomAdjLocked(
12171 client, myHiddenAdj, TOP_APP);
12172 if (adj > clientAdj) {
12173 adj = clientAdj > VISIBLE_APP_ADJ
12174 ? clientAdj : VISIBLE_APP_ADJ;
12175 }
12176 }
12177 HistoryRecord a = cr.activity;
12178 //if (a != null) {
12179 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12180 //}
12181 if (a != null && adj > FOREGROUND_APP_ADJ &&
12182 (a.state == ActivityState.RESUMED
12183 || a.state == ActivityState.PAUSING)) {
12184 adj = FOREGROUND_APP_ADJ;
12185 }
12186 }
12187 }
12188 }
12189 }
12190
12191 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12192 // If this process has published any content providers, then
12193 // its adjustment makes it at least as important as any of the
12194 // processes using those providers, and no less important than
12195 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12196 if (adj > CONTENT_PROVIDER_ADJ) {
12197 adj = CONTENT_PROVIDER_ADJ;
12198 }
12199 Iterator jt = app.pubProviders.values().iterator();
12200 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12201 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12202 if (cpr.clients.size() != 0) {
12203 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12204 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12205 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012206 if (client == app) {
12207 // Being our own client is not interesting.
12208 continue;
12209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012210 int myHiddenAdj = hiddenAdj;
12211 if (myHiddenAdj > client.hiddenAdj) {
12212 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12213 myHiddenAdj = client.hiddenAdj;
12214 } else {
12215 myHiddenAdj = FOREGROUND_APP_ADJ;
12216 }
12217 }
12218 int clientAdj = computeOomAdjLocked(
12219 client, myHiddenAdj, TOP_APP);
12220 if (adj > clientAdj) {
12221 adj = clientAdj > FOREGROUND_APP_ADJ
12222 ? clientAdj : FOREGROUND_APP_ADJ;
12223 }
12224 }
12225 }
12226 // If the provider has external (non-framework) process
12227 // dependencies, ensure that its adjustment is at least
12228 // FOREGROUND_APP_ADJ.
12229 if (cpr.externals != 0) {
12230 if (adj > FOREGROUND_APP_ADJ) {
12231 adj = FOREGROUND_APP_ADJ;
12232 }
12233 }
12234 }
12235 }
12236
12237 app.curRawAdj = adj;
12238
12239 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12240 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12241 if (adj > app.maxAdj) {
12242 adj = app.maxAdj;
12243 }
12244
12245 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012246 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12247 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12248 : Process.THREAD_GROUP_DEFAULT;
12249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012250 return adj;
12251 }
12252
12253 /**
12254 * Ask a given process to GC right now.
12255 */
12256 final void performAppGcLocked(ProcessRecord app) {
12257 try {
12258 app.lastRequestedGc = SystemClock.uptimeMillis();
12259 if (app.thread != null) {
12260 app.thread.processInBackground();
12261 }
12262 } catch (Exception e) {
12263 // whatever.
12264 }
12265 }
12266
12267 /**
12268 * Returns true if things are idle enough to perform GCs.
12269 */
12270 private final boolean canGcNow() {
12271 return mParallelBroadcasts.size() == 0
12272 && mOrderedBroadcasts.size() == 0
12273 && (mSleeping || (mResumedActivity != null &&
12274 mResumedActivity.idle));
12275 }
12276
12277 /**
12278 * Perform GCs on all processes that are waiting for it, but only
12279 * if things are idle.
12280 */
12281 final void performAppGcsLocked() {
12282 final int N = mProcessesToGc.size();
12283 if (N <= 0) {
12284 return;
12285 }
12286 if (canGcNow()) {
12287 while (mProcessesToGc.size() > 0) {
12288 ProcessRecord proc = mProcessesToGc.remove(0);
12289 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12290 // To avoid spamming the system, we will GC processes one
12291 // at a time, waiting a few seconds between each.
12292 performAppGcLocked(proc);
12293 scheduleAppGcsLocked();
12294 return;
12295 }
12296 }
12297 }
12298 }
12299
12300 /**
12301 * If all looks good, perform GCs on all processes waiting for them.
12302 */
12303 final void performAppGcsIfAppropriateLocked() {
12304 if (canGcNow()) {
12305 performAppGcsLocked();
12306 return;
12307 }
12308 // Still not idle, wait some more.
12309 scheduleAppGcsLocked();
12310 }
12311
12312 /**
12313 * Schedule the execution of all pending app GCs.
12314 */
12315 final void scheduleAppGcsLocked() {
12316 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12317 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12318 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12319 }
12320
12321 /**
12322 * Set up to ask a process to GC itself. This will either do it
12323 * immediately, or put it on the list of processes to gc the next
12324 * time things are idle.
12325 */
12326 final void scheduleAppGcLocked(ProcessRecord app) {
12327 long now = SystemClock.uptimeMillis();
12328 if ((app.lastRequestedGc+5000) > now) {
12329 return;
12330 }
12331 if (!mProcessesToGc.contains(app)) {
12332 mProcessesToGc.add(app);
12333 scheduleAppGcsLocked();
12334 }
12335 }
12336
12337 private final boolean updateOomAdjLocked(
12338 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12339 app.hiddenAdj = hiddenAdj;
12340
12341 if (app.thread == null) {
12342 return true;
12343 }
12344
12345 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12346
12347 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12348 //Thread priority adjustment is disabled out to see
12349 //how the kernel scheduler performs.
12350 if (false) {
12351 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12352 app.setIsForeground = app.isForeground;
12353 if (app.pid != MY_PID) {
12354 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12355 + " to " + (app.isForeground
12356 ? Process.THREAD_PRIORITY_FOREGROUND
12357 : Process.THREAD_PRIORITY_DEFAULT));
12358 try {
12359 Process.setThreadPriority(app.pid, app.isForeground
12360 ? Process.THREAD_PRIORITY_FOREGROUND
12361 : Process.THREAD_PRIORITY_DEFAULT);
12362 } catch (RuntimeException e) {
12363 Log.w(TAG, "Exception trying to set priority of application thread "
12364 + app.pid, e);
12365 }
12366 }
12367 }
12368 }
12369 if (app.pid != 0 && app.pid != MY_PID) {
12370 if (app.curRawAdj != app.setRawAdj) {
12371 if (app.curRawAdj > FOREGROUND_APP_ADJ
12372 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12373 // If this app is transitioning from foreground to
12374 // non-foreground, have it do a gc.
12375 scheduleAppGcLocked(app);
12376 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12377 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12378 // Likewise do a gc when an app is moving in to the
12379 // background (such as a service stopping).
12380 scheduleAppGcLocked(app);
12381 }
12382 app.setRawAdj = app.curRawAdj;
12383 }
12384 if (adj != app.setAdj) {
12385 if (Process.setOomAdj(app.pid, adj)) {
12386 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12387 TAG, "Set app " + app.processName +
12388 " oom adj to " + adj);
12389 app.setAdj = adj;
12390 } else {
12391 return false;
12392 }
12393 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012394 if (app.setSchedGroup != app.curSchedGroup) {
12395 app.setSchedGroup = app.curSchedGroup;
12396 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12397 "Setting process group of " + app.processName
12398 + " to " + app.curSchedGroup);
12399 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012400 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012401 try {
12402 Process.setProcessGroup(app.pid, app.curSchedGroup);
12403 } catch (Exception e) {
12404 Log.w(TAG, "Failed setting process group of " + app.pid
12405 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012406 e.printStackTrace();
12407 } finally {
12408 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012409 }
12410 }
12411 if (false) {
12412 if (app.thread != null) {
12413 try {
12414 app.thread.setSchedulingGroup(app.curSchedGroup);
12415 } catch (RemoteException e) {
12416 }
12417 }
12418 }
12419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012420 }
12421
12422 return true;
12423 }
12424
12425 private final HistoryRecord resumedAppLocked() {
12426 HistoryRecord resumedActivity = mResumedActivity;
12427 if (resumedActivity == null || resumedActivity.app == null) {
12428 resumedActivity = mPausingActivity;
12429 if (resumedActivity == null || resumedActivity.app == null) {
12430 resumedActivity = topRunningActivityLocked(null);
12431 }
12432 }
12433 return resumedActivity;
12434 }
12435
12436 private final boolean updateOomAdjLocked(ProcessRecord app) {
12437 final HistoryRecord TOP_ACT = resumedAppLocked();
12438 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12439 int curAdj = app.curAdj;
12440 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12441 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12442
12443 mAdjSeq++;
12444
12445 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12446 if (res) {
12447 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12448 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12449 if (nowHidden != wasHidden) {
12450 // Changed to/from hidden state, so apps after it in the LRU
12451 // list may also be changed.
12452 updateOomAdjLocked();
12453 }
12454 }
12455 return res;
12456 }
12457
12458 private final boolean updateOomAdjLocked() {
12459 boolean didOomAdj = true;
12460 final HistoryRecord TOP_ACT = resumedAppLocked();
12461 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12462
12463 if (false) {
12464 RuntimeException e = new RuntimeException();
12465 e.fillInStackTrace();
12466 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12467 }
12468
12469 mAdjSeq++;
12470
12471 // First try updating the OOM adjustment for each of the
12472 // application processes based on their current state.
12473 int i = mLRUProcesses.size();
12474 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12475 while (i > 0) {
12476 i--;
12477 ProcessRecord app = mLRUProcesses.get(i);
12478 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12479 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12480 && app.curAdj == curHiddenAdj) {
12481 curHiddenAdj++;
12482 }
12483 } else {
12484 didOomAdj = false;
12485 }
12486 }
12487
12488 // todo: for now pretend like OOM ADJ didn't work, because things
12489 // aren't behaving as expected on Linux -- it's not killing processes.
12490 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12491 }
12492
12493 private final void trimApplications() {
12494 synchronized (this) {
12495 int i;
12496
12497 // First remove any unused application processes whose package
12498 // has been removed.
12499 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12500 final ProcessRecord app = mRemovedProcesses.get(i);
12501 if (app.activities.size() == 0
12502 && app.curReceiver == null && app.services.size() == 0) {
12503 Log.i(
12504 TAG, "Exiting empty application process "
12505 + app.processName + " ("
12506 + (app.thread != null ? app.thread.asBinder() : null)
12507 + ")\n");
12508 if (app.pid > 0 && app.pid != MY_PID) {
12509 Process.killProcess(app.pid);
12510 } else {
12511 try {
12512 app.thread.scheduleExit();
12513 } catch (Exception e) {
12514 // Ignore exceptions.
12515 }
12516 }
12517 cleanUpApplicationRecordLocked(app, false, -1);
12518 mRemovedProcesses.remove(i);
12519
12520 if (app.persistent) {
12521 if (app.persistent) {
12522 addAppLocked(app.info);
12523 }
12524 }
12525 }
12526 }
12527
12528 // Now try updating the OOM adjustment for each of the
12529 // application processes based on their current state.
12530 // If the setOomAdj() API is not supported, then go with our
12531 // back-up plan...
12532 if (!updateOomAdjLocked()) {
12533
12534 // Count how many processes are running services.
12535 int numServiceProcs = 0;
12536 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12537 final ProcessRecord app = mLRUProcesses.get(i);
12538
12539 if (app.persistent || app.services.size() != 0
12540 || app.curReceiver != null
12541 || app.persistentActivities > 0) {
12542 // Don't count processes holding services against our
12543 // maximum process count.
12544 if (localLOGV) Log.v(
12545 TAG, "Not trimming app " + app + " with services: "
12546 + app.services);
12547 numServiceProcs++;
12548 }
12549 }
12550
12551 int curMaxProcs = mProcessLimit;
12552 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12553 if (mAlwaysFinishActivities) {
12554 curMaxProcs = 1;
12555 }
12556 curMaxProcs += numServiceProcs;
12557
12558 // Quit as many processes as we can to get down to the desired
12559 // process count. First remove any processes that no longer
12560 // have activites running in them.
12561 for ( i=0;
12562 i<mLRUProcesses.size()
12563 && mLRUProcesses.size() > curMaxProcs;
12564 i++) {
12565 final ProcessRecord app = mLRUProcesses.get(i);
12566 // Quit an application only if it is not currently
12567 // running any activities.
12568 if (!app.persistent && app.activities.size() == 0
12569 && app.curReceiver == null && app.services.size() == 0) {
12570 Log.i(
12571 TAG, "Exiting empty application process "
12572 + app.processName + " ("
12573 + (app.thread != null ? app.thread.asBinder() : null)
12574 + ")\n");
12575 if (app.pid > 0 && app.pid != MY_PID) {
12576 Process.killProcess(app.pid);
12577 } else {
12578 try {
12579 app.thread.scheduleExit();
12580 } catch (Exception e) {
12581 // Ignore exceptions.
12582 }
12583 }
12584 // todo: For now we assume the application is not buggy
12585 // or evil, and will quit as a result of our request.
12586 // Eventually we need to drive this off of the death
12587 // notification, and kill the process if it takes too long.
12588 cleanUpApplicationRecordLocked(app, false, i);
12589 i--;
12590 }
12591 }
12592
12593 // If we still have too many processes, now from the least
12594 // recently used process we start finishing activities.
12595 if (Config.LOGV) Log.v(
12596 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12597 " of " + curMaxProcs + " processes");
12598 for ( i=0;
12599 i<mLRUProcesses.size()
12600 && mLRUProcesses.size() > curMaxProcs;
12601 i++) {
12602 final ProcessRecord app = mLRUProcesses.get(i);
12603 // Quit the application only if we have a state saved for
12604 // all of its activities.
12605 boolean canQuit = !app.persistent && app.curReceiver == null
12606 && app.services.size() == 0
12607 && app.persistentActivities == 0;
12608 int NUMA = app.activities.size();
12609 int j;
12610 if (Config.LOGV) Log.v(
12611 TAG, "Looking to quit " + app.processName);
12612 for (j=0; j<NUMA && canQuit; j++) {
12613 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12614 if (Config.LOGV) Log.v(
12615 TAG, " " + r.intent.getComponent().flattenToShortString()
12616 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12617 canQuit = (r.haveState || !r.stateNotNeeded)
12618 && !r.visible && r.stopped;
12619 }
12620 if (canQuit) {
12621 // Finish all of the activities, and then the app itself.
12622 for (j=0; j<NUMA; j++) {
12623 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12624 if (!r.finishing) {
12625 destroyActivityLocked(r, false);
12626 }
12627 r.resultTo = null;
12628 }
12629 Log.i(TAG, "Exiting application process "
12630 + app.processName + " ("
12631 + (app.thread != null ? app.thread.asBinder() : null)
12632 + ")\n");
12633 if (app.pid > 0 && app.pid != MY_PID) {
12634 Process.killProcess(app.pid);
12635 } else {
12636 try {
12637 app.thread.scheduleExit();
12638 } catch (Exception e) {
12639 // Ignore exceptions.
12640 }
12641 }
12642 // todo: For now we assume the application is not buggy
12643 // or evil, and will quit as a result of our request.
12644 // Eventually we need to drive this off of the death
12645 // notification, and kill the process if it takes too long.
12646 cleanUpApplicationRecordLocked(app, false, i);
12647 i--;
12648 //dump();
12649 }
12650 }
12651
12652 }
12653
12654 int curMaxActivities = MAX_ACTIVITIES;
12655 if (mAlwaysFinishActivities) {
12656 curMaxActivities = 1;
12657 }
12658
12659 // Finally, if there are too many activities now running, try to
12660 // finish as many as we can to get back down to the limit.
12661 for ( i=0;
12662 i<mLRUActivities.size()
12663 && mLRUActivities.size() > curMaxActivities;
12664 i++) {
12665 final HistoryRecord r
12666 = (HistoryRecord)mLRUActivities.get(i);
12667
12668 // We can finish this one if we have its icicle saved and
12669 // it is not persistent.
12670 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12671 && r.stopped && !r.persistent && !r.finishing) {
12672 final int origSize = mLRUActivities.size();
12673 destroyActivityLocked(r, true);
12674
12675 // This will remove it from the LRU list, so keep
12676 // our index at the same value. Note that this check to
12677 // see if the size changes is just paranoia -- if
12678 // something unexpected happens, we don't want to end up
12679 // in an infinite loop.
12680 if (origSize > mLRUActivities.size()) {
12681 i--;
12682 }
12683 }
12684 }
12685 }
12686 }
12687
12688 /** This method sends the specified signal to each of the persistent apps */
12689 public void signalPersistentProcesses(int sig) throws RemoteException {
12690 if (sig != Process.SIGNAL_USR1) {
12691 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12692 }
12693
12694 synchronized (this) {
12695 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12696 != PackageManager.PERMISSION_GRANTED) {
12697 throw new SecurityException("Requires permission "
12698 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12699 }
12700
12701 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12702 ProcessRecord r = mLRUProcesses.get(i);
12703 if (r.thread != null && r.persistent) {
12704 Process.sendSignal(r.pid, sig);
12705 }
12706 }
12707 }
12708 }
12709
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012710 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012711 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012712
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012713 try {
12714 synchronized (this) {
12715 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12716 // its own permission.
12717 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12718 != PackageManager.PERMISSION_GRANTED) {
12719 throw new SecurityException("Requires permission "
12720 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012721 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012722
12723 if (start && fd == null) {
12724 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012725 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012726
12727 ProcessRecord proc = null;
12728 try {
12729 int pid = Integer.parseInt(process);
12730 synchronized (mPidsSelfLocked) {
12731 proc = mPidsSelfLocked.get(pid);
12732 }
12733 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012734 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012735
12736 if (proc == null) {
12737 HashMap<String, SparseArray<ProcessRecord>> all
12738 = mProcessNames.getMap();
12739 SparseArray<ProcessRecord> procs = all.get(process);
12740 if (procs != null && procs.size() > 0) {
12741 proc = procs.valueAt(0);
12742 }
12743 }
12744
12745 if (proc == null || proc.thread == null) {
12746 throw new IllegalArgumentException("Unknown process: " + process);
12747 }
12748
12749 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12750 if (isSecure) {
12751 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12752 throw new SecurityException("Process not debuggable: " + proc);
12753 }
12754 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012755
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012756 proc.thread.profilerControl(start, path, fd);
12757 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012758 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012759 }
12760 } catch (RemoteException e) {
12761 throw new IllegalStateException("Process disappeared");
12762 } finally {
12763 if (fd != null) {
12764 try {
12765 fd.close();
12766 } catch (IOException e) {
12767 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012768 }
12769 }
12770 }
12771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012772 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12773 public void monitor() {
12774 synchronized (this) { }
12775 }
12776}