blob: ac176caf286a15774168fd41ede980741db824bf [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import com.android.server.IntentResolver;
21import com.android.server.ProcessMap;
22import com.android.server.ProcessStats;
23import com.android.server.SystemServer;
24import com.android.server.Watchdog;
25import com.android.server.WindowManagerService;
26
27import android.app.Activity;
28import android.app.ActivityManager;
29import android.app.ActivityManagerNative;
30import android.app.ActivityThread;
31import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020032import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.app.Dialog;
34import android.app.IActivityWatcher;
35import android.app.IApplicationThread;
36import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.app.IServiceConnection;
38import android.app.IThumbnailReceiver;
39import android.app.Instrumentation;
40import android.app.PendingIntent;
41import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070042import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020043import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.ComponentName;
45import android.content.ContentResolver;
46import android.content.Context;
47import android.content.Intent;
48import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070049import android.content.IIntentReceiver;
50import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.pm.ActivityInfo;
52import android.content.pm.ApplicationInfo;
53import android.content.pm.ConfigurationInfo;
54import android.content.pm.IPackageDataObserver;
55import android.content.pm.IPackageManager;
56import android.content.pm.InstrumentationInfo;
57import android.content.pm.PackageManager;
58import android.content.pm.ProviderInfo;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
61import android.content.res.Configuration;
62import android.graphics.Bitmap;
63import android.net.Uri;
64import android.os.Binder;
65import android.os.Bundle;
66import android.os.Environment;
67import android.os.FileUtils;
68import android.os.Handler;
69import android.os.IBinder;
70import android.os.IPermissionController;
71import android.os.Looper;
72import android.os.Message;
73import android.os.Parcel;
74import android.os.ParcelFileDescriptor;
75import android.os.PowerManager;
76import android.os.Process;
77import android.os.RemoteException;
78import android.os.ServiceManager;
79import android.os.SystemClock;
80import android.os.SystemProperties;
81import android.provider.Checkin;
82import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020083import android.server.data.CrashData;
84import android.server.data.StackTraceElementData;
85import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.text.TextUtils;
87import android.util.Config;
88import android.util.EventLog;
89import android.util.Log;
90import android.util.PrintWriterPrinter;
91import android.util.SparseArray;
92import android.view.Gravity;
93import android.view.LayoutInflater;
94import android.view.View;
95import android.view.WindowManager;
96import android.view.WindowManagerPolicy;
97
98import dalvik.system.Zygote;
99
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200100import java.io.ByteArrayInputStream;
101import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import java.io.File;
103import java.io.FileDescriptor;
104import java.io.FileInputStream;
105import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200106import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.io.PrintWriter;
108import java.lang.IllegalStateException;
109import java.lang.ref.WeakReference;
110import java.util.ArrayList;
111import java.util.HashMap;
112import java.util.HashSet;
113import java.util.Iterator;
114import java.util.List;
115import java.util.Locale;
116import java.util.Map;
117
118public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
119 static final String TAG = "ActivityManager";
120 static final boolean DEBUG = false;
121 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
122 static final boolean DEBUG_SWITCH = localLOGV || false;
123 static final boolean DEBUG_TASKS = localLOGV || false;
124 static final boolean DEBUG_PAUSE = localLOGV || false;
125 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
126 static final boolean DEBUG_TRANSITION = localLOGV || false;
127 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700128 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 static final boolean DEBUG_SERVICE = localLOGV || false;
130 static final boolean DEBUG_VISBILITY = localLOGV || false;
131 static final boolean DEBUG_PROCESSES = localLOGV || false;
132 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700133 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700134 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean VALIDATE_TOKENS = false;
136 static final boolean SHOW_ACTIVITY_START_TIME = true;
137
138 // Control over CPU and battery monitoring.
139 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
140 static final boolean MONITOR_CPU_USAGE = true;
141 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
142 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
143 static final boolean MONITOR_THREAD_CPU_USAGE = false;
144
145 // Event log tags
146 static final int LOG_CONFIGURATION_CHANGED = 2719;
147 static final int LOG_CPU = 2721;
148 static final int LOG_AM_FINISH_ACTIVITY = 30001;
149 static final int LOG_TASK_TO_FRONT = 30002;
150 static final int LOG_AM_NEW_INTENT = 30003;
151 static final int LOG_AM_CREATE_TASK = 30004;
152 static final int LOG_AM_CREATE_ACTIVITY = 30005;
153 static final int LOG_AM_RESTART_ACTIVITY = 30006;
154 static final int LOG_AM_RESUME_ACTIVITY = 30007;
155 static final int LOG_ANR = 30008;
156 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
157 static final int LOG_AM_PROCESS_BOUND = 30010;
158 static final int LOG_AM_PROCESS_DIED = 30011;
159 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
160 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
161 static final int LOG_AM_PROCESS_START = 30014;
162 static final int LOG_AM_PROCESS_BAD = 30015;
163 static final int LOG_AM_PROCESS_GOOD = 30016;
164 static final int LOG_AM_LOW_MEMORY = 30017;
165 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
166 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
167 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
168 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
169 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
170 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
171 static final int LOG_AM_CREATE_SERVICE = 30030;
172 static final int LOG_AM_DESTROY_SERVICE = 30031;
173 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
174 static final int LOG_AM_DROP_PROCESS = 30033;
175 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
176 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
177 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
178
179 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
180 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
181
Dianne Hackborn1655be42009-05-08 14:29:01 -0700182 // The flags that are set for all calls we make to the package manager.
183 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700184 | PackageManager.GET_SUPPORTS_DENSITIES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 private static final String SYSTEM_SECURE = "ro.secure";
187
188 // This is the maximum number of application processes we would like
189 // to have running. Due to the asynchronous nature of things, we can
190 // temporarily go beyond this limit.
191 static final int MAX_PROCESSES = 2;
192
193 // Set to false to leave processes running indefinitely, relying on
194 // the kernel killing them as resources are required.
195 static final boolean ENFORCE_PROCESS_LIMIT = false;
196
197 // This is the maximum number of activities that we would like to have
198 // running at a given time.
199 static final int MAX_ACTIVITIES = 20;
200
201 // Maximum number of recent tasks that we can remember.
202 static final int MAX_RECENT_TASKS = 20;
203
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700204 // Amount of time after a call to stopAppSwitches() during which we will
205 // prevent further untrusted switches from happening.
206 static final long APP_SWITCH_DELAY_TIME = 5*1000;
207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 // How long until we reset a task when the user returns to it. Currently
209 // 30 minutes.
210 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
211
212 // Set to true to disable the icon that is shown while a new activity
213 // is being started.
214 static final boolean SHOW_APP_STARTING_ICON = true;
215
216 // How long we wait until giving up on the last activity to pause. This
217 // is short because it directly impacts the responsiveness of starting the
218 // next activity.
219 static final int PAUSE_TIMEOUT = 500;
220
221 /**
222 * How long we can hold the launch wake lock before giving up.
223 */
224 static final int LAUNCH_TIMEOUT = 10*1000;
225
226 // How long we wait for a launched process to attach to the activity manager
227 // before we decide it's never going to come up for real.
228 static final int PROC_START_TIMEOUT = 10*1000;
229
230 // How long we wait until giving up on the last activity telling us it
231 // is idle.
232 static final int IDLE_TIMEOUT = 10*1000;
233
234 // How long to wait after going idle before forcing apps to GC.
235 static final int GC_TIMEOUT = 5*1000;
236
237 // How long we wait until giving up on an activity telling us it has
238 // finished destroying itself.
239 static final int DESTROY_TIMEOUT = 10*1000;
240
241 // How long we allow a receiver to run before giving up on it.
242 static final int BROADCAST_TIMEOUT = 10*1000;
243
244 // How long we wait for a service to finish executing.
245 static final int SERVICE_TIMEOUT = 20*1000;
246
247 // How long a service needs to be running until restarting its process
248 // is no longer considered to be a relaunch of the service.
249 static final int SERVICE_RESTART_DURATION = 5*1000;
250
251 // Maximum amount of time for there to be no activity on a service before
252 // we consider it non-essential and allow its process to go on the
253 // LRU background list.
254 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
255
256 // How long we wait until we timeout on key dispatching.
257 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
258
259 // The minimum time we allow between crashes, for us to consider this
260 // application to be bad and stop and its services and reject broadcasts.
261 static final int MIN_CRASH_INTERVAL = 60*1000;
262
263 // How long we wait until we timeout on key dispatching during instrumentation.
264 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
265
266 // OOM adjustments for processes in various states:
267
268 // This is a process without anything currently running in it. Definitely
269 // the first to go! Value set in system/rootdir/init.rc on startup.
270 // This value is initalized in the constructor, careful when refering to
271 // this static variable externally.
272 static int EMPTY_APP_ADJ;
273
274 // This is a process with a content provider that does not have any clients
275 // attached to it. If it did have any clients, its adjustment would be the
276 // one for the highest-priority of those processes.
277 static int CONTENT_PROVIDER_ADJ;
278
279 // This is a process only hosting activities that are not visible,
280 // so it can be killed without any disruption. Value set in
281 // system/rootdir/init.rc on startup.
282 final int HIDDEN_APP_MAX_ADJ;
283 static int HIDDEN_APP_MIN_ADJ;
284
The Android Open Source Project4df24232009-03-05 14:34:35 -0800285 // This is a process holding the home application -- we want to try
286 // avoiding killing it, even if it would normally be in the background,
287 // because the user interacts with it so much.
288 final int HOME_APP_ADJ;
289
Christopher Tate6fa95972009-06-05 18:43:55 -0700290 // This is a process currently hosting a backup operation. Killing it
291 // is not entirely fatal but is generally a bad idea.
292 final int BACKUP_APP_ADJ;
293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 // This is a process holding a secondary server -- killing it will not
295 // have much of an impact as far as the user is concerned. Value set in
296 // system/rootdir/init.rc on startup.
297 final int SECONDARY_SERVER_ADJ;
298
299 // This is a process only hosting activities that are visible to the
300 // user, so we'd prefer they don't disappear. Value set in
301 // system/rootdir/init.rc on startup.
302 final int VISIBLE_APP_ADJ;
303
304 // This is the process running the current foreground app. We'd really
305 // rather not kill it! Value set in system/rootdir/init.rc on startup.
306 final int FOREGROUND_APP_ADJ;
307
308 // This is a process running a core server, such as telephony. Definitely
309 // don't want to kill it, but doing so is not completely fatal.
310 static final int CORE_SERVER_ADJ = -12;
311
312 // The system process runs at the default adjustment.
313 static final int SYSTEM_ADJ = -16;
314
315 // Memory pages are 4K.
316 static final int PAGE_SIZE = 4*1024;
317
Jacek Surazski82a73df2009-06-17 14:33:18 +0200318 // System property defining error report receiver for system apps
319 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
320
321 // System property defining default error report receiver
322 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 // Corresponding memory levels for above adjustments.
325 final int EMPTY_APP_MEM;
326 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800327 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700328 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 final int SECONDARY_SERVER_MEM;
330 final int VISIBLE_APP_MEM;
331 final int FOREGROUND_APP_MEM;
332
333 final int MY_PID;
334
335 static final String[] EMPTY_STRING_ARRAY = new String[0];
336
337 enum ActivityState {
338 INITIALIZING,
339 RESUMED,
340 PAUSING,
341 PAUSED,
342 STOPPING,
343 STOPPED,
344 FINISHING,
345 DESTROYING,
346 DESTROYED
347 }
348
349 /**
350 * The back history of all previous (and possibly still
351 * running) activities. It contains HistoryRecord objects.
352 */
353 final ArrayList mHistory = new ArrayList();
354
355 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700356 * Description of a request to start a new activity, which has been held
357 * due to app switches being disabled.
358 */
359 class PendingActivityLaunch {
360 HistoryRecord r;
361 HistoryRecord sourceRecord;
362 Uri[] grantedUriPermissions;
363 int grantedMode;
364 boolean onlyIfNeeded;
365 }
366
367 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
368 = new ArrayList<PendingActivityLaunch>();
369
370 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 * List of all active broadcasts that are to be executed immediately
372 * (without waiting for another broadcast to finish). Currently this only
373 * contains broadcasts to registered receivers, to avoid spinning up
374 * a bunch of processes to execute IntentReceiver components.
375 */
376 final ArrayList<BroadcastRecord> mParallelBroadcasts
377 = new ArrayList<BroadcastRecord>();
378
379 /**
380 * List of all active broadcasts that are to be executed one at a time.
381 * The object at the top of the list is the currently activity broadcasts;
382 * those after it are waiting for the top to finish..
383 */
384 final ArrayList<BroadcastRecord> mOrderedBroadcasts
385 = new ArrayList<BroadcastRecord>();
386
387 /**
388 * Set when we current have a BROADCAST_INTENT_MSG in flight.
389 */
390 boolean mBroadcastsScheduled = false;
391
392 /**
393 * Set to indicate whether to issue an onUserLeaving callback when a
394 * newly launched activity is being brought in front of us.
395 */
396 boolean mUserLeaving = false;
397
398 /**
399 * When we are in the process of pausing an activity, before starting the
400 * next one, this variable holds the activity that is currently being paused.
401 */
402 HistoryRecord mPausingActivity = null;
403
404 /**
405 * Current activity that is resumed, or null if there is none.
406 */
407 HistoryRecord mResumedActivity = null;
408
409 /**
410 * Activity we have told the window manager to have key focus.
411 */
412 HistoryRecord mFocusedActivity = null;
413
414 /**
415 * This is the last activity that we put into the paused state. This is
416 * used to determine if we need to do an activity transition while sleeping,
417 * when we normally hold the top activity paused.
418 */
419 HistoryRecord mLastPausedActivity = null;
420
421 /**
422 * List of activities that are waiting for a new activity
423 * to become visible before completing whatever operation they are
424 * supposed to do.
425 */
426 final ArrayList mWaitingVisibleActivities = new ArrayList();
427
428 /**
429 * List of activities that are ready to be stopped, but waiting
430 * for the next activity to settle down before doing so. It contains
431 * HistoryRecord objects.
432 */
433 final ArrayList<HistoryRecord> mStoppingActivities
434 = new ArrayList<HistoryRecord>();
435
436 /**
437 * List of intents that were used to start the most recent tasks.
438 */
439 final ArrayList<TaskRecord> mRecentTasks
440 = new ArrayList<TaskRecord>();
441
442 /**
443 * List of activities that are ready to be finished, but waiting
444 * for the previous activity to settle down before doing so. It contains
445 * HistoryRecord objects.
446 */
447 final ArrayList mFinishingActivities = new ArrayList();
448
449 /**
450 * All of the applications we currently have running organized by name.
451 * The keys are strings of the application package name (as
452 * returned by the package manager), and the keys are ApplicationRecord
453 * objects.
454 */
455 final ProcessMap<ProcessRecord> mProcessNames
456 = new ProcessMap<ProcessRecord>();
457
458 /**
459 * The last time that various processes have crashed.
460 */
461 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
462
463 /**
464 * Set of applications that we consider to be bad, and will reject
465 * incoming broadcasts from (which the user has no control over).
466 * Processes are added to this set when they have crashed twice within
467 * a minimum amount of time; they are removed from it when they are
468 * later restarted (hopefully due to some user action). The value is the
469 * time it was added to the list.
470 */
471 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
472
473 /**
474 * All of the processes we currently have running organized by pid.
475 * The keys are the pid running the application.
476 *
477 * <p>NOTE: This object is protected by its own lock, NOT the global
478 * activity manager lock!
479 */
480 final SparseArray<ProcessRecord> mPidsSelfLocked
481 = new SparseArray<ProcessRecord>();
482
483 /**
484 * All of the processes that have been forced to be foreground. The key
485 * is the pid of the caller who requested it (we hold a death
486 * link on it).
487 */
488 abstract class ForegroundToken implements IBinder.DeathRecipient {
489 int pid;
490 IBinder token;
491 }
492 final SparseArray<ForegroundToken> mForegroundProcesses
493 = new SparseArray<ForegroundToken>();
494
495 /**
496 * List of records for processes that someone had tried to start before the
497 * system was ready. We don't start them at that point, but ensure they
498 * are started by the time booting is complete.
499 */
500 final ArrayList<ProcessRecord> mProcessesOnHold
501 = new ArrayList<ProcessRecord>();
502
503 /**
504 * List of records for processes that we have started and are waiting
505 * for them to call back. This is really only needed when running in
506 * single processes mode, in which case we do not have a unique pid for
507 * each process.
508 */
509 final ArrayList<ProcessRecord> mStartingProcesses
510 = new ArrayList<ProcessRecord>();
511
512 /**
513 * List of persistent applications that are in the process
514 * of being started.
515 */
516 final ArrayList<ProcessRecord> mPersistentStartingProcesses
517 = new ArrayList<ProcessRecord>();
518
519 /**
520 * Processes that are being forcibly torn down.
521 */
522 final ArrayList<ProcessRecord> mRemovedProcesses
523 = new ArrayList<ProcessRecord>();
524
525 /**
526 * List of running applications, sorted by recent usage.
527 * The first entry in the list is the least recently used.
528 * It contains ApplicationRecord objects. This list does NOT include
529 * any persistent application records (since we never want to exit them).
530 */
531 final ArrayList<ProcessRecord> mLRUProcesses
532 = new ArrayList<ProcessRecord>();
533
534 /**
535 * List of processes that should gc as soon as things are idle.
536 */
537 final ArrayList<ProcessRecord> mProcessesToGc
538 = new ArrayList<ProcessRecord>();
539
540 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800541 * This is the process holding what we currently consider to be
542 * the "home" activity.
543 */
544 private ProcessRecord mHomeProcess;
545
546 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 * List of running activities, sorted by recent usage.
548 * The first entry in the list is the least recently used.
549 * It contains HistoryRecord objects.
550 */
551 private final ArrayList mLRUActivities = new ArrayList();
552
553 /**
554 * Set of PendingResultRecord objects that are currently active.
555 */
556 final HashSet mPendingResultRecords = new HashSet();
557
558 /**
559 * Set of IntentSenderRecord objects that are currently active.
560 */
561 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
562 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
563
564 /**
565 * Intent broadcast that we have tried to start, but are
566 * waiting for its application's process to be created. We only
567 * need one (instead of a list) because we always process broadcasts
568 * one at a time, so no others can be started while waiting for this
569 * one.
570 */
571 BroadcastRecord mPendingBroadcast = null;
572
573 /**
574 * Keeps track of all IIntentReceivers that have been registered for
575 * broadcasts. Hash keys are the receiver IBinder, hash value is
576 * a ReceiverList.
577 */
578 final HashMap mRegisteredReceivers = new HashMap();
579
580 /**
581 * Resolver for broadcast intents to registered receivers.
582 * Holds BroadcastFilter (subclass of IntentFilter).
583 */
584 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
585 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
586 @Override
587 protected boolean allowFilterResult(
588 BroadcastFilter filter, List<BroadcastFilter> dest) {
589 IBinder target = filter.receiverList.receiver.asBinder();
590 for (int i=dest.size()-1; i>=0; i--) {
591 if (dest.get(i).receiverList.receiver.asBinder() == target) {
592 return false;
593 }
594 }
595 return true;
596 }
597 };
598
599 /**
600 * State of all active sticky broadcasts. Keys are the action of the
601 * sticky Intent, values are an ArrayList of all broadcasted intents with
602 * that action (which should usually be one).
603 */
604 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
605 new HashMap<String, ArrayList<Intent>>();
606
607 /**
608 * All currently running services.
609 */
610 final HashMap<ComponentName, ServiceRecord> mServices =
611 new HashMap<ComponentName, ServiceRecord>();
612
613 /**
614 * All currently running services indexed by the Intent used to start them.
615 */
616 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
617 new HashMap<Intent.FilterComparison, ServiceRecord>();
618
619 /**
620 * All currently bound service connections. Keys are the IBinder of
621 * the client's IServiceConnection.
622 */
623 final HashMap<IBinder, ConnectionRecord> mServiceConnections
624 = new HashMap<IBinder, ConnectionRecord>();
625
626 /**
627 * List of services that we have been asked to start,
628 * but haven't yet been able to. It is used to hold start requests
629 * while waiting for their corresponding application thread to get
630 * going.
631 */
632 final ArrayList<ServiceRecord> mPendingServices
633 = new ArrayList<ServiceRecord>();
634
635 /**
636 * List of services that are scheduled to restart following a crash.
637 */
638 final ArrayList<ServiceRecord> mRestartingServices
639 = new ArrayList<ServiceRecord>();
640
641 /**
642 * List of services that are in the process of being stopped.
643 */
644 final ArrayList<ServiceRecord> mStoppingServices
645 = new ArrayList<ServiceRecord>();
646
647 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700648 * Backup/restore process management
649 */
650 String mBackupAppName = null;
651 BackupRecord mBackupTarget = null;
652
653 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 * List of PendingThumbnailsRecord objects of clients who are still
655 * waiting to receive all of the thumbnails for a task.
656 */
657 final ArrayList mPendingThumbnails = new ArrayList();
658
659 /**
660 * List of HistoryRecord objects that have been finished and must
661 * still report back to a pending thumbnail receiver.
662 */
663 final ArrayList mCancelledThumbnails = new ArrayList();
664
665 /**
666 * All of the currently running global content providers. Keys are a
667 * string containing the provider name and values are a
668 * ContentProviderRecord object containing the data about it. Note
669 * that a single provider may be published under multiple names, so
670 * there may be multiple entries here for a single one in mProvidersByClass.
671 */
672 final HashMap mProvidersByName = new HashMap();
673
674 /**
675 * All of the currently running global content providers. Keys are a
676 * string containing the provider's implementation class and values are a
677 * ContentProviderRecord object containing the data about it.
678 */
679 final HashMap mProvidersByClass = new HashMap();
680
681 /**
682 * List of content providers who have clients waiting for them. The
683 * application is currently being launched and the provider will be
684 * removed from this list once it is published.
685 */
686 final ArrayList mLaunchingProviders = new ArrayList();
687
688 /**
689 * Global set of specific Uri permissions that have been granted.
690 */
691 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
692 = new SparseArray<HashMap<Uri, UriPermission>>();
693
694 /**
695 * Thread-local storage used to carry caller permissions over through
696 * indirect content-provider access.
697 * @see #ActivityManagerService.openContentUri()
698 */
699 private class Identity {
700 public int pid;
701 public int uid;
702
703 Identity(int _pid, int _uid) {
704 pid = _pid;
705 uid = _uid;
706 }
707 }
708 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
709
710 /**
711 * All information we have collected about the runtime performance of
712 * any user id that can impact battery performance.
713 */
714 final BatteryStatsService mBatteryStatsService;
715
716 /**
717 * information about component usage
718 */
719 final UsageStatsService mUsageStatsService;
720
721 /**
722 * Current configuration information. HistoryRecord objects are given
723 * a reference to this object to indicate which configuration they are
724 * currently running in, so this object must be kept immutable.
725 */
726 Configuration mConfiguration = new Configuration();
727
728 /**
729 * List of initialization arguments to pass to all processes when binding applications to them.
730 * For example, references to the commonly used services.
731 */
732 HashMap<String, IBinder> mAppBindArgs;
733
734 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700735 * Temporary to avoid allocations. Protected by main lock.
736 */
737 final StringBuilder mStringBuilder = new StringBuilder(256);
738
739 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 * Used to control how we initialize the service.
741 */
742 boolean mStartRunning = false;
743 ComponentName mTopComponent;
744 String mTopAction;
745 String mTopData;
746 boolean mSystemReady = false;
747 boolean mBooting = false;
748
749 Context mContext;
750
751 int mFactoryTest;
752
753 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700754 * The time at which we will allow normal application switches again,
755 * after a call to {@link #stopAppSwitches()}.
756 */
757 long mAppSwitchesAllowedTime;
758
759 /**
760 * This is set to true after the first switch after mAppSwitchesAllowedTime
761 * is set; any switches after that will clear the time.
762 */
763 boolean mDidAppSwitch;
764
765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 * Set while we are wanting to sleep, to prevent any
767 * activities from being started/resumed.
768 */
769 boolean mSleeping = false;
770
771 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700772 * Set if we are shutting down the system, similar to sleeping.
773 */
774 boolean mShuttingDown = false;
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Set when the system is going to sleep, until we have
778 * successfully paused the current activity and released our wake lock.
779 * At that point the system is allowed to actually sleep.
780 */
781 PowerManager.WakeLock mGoingToSleep;
782
783 /**
784 * We don't want to allow the device to go to sleep while in the process
785 * of launching an activity. This is primarily to allow alarm intent
786 * receivers to launch an activity and get that to run before the device
787 * goes back to sleep.
788 */
789 PowerManager.WakeLock mLaunchingActivity;
790
791 /**
792 * Task identifier that activities are currently being started
793 * in. Incremented each time a new task is created.
794 * todo: Replace this with a TokenSpace class that generates non-repeating
795 * integers that won't wrap.
796 */
797 int mCurTask = 1;
798
799 /**
800 * Current sequence id for oom_adj computation traversal.
801 */
802 int mAdjSeq = 0;
803
804 /**
805 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
806 * is set, indicating the user wants processes started in such a way
807 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
808 * running in each process (thus no pre-initialized process, etc).
809 */
810 boolean mSimpleProcessManagement = false;
811
812 /**
813 * System monitoring: number of processes that died since the last
814 * N procs were started.
815 */
816 int[] mProcDeaths = new int[20];
817
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700818 /**
819 * This is set if we had to do a delayed dexopt of an app before launching
820 * it, to increasing the ANR timeouts in that case.
821 */
822 boolean mDidDexOpt;
823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 String mDebugApp = null;
825 boolean mWaitForDebugger = false;
826 boolean mDebugTransient = false;
827 String mOrigDebugApp = null;
828 boolean mOrigWaitForDebugger = false;
829 boolean mAlwaysFinishActivities = false;
830 IActivityWatcher mWatcher = null;
831
832 /**
833 * Callback of last caller to {@link #requestPss}.
834 */
835 Runnable mRequestPssCallback;
836
837 /**
838 * Remaining processes for which we are waiting results from the last
839 * call to {@link #requestPss}.
840 */
841 final ArrayList<ProcessRecord> mRequestPssList
842 = new ArrayList<ProcessRecord>();
843
844 /**
845 * Runtime statistics collection thread. This object's lock is used to
846 * protect all related state.
847 */
848 final Thread mProcessStatsThread;
849
850 /**
851 * Used to collect process stats when showing not responding dialog.
852 * Protected by mProcessStatsThread.
853 */
854 final ProcessStats mProcessStats = new ProcessStats(
855 MONITOR_THREAD_CPU_USAGE);
856 long mLastCpuTime = 0;
857 long mLastWriteTime = 0;
858
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700859 long mInitialStartTime = 0;
860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 /**
862 * Set to true after the system has finished booting.
863 */
864 boolean mBooted = false;
865
866 int mProcessLimit = 0;
867
868 WindowManagerService mWindowManager;
869
870 static ActivityManagerService mSelf;
871 static ActivityThread mSystemThread;
872
873 private final class AppDeathRecipient implements IBinder.DeathRecipient {
874 final ProcessRecord mApp;
875 final int mPid;
876 final IApplicationThread mAppThread;
877
878 AppDeathRecipient(ProcessRecord app, int pid,
879 IApplicationThread thread) {
880 if (localLOGV) Log.v(
881 TAG, "New death recipient " + this
882 + " for thread " + thread.asBinder());
883 mApp = app;
884 mPid = pid;
885 mAppThread = thread;
886 }
887
888 public void binderDied() {
889 if (localLOGV) Log.v(
890 TAG, "Death received in " + this
891 + " for thread " + mAppThread.asBinder());
892 removeRequestedPss(mApp);
893 synchronized(ActivityManagerService.this) {
894 appDiedLocked(mApp, mPid, mAppThread);
895 }
896 }
897 }
898
899 static final int SHOW_ERROR_MSG = 1;
900 static final int SHOW_NOT_RESPONDING_MSG = 2;
901 static final int SHOW_FACTORY_ERROR_MSG = 3;
902 static final int UPDATE_CONFIGURATION_MSG = 4;
903 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
904 static final int WAIT_FOR_DEBUGGER_MSG = 6;
905 static final int BROADCAST_INTENT_MSG = 7;
906 static final int BROADCAST_TIMEOUT_MSG = 8;
907 static final int PAUSE_TIMEOUT_MSG = 9;
908 static final int IDLE_TIMEOUT_MSG = 10;
909 static final int IDLE_NOW_MSG = 11;
910 static final int SERVICE_TIMEOUT_MSG = 12;
911 static final int UPDATE_TIME_ZONE = 13;
912 static final int SHOW_UID_ERROR_MSG = 14;
913 static final int IM_FEELING_LUCKY_MSG = 15;
914 static final int LAUNCH_TIMEOUT_MSG = 16;
915 static final int DESTROY_TIMEOUT_MSG = 17;
916 static final int SERVICE_ERROR_MSG = 18;
917 static final int RESUME_TOP_ACTIVITY_MSG = 19;
918 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700919 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920
921 AlertDialog mUidAlert;
922
923 final Handler mHandler = new Handler() {
924 //public Handler() {
925 // if (localLOGV) Log.v(TAG, "Handler started!");
926 //}
927
928 public void handleMessage(Message msg) {
929 switch (msg.what) {
930 case SHOW_ERROR_MSG: {
931 HashMap data = (HashMap) msg.obj;
932 byte[] crashData = (byte[])data.get("crashData");
933 if (crashData != null) {
934 // This needs to be *un*synchronized to avoid deadlock.
935 ContentResolver resolver = mContext.getContentResolver();
936 Checkin.reportCrash(resolver, crashData);
937 }
938 synchronized (ActivityManagerService.this) {
939 ProcessRecord proc = (ProcessRecord)data.get("app");
940 if (proc != null && proc.crashDialog != null) {
941 Log.e(TAG, "App already has crash dialog: " + proc);
942 return;
943 }
944 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700945 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 Dialog d = new AppErrorDialog(
947 mContext, res, proc,
948 (Integer)data.get("flags"),
949 (String)data.get("shortMsg"),
950 (String)data.get("longMsg"));
951 d.show();
952 proc.crashDialog = d;
953 } else {
954 // The device is asleep, so just pretend that the user
955 // saw a crash dialog and hit "force quit".
956 res.set(0);
957 }
958 }
959 } break;
960 case SHOW_NOT_RESPONDING_MSG: {
961 synchronized (ActivityManagerService.this) {
962 HashMap data = (HashMap) msg.obj;
963 ProcessRecord proc = (ProcessRecord)data.get("app");
964 if (proc != null && proc.anrDialog != null) {
965 Log.e(TAG, "App already has anr dialog: " + proc);
966 return;
967 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800968
969 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
970 null, null, 0, null, null, null,
971 false, false, MY_PID, Process.SYSTEM_UID);
972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
974 mContext, proc, (HistoryRecord)data.get("activity"));
975 d.show();
976 proc.anrDialog = d;
977 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700978
979 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 } break;
981 case SHOW_FACTORY_ERROR_MSG: {
982 Dialog d = new FactoryErrorDialog(
983 mContext, msg.getData().getCharSequence("msg"));
984 d.show();
985 enableScreenAfterBoot();
986 } break;
987 case UPDATE_CONFIGURATION_MSG: {
988 final ContentResolver resolver = mContext.getContentResolver();
989 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
990 } break;
991 case GC_BACKGROUND_PROCESSES_MSG: {
992 synchronized (ActivityManagerService.this) {
993 performAppGcsIfAppropriateLocked();
994 }
995 } break;
996 case WAIT_FOR_DEBUGGER_MSG: {
997 synchronized (ActivityManagerService.this) {
998 ProcessRecord app = (ProcessRecord)msg.obj;
999 if (msg.arg1 != 0) {
1000 if (!app.waitedForDebugger) {
1001 Dialog d = new AppWaitingForDebuggerDialog(
1002 ActivityManagerService.this,
1003 mContext, app);
1004 app.waitDialog = d;
1005 app.waitedForDebugger = true;
1006 d.show();
1007 }
1008 } else {
1009 if (app.waitDialog != null) {
1010 app.waitDialog.dismiss();
1011 app.waitDialog = null;
1012 }
1013 }
1014 }
1015 } break;
1016 case BROADCAST_INTENT_MSG: {
1017 if (DEBUG_BROADCAST) Log.v(
1018 TAG, "Received BROADCAST_INTENT_MSG");
1019 processNextBroadcast(true);
1020 } break;
1021 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001022 if (mDidDexOpt) {
1023 mDidDexOpt = false;
1024 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1025 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1026 return;
1027 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 broadcastTimeout();
1029 } break;
1030 case PAUSE_TIMEOUT_MSG: {
1031 IBinder token = (IBinder)msg.obj;
1032 // We don't at this point know if the activity is fullscreen,
1033 // so we need to be conservative and assume it isn't.
1034 Log.w(TAG, "Activity pause timeout for " + token);
1035 activityPaused(token, null, true);
1036 } break;
1037 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001038 if (mDidDexOpt) {
1039 mDidDexOpt = false;
1040 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1041 nmsg.obj = msg.obj;
1042 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1043 return;
1044 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 // We don't at this point know if the activity is fullscreen,
1046 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001047 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 Log.w(TAG, "Activity idle timeout for " + token);
1049 activityIdleInternal(token, true);
1050 } break;
1051 case DESTROY_TIMEOUT_MSG: {
1052 IBinder token = (IBinder)msg.obj;
1053 // We don't at this point know if the activity is fullscreen,
1054 // so we need to be conservative and assume it isn't.
1055 Log.w(TAG, "Activity destroy timeout for " + token);
1056 activityDestroyed(token);
1057 } break;
1058 case IDLE_NOW_MSG: {
1059 IBinder token = (IBinder)msg.obj;
1060 activityIdle(token);
1061 } break;
1062 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001063 if (mDidDexOpt) {
1064 mDidDexOpt = false;
1065 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1066 nmsg.obj = msg.obj;
1067 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1068 return;
1069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 serviceTimeout((ProcessRecord)msg.obj);
1071 } break;
1072 case UPDATE_TIME_ZONE: {
1073 synchronized (ActivityManagerService.this) {
1074 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1075 ProcessRecord r = mLRUProcesses.get(i);
1076 if (r.thread != null) {
1077 try {
1078 r.thread.updateTimeZone();
1079 } catch (RemoteException ex) {
1080 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1081 }
1082 }
1083 }
1084 }
1085 break;
1086 }
1087 case SHOW_UID_ERROR_MSG: {
1088 // XXX This is a temporary dialog, no need to localize.
1089 AlertDialog d = new BaseErrorDialog(mContext);
1090 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1091 d.setCancelable(false);
1092 d.setTitle("System UIDs Inconsistent");
1093 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1094 d.setButton("I'm Feeling Lucky",
1095 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1096 mUidAlert = d;
1097 d.show();
1098 } break;
1099 case IM_FEELING_LUCKY_MSG: {
1100 if (mUidAlert != null) {
1101 mUidAlert.dismiss();
1102 mUidAlert = null;
1103 }
1104 } break;
1105 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001106 if (mDidDexOpt) {
1107 mDidDexOpt = false;
1108 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1109 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1110 return;
1111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 synchronized (ActivityManagerService.this) {
1113 if (mLaunchingActivity.isHeld()) {
1114 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1115 mLaunchingActivity.release();
1116 }
1117 }
1118 } break;
1119 case SERVICE_ERROR_MSG: {
1120 ServiceRecord srv = (ServiceRecord)msg.obj;
1121 // This needs to be *un*synchronized to avoid deadlock.
1122 Checkin.logEvent(mContext.getContentResolver(),
1123 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1124 srv.name.toShortString());
1125 } break;
1126 case RESUME_TOP_ACTIVITY_MSG: {
1127 synchronized (ActivityManagerService.this) {
1128 resumeTopActivityLocked(null);
1129 }
1130 }
1131 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001132 if (mDidDexOpt) {
1133 mDidDexOpt = false;
1134 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1135 nmsg.obj = msg.obj;
1136 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1137 return;
1138 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 ProcessRecord app = (ProcessRecord)msg.obj;
1140 synchronized (ActivityManagerService.this) {
1141 processStartTimedOutLocked(app);
1142 }
1143 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001144 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1145 synchronized (ActivityManagerService.this) {
1146 doPendingActivityLaunchesLocked(true);
1147 }
1148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 }
1150 }
1151 };
1152
1153 public static void setSystemProcess() {
1154 try {
1155 ActivityManagerService m = mSelf;
1156
1157 ServiceManager.addService("activity", m);
1158 ServiceManager.addService("meminfo", new MemBinder(m));
1159 if (MONITOR_CPU_USAGE) {
1160 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1161 }
1162 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1163 ServiceManager.addService("activity.services", new ServicesBinder(m));
1164 ServiceManager.addService("activity.senders", new SendersBinder(m));
1165 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1166 ServiceManager.addService("permission", new PermissionController(m));
1167
1168 ApplicationInfo info =
1169 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001170 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 synchronized (mSelf) {
1172 ProcessRecord app = mSelf.newProcessRecordLocked(
1173 mSystemThread.getApplicationThread(), info,
1174 info.processName);
1175 app.persistent = true;
1176 app.pid = Process.myPid();
1177 app.maxAdj = SYSTEM_ADJ;
1178 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1179 synchronized (mSelf.mPidsSelfLocked) {
1180 mSelf.mPidsSelfLocked.put(app.pid, app);
1181 }
1182 mSelf.updateLRUListLocked(app, true);
1183 }
1184 } catch (PackageManager.NameNotFoundException e) {
1185 throw new RuntimeException(
1186 "Unable to find android system package", e);
1187 }
1188 }
1189
1190 public void setWindowManager(WindowManagerService wm) {
1191 mWindowManager = wm;
1192 }
1193
1194 public static final Context main(int factoryTest) {
1195 AThread thr = new AThread();
1196 thr.start();
1197
1198 synchronized (thr) {
1199 while (thr.mService == null) {
1200 try {
1201 thr.wait();
1202 } catch (InterruptedException e) {
1203 }
1204 }
1205 }
1206
1207 ActivityManagerService m = thr.mService;
1208 mSelf = m;
1209 ActivityThread at = ActivityThread.systemMain();
1210 mSystemThread = at;
1211 Context context = at.getSystemContext();
1212 m.mContext = context;
1213 m.mFactoryTest = factoryTest;
1214 PowerManager pm =
1215 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1216 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1217 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1218 m.mLaunchingActivity.setReferenceCounted(false);
1219
1220 m.mBatteryStatsService.publish(context);
1221 m.mUsageStatsService.publish(context);
1222
1223 synchronized (thr) {
1224 thr.mReady = true;
1225 thr.notifyAll();
1226 }
1227
1228 m.startRunning(null, null, null, null);
1229
1230 return context;
1231 }
1232
1233 public static ActivityManagerService self() {
1234 return mSelf;
1235 }
1236
1237 static class AThread extends Thread {
1238 ActivityManagerService mService;
1239 boolean mReady = false;
1240
1241 public AThread() {
1242 super("ActivityManager");
1243 }
1244
1245 public void run() {
1246 Looper.prepare();
1247
1248 android.os.Process.setThreadPriority(
1249 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1250
1251 ActivityManagerService m = new ActivityManagerService();
1252
1253 synchronized (this) {
1254 mService = m;
1255 notifyAll();
1256 }
1257
1258 synchronized (this) {
1259 while (!mReady) {
1260 try {
1261 wait();
1262 } catch (InterruptedException e) {
1263 }
1264 }
1265 }
1266
1267 Looper.loop();
1268 }
1269 }
1270
1271 static class BroadcastsBinder extends Binder {
1272 ActivityManagerService mActivityManagerService;
1273 BroadcastsBinder(ActivityManagerService activityManagerService) {
1274 mActivityManagerService = activityManagerService;
1275 }
1276
1277 @Override
1278 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1279 mActivityManagerService.dumpBroadcasts(pw);
1280 }
1281 }
1282
1283 static class ServicesBinder extends Binder {
1284 ActivityManagerService mActivityManagerService;
1285 ServicesBinder(ActivityManagerService activityManagerService) {
1286 mActivityManagerService = activityManagerService;
1287 }
1288
1289 @Override
1290 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1291 mActivityManagerService.dumpServices(pw);
1292 }
1293 }
1294
1295 static class SendersBinder extends Binder {
1296 ActivityManagerService mActivityManagerService;
1297 SendersBinder(ActivityManagerService activityManagerService) {
1298 mActivityManagerService = activityManagerService;
1299 }
1300
1301 @Override
1302 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1303 mActivityManagerService.dumpSenders(pw);
1304 }
1305 }
1306
1307 static class ProvidersBinder extends Binder {
1308 ActivityManagerService mActivityManagerService;
1309 ProvidersBinder(ActivityManagerService activityManagerService) {
1310 mActivityManagerService = activityManagerService;
1311 }
1312
1313 @Override
1314 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1315 mActivityManagerService.dumpProviders(pw);
1316 }
1317 }
1318
1319 static class MemBinder extends Binder {
1320 ActivityManagerService mActivityManagerService;
1321 MemBinder(ActivityManagerService activityManagerService) {
1322 mActivityManagerService = activityManagerService;
1323 }
1324
1325 @Override
1326 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1327 ActivityManagerService service = mActivityManagerService;
1328 ArrayList<ProcessRecord> procs;
1329 synchronized (mActivityManagerService) {
1330 if (args != null && args.length > 0
1331 && args[0].charAt(0) != '-') {
1332 procs = new ArrayList<ProcessRecord>();
1333 int pid = -1;
1334 try {
1335 pid = Integer.parseInt(args[0]);
1336 } catch (NumberFormatException e) {
1337
1338 }
1339 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1340 ProcessRecord proc = service.mLRUProcesses.get(i);
1341 if (proc.pid == pid) {
1342 procs.add(proc);
1343 } else if (proc.processName.equals(args[0])) {
1344 procs.add(proc);
1345 }
1346 }
1347 if (procs.size() <= 0) {
1348 pw.println("No process found for: " + args[0]);
1349 return;
1350 }
1351 } else {
1352 procs = service.mLRUProcesses;
1353 }
1354 }
1355 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1356 }
1357 }
1358
1359 static class CpuBinder extends Binder {
1360 ActivityManagerService mActivityManagerService;
1361 CpuBinder(ActivityManagerService activityManagerService) {
1362 mActivityManagerService = activityManagerService;
1363 }
1364
1365 @Override
1366 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1367 synchronized (mActivityManagerService.mProcessStatsThread) {
1368 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1369 }
1370 }
1371 }
1372
1373 private ActivityManagerService() {
1374 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1375 if (v != null && Integer.getInteger(v) != 0) {
1376 mSimpleProcessManagement = true;
1377 }
1378 v = System.getenv("ANDROID_DEBUG_APP");
1379 if (v != null) {
1380 mSimpleProcessManagement = true;
1381 }
1382
1383 MY_PID = Process.myPid();
1384
1385 File dataDir = Environment.getDataDirectory();
1386 File systemDir = new File(dataDir, "system");
1387 systemDir.mkdirs();
1388 mBatteryStatsService = new BatteryStatsService(new File(
1389 systemDir, "batterystats.bin").toString());
1390 mBatteryStatsService.getActiveStatistics().readLocked();
1391 mBatteryStatsService.getActiveStatistics().writeLocked();
1392
1393 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001394 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395
1396 mConfiguration.makeDefault();
1397 mProcessStats.init();
1398
1399 // Add ourself to the Watchdog monitors.
1400 Watchdog.getInstance().addMonitor(this);
1401
1402 // These values are set in system/rootdir/init.rc on startup.
1403 FOREGROUND_APP_ADJ =
1404 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1405 VISIBLE_APP_ADJ =
1406 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1407 SECONDARY_SERVER_ADJ =
1408 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001409 BACKUP_APP_ADJ =
1410 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001411 HOME_APP_ADJ =
1412 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 HIDDEN_APP_MIN_ADJ =
1414 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1415 CONTENT_PROVIDER_ADJ =
1416 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1417 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1418 EMPTY_APP_ADJ =
1419 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1420 FOREGROUND_APP_MEM =
1421 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1422 VISIBLE_APP_MEM =
1423 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1424 SECONDARY_SERVER_MEM =
1425 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001426 BACKUP_APP_MEM =
1427 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001428 HOME_APP_MEM =
1429 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 HIDDEN_APP_MEM =
1431 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1432 EMPTY_APP_MEM =
1433 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1434
1435 mProcessStatsThread = new Thread("ProcessStats") {
1436 public void run() {
1437 while (true) {
1438 try {
1439 try {
1440 synchronized(this) {
1441 final long now = SystemClock.uptimeMillis();
1442 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1443 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1444 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1445 // + ", write delay=" + nextWriteDelay);
1446 if (nextWriteDelay < nextCpuDelay) {
1447 nextCpuDelay = nextWriteDelay;
1448 }
1449 if (nextCpuDelay > 0) {
1450 this.wait(nextCpuDelay);
1451 }
1452 }
1453 } catch (InterruptedException e) {
1454 }
1455
1456 updateCpuStatsNow();
1457 } catch (Exception e) {
1458 Log.e(TAG, "Unexpected exception collecting process stats", e);
1459 }
1460 }
1461 }
1462 };
1463 mProcessStatsThread.start();
1464 }
1465
1466 @Override
1467 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1468 throws RemoteException {
1469 try {
1470 return super.onTransact(code, data, reply, flags);
1471 } catch (RuntimeException e) {
1472 // The activity manager only throws security exceptions, so let's
1473 // log all others.
1474 if (!(e instanceof SecurityException)) {
1475 Log.e(TAG, "Activity Manager Crash", e);
1476 }
1477 throw e;
1478 }
1479 }
1480
1481 void updateCpuStats() {
1482 synchronized (mProcessStatsThread) {
1483 final long now = SystemClock.uptimeMillis();
1484 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1485 mProcessStatsThread.notify();
1486 }
1487 }
1488 }
1489
1490 void updateCpuStatsNow() {
1491 synchronized (mProcessStatsThread) {
1492 final long now = SystemClock.uptimeMillis();
1493 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 if (MONITOR_CPU_USAGE &&
1496 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1497 mLastCpuTime = now;
1498 haveNewCpuStats = true;
1499 mProcessStats.update();
1500 //Log.i(TAG, mProcessStats.printCurrentState());
1501 //Log.i(TAG, "Total CPU usage: "
1502 // + mProcessStats.getTotalCpuPercent() + "%");
1503
1504 // Log the cpu usage if the property is set.
1505 if ("true".equals(SystemProperties.get("events.cpu"))) {
1506 int user = mProcessStats.getLastUserTime();
1507 int system = mProcessStats.getLastSystemTime();
1508 int iowait = mProcessStats.getLastIoWaitTime();
1509 int irq = mProcessStats.getLastIrqTime();
1510 int softIrq = mProcessStats.getLastSoftIrqTime();
1511 int idle = mProcessStats.getLastIdleTime();
1512
1513 int total = user + system + iowait + irq + softIrq + idle;
1514 if (total == 0) total = 1;
1515
1516 EventLog.writeEvent(LOG_CPU,
1517 ((user+system+iowait+irq+softIrq) * 100) / total,
1518 (user * 100) / total,
1519 (system * 100) / total,
1520 (iowait * 100) / total,
1521 (irq * 100) / total,
1522 (softIrq * 100) / total);
1523 }
1524 }
1525
1526 synchronized(mBatteryStatsService.getActiveStatistics()) {
1527 synchronized(mPidsSelfLocked) {
1528 if (haveNewCpuStats) {
1529 if (mBatteryStatsService.isOnBattery()) {
1530 final int N = mProcessStats.countWorkingStats();
1531 for (int i=0; i<N; i++) {
1532 ProcessStats.Stats st
1533 = mProcessStats.getWorkingStats(i);
1534 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1535 if (pr != null) {
1536 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1537 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1538 }
1539 }
1540 }
1541 }
1542 }
1543
1544 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1545 mLastWriteTime = now;
1546 mBatteryStatsService.getActiveStatistics().writeLocked();
1547 }
1548 }
1549 }
1550 }
1551
1552 /**
1553 * Initialize the application bind args. These are passed to each
1554 * process when the bindApplication() IPC is sent to the process. They're
1555 * lazily setup to make sure the services are running when they're asked for.
1556 */
1557 private HashMap<String, IBinder> getCommonServicesLocked() {
1558 if (mAppBindArgs == null) {
1559 mAppBindArgs = new HashMap<String, IBinder>();
1560
1561 // Setup the application init args
1562 mAppBindArgs.put("package", ServiceManager.getService("package"));
1563 mAppBindArgs.put("window", ServiceManager.getService("window"));
1564 mAppBindArgs.put(Context.ALARM_SERVICE,
1565 ServiceManager.getService(Context.ALARM_SERVICE));
1566 }
1567 return mAppBindArgs;
1568 }
1569
1570 private final void setFocusedActivityLocked(HistoryRecord r) {
1571 if (mFocusedActivity != r) {
1572 mFocusedActivity = r;
1573 mWindowManager.setFocusedApp(r, true);
1574 }
1575 }
1576
1577 private final void updateLRUListLocked(ProcessRecord app,
1578 boolean oomAdj) {
1579 // put it on the LRU to keep track of when it should be exited.
1580 int lrui = mLRUProcesses.indexOf(app);
1581 if (lrui >= 0) mLRUProcesses.remove(lrui);
1582 mLRUProcesses.add(app);
1583 //Log.i(TAG, "Putting proc to front: " + app.processName);
1584 if (oomAdj) {
1585 updateOomAdjLocked();
1586 }
1587 }
1588
1589 private final boolean updateLRUListLocked(HistoryRecord r) {
1590 final boolean hadit = mLRUActivities.remove(r);
1591 mLRUActivities.add(r);
1592 return hadit;
1593 }
1594
1595 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1596 int i = mHistory.size()-1;
1597 while (i >= 0) {
1598 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1599 if (!r.finishing && r != notTop) {
1600 return r;
1601 }
1602 i--;
1603 }
1604 return null;
1605 }
1606
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001607 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1608 int i = mHistory.size()-1;
1609 while (i >= 0) {
1610 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1611 if (!r.finishing && !r.delayedResume && r != notTop) {
1612 return r;
1613 }
1614 i--;
1615 }
1616 return null;
1617 }
1618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 /**
1620 * This is a simplified version of topRunningActivityLocked that provides a number of
1621 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1622 *
1623 * @param token If non-null, any history records matching this token will be skipped.
1624 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1625 *
1626 * @return Returns the HistoryRecord of the next activity on the stack.
1627 */
1628 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1629 int i = mHistory.size()-1;
1630 while (i >= 0) {
1631 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1632 // Note: the taskId check depends on real taskId fields being non-zero
1633 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1634 return r;
1635 }
1636 i--;
1637 }
1638 return null;
1639 }
1640
1641 private final ProcessRecord getProcessRecordLocked(
1642 String processName, int uid) {
1643 if (uid == Process.SYSTEM_UID) {
1644 // The system gets to run in any process. If there are multiple
1645 // processes with the same uid, just pick the first (this
1646 // should never happen).
1647 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1648 processName);
1649 return procs != null ? procs.valueAt(0) : null;
1650 }
1651 ProcessRecord proc = mProcessNames.get(processName, uid);
1652 return proc;
1653 }
1654
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001655 private void ensurePackageDexOpt(String packageName) {
1656 IPackageManager pm = ActivityThread.getPackageManager();
1657 try {
1658 if (pm.performDexOpt(packageName)) {
1659 mDidDexOpt = true;
1660 }
1661 } catch (RemoteException e) {
1662 }
1663 }
1664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 private boolean isNextTransitionForward() {
1666 int transit = mWindowManager.getPendingAppTransition();
1667 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1668 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1669 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1670 }
1671
1672 private final boolean realStartActivityLocked(HistoryRecord r,
1673 ProcessRecord app, boolean andResume, boolean checkConfig)
1674 throws RemoteException {
1675
1676 r.startFreezingScreenLocked(app, 0);
1677 mWindowManager.setAppVisibility(r, true);
1678
1679 // Have the window manager re-evaluate the orientation of
1680 // the screen based on the new activity order. Note that
1681 // as a result of this, it can call back into the activity
1682 // manager with a new orientation. We don't care about that,
1683 // because the activity is not currently running so we are
1684 // just restarting it anyway.
1685 if (checkConfig) {
1686 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001687 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 r.mayFreezeScreenLocked(app) ? r : null);
1689 updateConfigurationLocked(config, r);
1690 }
1691
1692 r.app = app;
1693
1694 if (localLOGV) Log.v(TAG, "Launching: " + r);
1695
1696 int idx = app.activities.indexOf(r);
1697 if (idx < 0) {
1698 app.activities.add(r);
1699 }
1700 updateLRUListLocked(app, true);
1701
1702 try {
1703 if (app.thread == null) {
1704 throw new RemoteException();
1705 }
1706 List<ResultInfo> results = null;
1707 List<Intent> newIntents = null;
1708 if (andResume) {
1709 results = r.results;
1710 newIntents = r.newIntents;
1711 }
1712 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1713 + " icicle=" + r.icicle
1714 + " with results=" + results + " newIntents=" + newIntents
1715 + " andResume=" + andResume);
1716 if (andResume) {
1717 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1718 System.identityHashCode(r),
1719 r.task.taskId, r.shortComponentName);
1720 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001721 if (r.isHomeActivity) {
1722 mHomeProcess = app;
1723 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001724 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1726 r.info, r.icicle, results, newIntents, !andResume,
1727 isNextTransitionForward());
1728 // Update usage stats for launched activity
1729 updateUsageStats(r, true);
1730 } catch (RemoteException e) {
1731 if (r.launchFailed) {
1732 // This is the second time we failed -- finish activity
1733 // and give up.
1734 Log.e(TAG, "Second failure launching "
1735 + r.intent.getComponent().flattenToShortString()
1736 + ", giving up", e);
1737 appDiedLocked(app, app.pid, app.thread);
1738 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1739 "2nd-crash");
1740 return false;
1741 }
1742
1743 // This is the first time we failed -- restart process and
1744 // retry.
1745 app.activities.remove(r);
1746 throw e;
1747 }
1748
1749 r.launchFailed = false;
1750 if (updateLRUListLocked(r)) {
1751 Log.w(TAG, "Activity " + r
1752 + " being launched, but already in LRU list");
1753 }
1754
1755 if (andResume) {
1756 // As part of the process of launching, ActivityThread also performs
1757 // a resume.
1758 r.state = ActivityState.RESUMED;
1759 r.icicle = null;
1760 r.haveState = false;
1761 r.stopped = false;
1762 mResumedActivity = r;
1763 r.task.touchActiveTime();
1764 completeResumeLocked(r);
1765 pauseIfSleepingLocked();
1766 } else {
1767 // This activity is not starting in the resumed state... which
1768 // should look like we asked it to pause+stop (but remain visible),
1769 // and it has done so and reported back the current icicle and
1770 // other state.
1771 r.state = ActivityState.STOPPED;
1772 r.stopped = true;
1773 }
1774
1775 return true;
1776 }
1777
1778 private final void startSpecificActivityLocked(HistoryRecord r,
1779 boolean andResume, boolean checkConfig) {
1780 // Is this activity's application already running?
1781 ProcessRecord app = getProcessRecordLocked(r.processName,
1782 r.info.applicationInfo.uid);
1783
1784 if (r.startTime == 0) {
1785 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001786 if (mInitialStartTime == 0) {
1787 mInitialStartTime = r.startTime;
1788 }
1789 } else if (mInitialStartTime == 0) {
1790 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 }
1792
1793 if (app != null && app.thread != null) {
1794 try {
1795 realStartActivityLocked(r, app, andResume, checkConfig);
1796 return;
1797 } catch (RemoteException e) {
1798 Log.w(TAG, "Exception when starting activity "
1799 + r.intent.getComponent().flattenToShortString(), e);
1800 }
1801
1802 // If a dead object exception was thrown -- fall through to
1803 // restart the application.
1804 }
1805
1806 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1807 "activity", r.intent.getComponent());
1808 }
1809
1810 private final ProcessRecord startProcessLocked(String processName,
1811 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1812 String hostingType, ComponentName hostingName) {
1813 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1814 // We don't have to do anything more if:
1815 // (1) There is an existing application record; and
1816 // (2) The caller doesn't think it is dead, OR there is no thread
1817 // object attached to it so we know it couldn't have crashed; and
1818 // (3) There is a pid assigned to it, so it is either starting or
1819 // already running.
1820 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1821 + " app=" + app + " knownToBeDead=" + knownToBeDead
1822 + " thread=" + (app != null ? app.thread : null)
1823 + " pid=" + (app != null ? app.pid : -1));
1824 if (app != null &&
1825 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1826 return app;
1827 }
1828
1829 String hostingNameStr = hostingName != null
1830 ? hostingName.flattenToShortString() : null;
1831
1832 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1833 // If we are in the background, then check to see if this process
1834 // is bad. If so, we will just silently fail.
1835 if (mBadProcesses.get(info.processName, info.uid) != null) {
1836 return null;
1837 }
1838 } else {
1839 // When the user is explicitly starting a process, then clear its
1840 // crash count so that we won't make it bad until they see at
1841 // least one crash dialog again, and make the process good again
1842 // if it had been bad.
1843 mProcessCrashTimes.remove(info.processName, info.uid);
1844 if (mBadProcesses.get(info.processName, info.uid) != null) {
1845 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1846 info.processName);
1847 mBadProcesses.remove(info.processName, info.uid);
1848 if (app != null) {
1849 app.bad = false;
1850 }
1851 }
1852 }
1853
1854 if (app == null) {
1855 app = newProcessRecordLocked(null, info, processName);
1856 mProcessNames.put(processName, info.uid, app);
1857 } else {
1858 // If this is a new package in the process, add the package to the list
1859 app.addPackage(info.packageName);
1860 }
1861
1862 // If the system is not ready yet, then hold off on starting this
1863 // process until it is.
1864 if (!mSystemReady
1865 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1866 if (!mProcessesOnHold.contains(app)) {
1867 mProcessesOnHold.add(app);
1868 }
1869 return app;
1870 }
1871
1872 startProcessLocked(app, hostingType, hostingNameStr);
1873 return (app.pid != 0) ? app : null;
1874 }
1875
1876 private final void startProcessLocked(ProcessRecord app,
1877 String hostingType, String hostingNameStr) {
1878 if (app.pid > 0 && app.pid != MY_PID) {
1879 synchronized (mPidsSelfLocked) {
1880 mPidsSelfLocked.remove(app.pid);
1881 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1882 }
1883 app.pid = 0;
1884 }
1885
1886 mProcessesOnHold.remove(app);
1887
1888 updateCpuStats();
1889
1890 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1891 mProcDeaths[0] = 0;
1892
1893 try {
1894 int uid = app.info.uid;
1895 int[] gids = null;
1896 try {
1897 gids = mContext.getPackageManager().getPackageGids(
1898 app.info.packageName);
1899 } catch (PackageManager.NameNotFoundException e) {
1900 Log.w(TAG, "Unable to retrieve gids", e);
1901 }
1902 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1903 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1904 && mTopComponent != null
1905 && app.processName.equals(mTopComponent.getPackageName())) {
1906 uid = 0;
1907 }
1908 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1909 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1910 uid = 0;
1911 }
1912 }
1913 int debugFlags = 0;
1914 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1915 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1916 }
1917 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1918 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1919 }
1920 if ("1".equals(SystemProperties.get("debug.assert"))) {
1921 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1922 }
1923 int pid = Process.start("android.app.ActivityThread",
1924 mSimpleProcessManagement ? app.processName : null, uid, uid,
1925 gids, debugFlags, null);
1926 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1927 synchronized (bs) {
1928 if (bs.isOnBattery()) {
1929 app.batteryStats.incStartsLocked();
1930 }
1931 }
1932
1933 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1934 app.processName, hostingType,
1935 hostingNameStr != null ? hostingNameStr : "");
1936
1937 if (app.persistent) {
1938 Watchdog.getInstance().processStarted(app, app.processName, pid);
1939 }
1940
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001941 StringBuilder buf = mStringBuilder;
1942 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 buf.append("Start proc ");
1944 buf.append(app.processName);
1945 buf.append(" for ");
1946 buf.append(hostingType);
1947 if (hostingNameStr != null) {
1948 buf.append(" ");
1949 buf.append(hostingNameStr);
1950 }
1951 buf.append(": pid=");
1952 buf.append(pid);
1953 buf.append(" uid=");
1954 buf.append(uid);
1955 buf.append(" gids={");
1956 if (gids != null) {
1957 for (int gi=0; gi<gids.length; gi++) {
1958 if (gi != 0) buf.append(", ");
1959 buf.append(gids[gi]);
1960
1961 }
1962 }
1963 buf.append("}");
1964 Log.i(TAG, buf.toString());
1965 if (pid == 0 || pid == MY_PID) {
1966 // Processes are being emulated with threads.
1967 app.pid = MY_PID;
1968 app.removed = false;
1969 mStartingProcesses.add(app);
1970 } else if (pid > 0) {
1971 app.pid = pid;
1972 app.removed = false;
1973 synchronized (mPidsSelfLocked) {
1974 this.mPidsSelfLocked.put(pid, app);
1975 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1976 msg.obj = app;
1977 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1978 }
1979 } else {
1980 app.pid = 0;
1981 RuntimeException e = new RuntimeException(
1982 "Failure starting process " + app.processName
1983 + ": returned pid=" + pid);
1984 Log.e(TAG, e.getMessage(), e);
1985 }
1986 } catch (RuntimeException e) {
1987 // XXX do better error recovery.
1988 app.pid = 0;
1989 Log.e(TAG, "Failure starting process " + app.processName, e);
1990 }
1991 }
1992
1993 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1994 if (mPausingActivity != null) {
1995 RuntimeException e = new RuntimeException();
1996 Log.e(TAG, "Trying to pause when pause is already pending for "
1997 + mPausingActivity, e);
1998 }
1999 HistoryRecord prev = mResumedActivity;
2000 if (prev == null) {
2001 RuntimeException e = new RuntimeException();
2002 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2003 resumeTopActivityLocked(null);
2004 return;
2005 }
2006 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2007 mResumedActivity = null;
2008 mPausingActivity = prev;
2009 mLastPausedActivity = prev;
2010 prev.state = ActivityState.PAUSING;
2011 prev.task.touchActiveTime();
2012
2013 updateCpuStats();
2014
2015 if (prev.app != null && prev.app.thread != null) {
2016 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2017 try {
2018 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2019 System.identityHashCode(prev),
2020 prev.shortComponentName);
2021 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2022 prev.configChangeFlags);
2023 updateUsageStats(prev, false);
2024 } catch (Exception e) {
2025 // Ignore exception, if process died other code will cleanup.
2026 Log.w(TAG, "Exception thrown during pause", e);
2027 mPausingActivity = null;
2028 mLastPausedActivity = null;
2029 }
2030 } else {
2031 mPausingActivity = null;
2032 mLastPausedActivity = null;
2033 }
2034
2035 // If we are not going to sleep, we want to ensure the device is
2036 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002037 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 mLaunchingActivity.acquire();
2039 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2040 // To be safe, don't allow the wake lock to be held for too long.
2041 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2042 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2043 }
2044 }
2045
2046
2047 if (mPausingActivity != null) {
2048 // Have the window manager pause its key dispatching until the new
2049 // activity has started. If we're pausing the activity just because
2050 // the screen is being turned off and the UI is sleeping, don't interrupt
2051 // key dispatch; the same activity will pick it up again on wakeup.
2052 if (!uiSleeping) {
2053 prev.pauseKeyDispatchingLocked();
2054 } else {
2055 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2056 }
2057
2058 // Schedule a pause timeout in case the app doesn't respond.
2059 // We don't give it much time because this directly impacts the
2060 // responsiveness seen by the user.
2061 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2062 msg.obj = prev;
2063 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2064 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2065 } else {
2066 // This activity failed to schedule the
2067 // pause, so just treat it as being paused now.
2068 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2069 resumeTopActivityLocked(null);
2070 }
2071 }
2072
2073 private final void completePauseLocked() {
2074 HistoryRecord prev = mPausingActivity;
2075 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2076
2077 if (prev != null) {
2078 if (prev.finishing) {
2079 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2080 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2081 } else if (prev.app != null) {
2082 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2083 if (prev.waitingVisible) {
2084 prev.waitingVisible = false;
2085 mWaitingVisibleActivities.remove(prev);
2086 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2087 TAG, "Complete pause, no longer waiting: " + prev);
2088 }
2089 if (prev.configDestroy) {
2090 // The previous is being paused because the configuration
2091 // is changing, which means it is actually stopping...
2092 // To juggle the fact that we are also starting a new
2093 // instance right now, we need to first completely stop
2094 // the current instance before starting the new one.
2095 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2096 destroyActivityLocked(prev, true);
2097 } else {
2098 mStoppingActivities.add(prev);
2099 if (mStoppingActivities.size() > 3) {
2100 // If we already have a few activities waiting to stop,
2101 // then give up on things going idle and start clearing
2102 // them out.
2103 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2104 Message msg = Message.obtain();
2105 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2106 mHandler.sendMessage(msg);
2107 }
2108 }
2109 } else {
2110 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2111 prev = null;
2112 }
2113 mPausingActivity = null;
2114 }
2115
Dianne Hackborn55280a92009-05-07 15:53:46 -07002116 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 resumeTopActivityLocked(prev);
2118 } else {
2119 if (mGoingToSleep.isHeld()) {
2120 mGoingToSleep.release();
2121 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002122 if (mShuttingDown) {
2123 notifyAll();
2124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 }
2126
2127 if (prev != null) {
2128 prev.resumeKeyDispatchingLocked();
2129 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002130
2131 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2132 long diff = 0;
2133 synchronized (mProcessStatsThread) {
2134 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2135 }
2136 if (diff > 0) {
2137 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2138 synchronized (bsi) {
2139 BatteryStatsImpl.Uid.Proc ps =
2140 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2141 prev.info.packageName);
2142 if (ps != null) {
2143 ps.addForegroundTimeLocked(diff);
2144 }
2145 }
2146 }
2147 }
2148 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 }
2150
2151 /**
2152 * Once we know that we have asked an application to put an activity in
2153 * the resumed state (either by launching it or explicitly telling it),
2154 * this function updates the rest of our state to match that fact.
2155 */
2156 private final void completeResumeLocked(HistoryRecord next) {
2157 next.idle = false;
2158 next.results = null;
2159 next.newIntents = null;
2160
2161 // schedule an idle timeout in case the app doesn't do it for us.
2162 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2163 msg.obj = next;
2164 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2165
2166 if (false) {
2167 // The activity was never told to pause, so just keep
2168 // things going as-is. To maintain our own state,
2169 // we need to emulate it coming back and saying it is
2170 // idle.
2171 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2172 msg.obj = next;
2173 mHandler.sendMessage(msg);
2174 }
2175
2176 next.thumbnail = null;
2177 setFocusedActivityLocked(next);
2178 next.resumeKeyDispatchingLocked();
2179 ensureActivitiesVisibleLocked(null, 0);
2180 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002181
2182 // Mark the point when the activity is resuming
2183 // TODO: To be more accurate, the mark should be before the onCreate,
2184 // not after the onResume. But for subsequent starts, onResume is fine.
2185 if (next.app != null) {
2186 synchronized (mProcessStatsThread) {
2187 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2188 }
2189 } else {
2190 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 }
2193
2194 /**
2195 * Make sure that all activities that need to be visible (that is, they
2196 * currently can be seen by the user) actually are.
2197 */
2198 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2199 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2200 if (DEBUG_VISBILITY) Log.v(
2201 TAG, "ensureActivitiesVisible behind " + top
2202 + " configChanges=0x" + Integer.toHexString(configChanges));
2203
2204 // If the top activity is not fullscreen, then we need to
2205 // make sure any activities under it are now visible.
2206 final int count = mHistory.size();
2207 int i = count-1;
2208 while (mHistory.get(i) != top) {
2209 i--;
2210 }
2211 HistoryRecord r;
2212 boolean behindFullscreen = false;
2213 for (; i>=0; i--) {
2214 r = (HistoryRecord)mHistory.get(i);
2215 if (DEBUG_VISBILITY) Log.v(
2216 TAG, "Make visible? " + r + " finishing=" + r.finishing
2217 + " state=" + r.state);
2218 if (r.finishing) {
2219 continue;
2220 }
2221
2222 final boolean doThisProcess = onlyThisProcess == null
2223 || onlyThisProcess.equals(r.processName);
2224
2225 // First: if this is not the current activity being started, make
2226 // sure it matches the current configuration.
2227 if (r != starting && doThisProcess) {
2228 ensureActivityConfigurationLocked(r, 0);
2229 }
2230
2231 if (r.app == null || r.app.thread == null) {
2232 if (onlyThisProcess == null
2233 || onlyThisProcess.equals(r.processName)) {
2234 // This activity needs to be visible, but isn't even
2235 // running... get it started, but don't resume it
2236 // at this point.
2237 if (DEBUG_VISBILITY) Log.v(
2238 TAG, "Start and freeze screen for " + r);
2239 if (r != starting) {
2240 r.startFreezingScreenLocked(r.app, configChanges);
2241 }
2242 if (!r.visible) {
2243 if (DEBUG_VISBILITY) Log.v(
2244 TAG, "Starting and making visible: " + r);
2245 mWindowManager.setAppVisibility(r, true);
2246 }
2247 if (r != starting) {
2248 startSpecificActivityLocked(r, false, false);
2249 }
2250 }
2251
2252 } else if (r.visible) {
2253 // If this activity is already visible, then there is nothing
2254 // else to do here.
2255 if (DEBUG_VISBILITY) Log.v(
2256 TAG, "Skipping: already visible at " + r);
2257 r.stopFreezingScreenLocked(false);
2258
2259 } else if (onlyThisProcess == null) {
2260 // This activity is not currently visible, but is running.
2261 // Tell it to become visible.
2262 r.visible = true;
2263 if (r.state != ActivityState.RESUMED && r != starting) {
2264 // If this activity is paused, tell it
2265 // to now show its window.
2266 if (DEBUG_VISBILITY) Log.v(
2267 TAG, "Making visible and scheduling visibility: " + r);
2268 try {
2269 mWindowManager.setAppVisibility(r, true);
2270 r.app.thread.scheduleWindowVisibility(r, true);
2271 r.stopFreezingScreenLocked(false);
2272 } catch (Exception e) {
2273 // Just skip on any failure; we'll make it
2274 // visible when it next restarts.
2275 Log.w(TAG, "Exception thrown making visibile: "
2276 + r.intent.getComponent(), e);
2277 }
2278 }
2279 }
2280
2281 // Aggregate current change flags.
2282 configChanges |= r.configChangeFlags;
2283
2284 if (r.fullscreen) {
2285 // At this point, nothing else needs to be shown
2286 if (DEBUG_VISBILITY) Log.v(
2287 TAG, "Stopping: fullscreen at " + r);
2288 behindFullscreen = true;
2289 i--;
2290 break;
2291 }
2292 }
2293
2294 // Now for any activities that aren't visible to the user, make
2295 // sure they no longer are keeping the screen frozen.
2296 while (i >= 0) {
2297 r = (HistoryRecord)mHistory.get(i);
2298 if (DEBUG_VISBILITY) Log.v(
2299 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2300 + " state=" + r.state
2301 + " behindFullscreen=" + behindFullscreen);
2302 if (!r.finishing) {
2303 if (behindFullscreen) {
2304 if (r.visible) {
2305 if (DEBUG_VISBILITY) Log.v(
2306 TAG, "Making invisible: " + r);
2307 r.visible = false;
2308 try {
2309 mWindowManager.setAppVisibility(r, false);
2310 if ((r.state == ActivityState.STOPPING
2311 || r.state == ActivityState.STOPPED)
2312 && r.app != null && r.app.thread != null) {
2313 if (DEBUG_VISBILITY) Log.v(
2314 TAG, "Scheduling invisibility: " + r);
2315 r.app.thread.scheduleWindowVisibility(r, false);
2316 }
2317 } catch (Exception e) {
2318 // Just skip on any failure; we'll make it
2319 // visible when it next restarts.
2320 Log.w(TAG, "Exception thrown making hidden: "
2321 + r.intent.getComponent(), e);
2322 }
2323 } else {
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Already invisible: " + r);
2326 }
2327 } else if (r.fullscreen) {
2328 if (DEBUG_VISBILITY) Log.v(
2329 TAG, "Now behindFullscreen: " + r);
2330 behindFullscreen = true;
2331 }
2332 }
2333 i--;
2334 }
2335 }
2336
2337 /**
2338 * Version of ensureActivitiesVisible that can easily be called anywhere.
2339 */
2340 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2341 int configChanges) {
2342 HistoryRecord r = topRunningActivityLocked(null);
2343 if (r != null) {
2344 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2345 }
2346 }
2347
2348 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2349 if (resumed) {
2350 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2351 } else {
2352 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2353 }
2354 }
2355
2356 /**
2357 * Ensure that the top activity in the stack is resumed.
2358 *
2359 * @param prev The previously resumed activity, for when in the process
2360 * of pausing; can be null to call from elsewhere.
2361 *
2362 * @return Returns true if something is being resumed, or false if
2363 * nothing happened.
2364 */
2365 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2366 // Find the first activity that is not finishing.
2367 HistoryRecord next = topRunningActivityLocked(null);
2368
2369 // Remember how we'll process this pause/resume situation, and ensure
2370 // that the state is reset however we wind up proceeding.
2371 final boolean userLeaving = mUserLeaving;
2372 mUserLeaving = false;
2373
2374 if (next == null) {
2375 // There are no more activities! Let's just start up the
2376 // Launcher...
2377 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2378 && mTopAction == null) {
2379 // We are running in factory test mode, but unable to find
2380 // the factory test app, so just sit around displaying the
2381 // error message and don't try to start anything.
2382 return false;
2383 }
2384 Intent intent = new Intent(
2385 mTopAction,
2386 mTopData != null ? Uri.parse(mTopData) : null);
2387 intent.setComponent(mTopComponent);
2388 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2389 intent.addCategory(Intent.CATEGORY_HOME);
2390 }
2391 ActivityInfo aInfo =
2392 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002393 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 if (aInfo != null) {
2395 intent.setComponent(new ComponentName(
2396 aInfo.applicationInfo.packageName, aInfo.name));
2397 // Don't do this if the home app is currently being
2398 // instrumented.
2399 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2400 aInfo.applicationInfo.uid);
2401 if (app == null || app.instrumentationClass == null) {
2402 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2403 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002404 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002405 }
2406 }
2407 return true;
2408 }
2409
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002410 next.delayedResume = false;
2411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 // If the top activity is the resumed one, nothing to do.
2413 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2414 // Make sure we have executed any pending transitions, since there
2415 // should be nothing left to do at this point.
2416 mWindowManager.executeAppTransition();
2417 return false;
2418 }
2419
2420 // If we are sleeping, and there is no resumed activity, and the top
2421 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002422 if ((mSleeping || mShuttingDown)
2423 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002424 // Make sure we have executed any pending transitions, since there
2425 // should be nothing left to do at this point.
2426 mWindowManager.executeAppTransition();
2427 return false;
2428 }
2429
2430 // The activity may be waiting for stop, but that is no longer
2431 // appropriate for it.
2432 mStoppingActivities.remove(next);
2433 mWaitingVisibleActivities.remove(next);
2434
2435 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2436
2437 // If we are currently pausing an activity, then don't do anything
2438 // until that is done.
2439 if (mPausingActivity != null) {
2440 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2441 return false;
2442 }
2443
2444 // We need to start pausing the current activity so the top one
2445 // can be resumed...
2446 if (mResumedActivity != null) {
2447 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2448 startPausingLocked(userLeaving, false);
2449 return true;
2450 }
2451
2452 if (prev != null && prev != next) {
2453 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2454 prev.waitingVisible = true;
2455 mWaitingVisibleActivities.add(prev);
2456 if (DEBUG_SWITCH) Log.v(
2457 TAG, "Resuming top, waiting visible to hide: " + prev);
2458 } else {
2459 // The next activity is already visible, so hide the previous
2460 // activity's windows right now so we can show the new one ASAP.
2461 // We only do this if the previous is finishing, which should mean
2462 // it is on top of the one being resumed so hiding it quickly
2463 // is good. Otherwise, we want to do the normal route of allowing
2464 // the resumed activity to be shown so we can decide if the
2465 // previous should actually be hidden depending on whether the
2466 // new one is found to be full-screen or not.
2467 if (prev.finishing) {
2468 mWindowManager.setAppVisibility(prev, false);
2469 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2470 + prev + ", waitingVisible="
2471 + (prev != null ? prev.waitingVisible : null)
2472 + ", nowVisible=" + next.nowVisible);
2473 } else {
2474 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2475 + prev + ", waitingVisible="
2476 + (prev != null ? prev.waitingVisible : null)
2477 + ", nowVisible=" + next.nowVisible);
2478 }
2479 }
2480 }
2481
2482 // We are starting up the next activity, so tell the window manager
2483 // that the previous one will be hidden soon. This way it can know
2484 // to ignore it when computing the desired screen orientation.
2485 if (prev != null) {
2486 if (prev.finishing) {
2487 if (DEBUG_TRANSITION) Log.v(TAG,
2488 "Prepare close transition: prev=" + prev);
2489 mWindowManager.prepareAppTransition(prev.task == next.task
2490 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2491 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2492 mWindowManager.setAppWillBeHidden(prev);
2493 mWindowManager.setAppVisibility(prev, false);
2494 } else {
2495 if (DEBUG_TRANSITION) Log.v(TAG,
2496 "Prepare open transition: prev=" + prev);
2497 mWindowManager.prepareAppTransition(prev.task == next.task
2498 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2499 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2500 }
2501 if (false) {
2502 mWindowManager.setAppWillBeHidden(prev);
2503 mWindowManager.setAppVisibility(prev, false);
2504 }
2505 } else if (mHistory.size() > 1) {
2506 if (DEBUG_TRANSITION) Log.v(TAG,
2507 "Prepare open transition: no previous");
2508 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2509 }
2510
2511 if (next.app != null && next.app.thread != null) {
2512 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2513
2514 // This activity is now becoming visible.
2515 mWindowManager.setAppVisibility(next, true);
2516
2517 HistoryRecord lastResumedActivity = mResumedActivity;
2518 ActivityState lastState = next.state;
2519
2520 updateCpuStats();
2521
2522 next.state = ActivityState.RESUMED;
2523 mResumedActivity = next;
2524 next.task.touchActiveTime();
2525 updateLRUListLocked(next.app, true);
2526 updateLRUListLocked(next);
2527
2528 // Have the window manager re-evaluate the orientation of
2529 // the screen based on the new activity order.
2530 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002531 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 next.mayFreezeScreenLocked(next.app) ? next : null);
2533 if (config != null) {
2534 next.frozenBeforeDestroy = true;
2535 }
2536 if (!updateConfigurationLocked(config, next)) {
2537 // The configuration update wasn't able to keep the existing
2538 // instance of the activity, and instead started a new one.
2539 // We should be all done, but let's just make sure our activity
2540 // is still at the top and schedule another run if something
2541 // weird happened.
2542 HistoryRecord nextNext = topRunningActivityLocked(null);
2543 if (DEBUG_SWITCH) Log.i(TAG,
2544 "Activity config changed during resume: " + next
2545 + ", new next: " + nextNext);
2546 if (nextNext != next) {
2547 // Do over!
2548 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2549 }
2550 mWindowManager.executeAppTransition();
2551 return true;
2552 }
2553
2554 try {
2555 // Deliver all pending results.
2556 ArrayList a = next.results;
2557 if (a != null) {
2558 final int N = a.size();
2559 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002560 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 TAG, "Delivering results to " + next
2562 + ": " + a);
2563 next.app.thread.scheduleSendResult(next, a);
2564 }
2565 }
2566
2567 if (next.newIntents != null) {
2568 next.app.thread.scheduleNewIntent(next.newIntents, next);
2569 }
2570
2571 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2572 System.identityHashCode(next),
2573 next.task.taskId, next.shortComponentName);
2574 updateUsageStats(next, true);
2575
2576 next.app.thread.scheduleResumeActivity(next,
2577 isNextTransitionForward());
2578 pauseIfSleepingLocked();
2579
2580 } catch (Exception e) {
2581 // Whoops, need to restart this activity!
2582 next.state = lastState;
2583 mResumedActivity = lastResumedActivity;
2584 if (Config.LOGD) Log.d(TAG,
2585 "Restarting because process died: " + next);
2586 if (!next.hasBeenLaunched) {
2587 next.hasBeenLaunched = true;
2588 } else {
2589 if (SHOW_APP_STARTING_ICON) {
2590 mWindowManager.setAppStartingWindow(
2591 next, next.packageName, next.theme,
2592 next.nonLocalizedLabel,
2593 next.labelRes, next.icon, null, true);
2594 }
2595 }
2596 startSpecificActivityLocked(next, true, false);
2597 return true;
2598 }
2599
2600 // From this point on, if something goes wrong there is no way
2601 // to recover the activity.
2602 try {
2603 next.visible = true;
2604 completeResumeLocked(next);
2605 } catch (Exception e) {
2606 // If any exception gets thrown, toss away this
2607 // activity and try the next one.
2608 Log.w(TAG, "Exception thrown during resume of " + next, e);
2609 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2610 "resume-exception");
2611 return true;
2612 }
2613
2614 // Didn't need to use the icicle, and it is now out of date.
2615 next.icicle = null;
2616 next.haveState = false;
2617 next.stopped = false;
2618
2619 } else {
2620 // Whoops, need to restart this activity!
2621 if (!next.hasBeenLaunched) {
2622 next.hasBeenLaunched = true;
2623 } else {
2624 if (SHOW_APP_STARTING_ICON) {
2625 mWindowManager.setAppStartingWindow(
2626 next, next.packageName, next.theme,
2627 next.nonLocalizedLabel,
2628 next.labelRes, next.icon, null, true);
2629 }
2630 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2631 }
2632 startSpecificActivityLocked(next, true, true);
2633 }
2634
2635 return true;
2636 }
2637
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002638 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2639 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002640 final int NH = mHistory.size();
2641
2642 int addPos = -1;
2643
2644 if (!newTask) {
2645 // If starting in an existing task, find where that is...
2646 HistoryRecord next = null;
2647 boolean startIt = true;
2648 for (int i = NH-1; i >= 0; i--) {
2649 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2650 if (p.finishing) {
2651 continue;
2652 }
2653 if (p.task == r.task) {
2654 // Here it is! Now, if this is not yet visible to the
2655 // user, then just add it without starting; it will
2656 // get started when the user navigates back to it.
2657 addPos = i+1;
2658 if (!startIt) {
2659 mHistory.add(addPos, r);
2660 r.inHistory = true;
2661 r.task.numActivities++;
2662 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2663 r.info.screenOrientation, r.fullscreen);
2664 if (VALIDATE_TOKENS) {
2665 mWindowManager.validateAppTokens(mHistory);
2666 }
2667 return;
2668 }
2669 break;
2670 }
2671 if (p.fullscreen) {
2672 startIt = false;
2673 }
2674 next = p;
2675 }
2676 }
2677
2678 // Place a new activity at top of stack, so it is next to interact
2679 // with the user.
2680 if (addPos < 0) {
2681 addPos = mHistory.size();
2682 }
2683
2684 // If we are not placing the new activity frontmost, we do not want
2685 // to deliver the onUserLeaving callback to the actual frontmost
2686 // activity
2687 if (addPos < NH) {
2688 mUserLeaving = false;
2689 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2690 }
2691
2692 // Slot the activity into the history stack and proceed
2693 mHistory.add(addPos, r);
2694 r.inHistory = true;
2695 r.frontOfTask = newTask;
2696 r.task.numActivities++;
2697 if (NH > 0) {
2698 // We want to show the starting preview window if we are
2699 // switching to a new task, or the next activity's process is
2700 // not currently running.
2701 boolean showStartingIcon = newTask;
2702 ProcessRecord proc = r.app;
2703 if (proc == null) {
2704 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2705 }
2706 if (proc == null || proc.thread == null) {
2707 showStartingIcon = true;
2708 }
2709 if (DEBUG_TRANSITION) Log.v(TAG,
2710 "Prepare open transition: starting " + r);
2711 mWindowManager.prepareAppTransition(newTask
2712 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2713 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2714 mWindowManager.addAppToken(
2715 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2716 boolean doShow = true;
2717 if (newTask) {
2718 // Even though this activity is starting fresh, we still need
2719 // to reset it to make sure we apply affinities to move any
2720 // existing activities from other tasks in to it.
2721 // If the caller has requested that the target task be
2722 // reset, then do so.
2723 if ((r.intent.getFlags()
2724 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2725 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002726 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 }
2728 }
2729 if (SHOW_APP_STARTING_ICON && doShow) {
2730 // Figure out if we are transitioning from another activity that is
2731 // "has the same starting icon" as the next one. This allows the
2732 // window manager to keep the previous window it had previously
2733 // created, if it still had one.
2734 HistoryRecord prev = mResumedActivity;
2735 if (prev != null) {
2736 // We don't want to reuse the previous starting preview if:
2737 // (1) The current activity is in a different task.
2738 if (prev.task != r.task) prev = null;
2739 // (2) The current activity is already displayed.
2740 else if (prev.nowVisible) prev = null;
2741 }
2742 mWindowManager.setAppStartingWindow(
2743 r, r.packageName, r.theme, r.nonLocalizedLabel,
2744 r.labelRes, r.icon, prev, showStartingIcon);
2745 }
2746 } else {
2747 // If this is the first activity, don't do any fancy animations,
2748 // because there is nothing for it to animate on top of.
2749 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2750 r.info.screenOrientation, r.fullscreen);
2751 }
2752 if (VALIDATE_TOKENS) {
2753 mWindowManager.validateAppTokens(mHistory);
2754 }
2755
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002756 if (doResume) {
2757 resumeTopActivityLocked(null);
2758 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002759 }
2760
2761 /**
2762 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002763 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2764 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002765 * an instance of that activity in the stack and, if found, finish all
2766 * activities on top of it and return the instance.
2767 *
2768 * @param newR Description of the new activity being started.
2769 * @return Returns the old activity that should be continue to be used,
2770 * or null if none was found.
2771 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002772 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 HistoryRecord newR, boolean doClear) {
2774 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002775
2776 // First find the requested task.
2777 while (i > 0) {
2778 i--;
2779 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2780 if (r.task.taskId == taskId) {
2781 i++;
2782 break;
2783 }
2784 }
2785
2786 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002787 while (i > 0) {
2788 i--;
2789 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2790 if (r.finishing) {
2791 continue;
2792 }
2793 if (r.task.taskId != taskId) {
2794 return null;
2795 }
2796 if (r.realActivity.equals(newR.realActivity)) {
2797 // Here it is! Now finish everything in front...
2798 HistoryRecord ret = r;
2799 if (doClear) {
2800 while (i < (mHistory.size()-1)) {
2801 i++;
2802 r = (HistoryRecord)mHistory.get(i);
2803 if (r.finishing) {
2804 continue;
2805 }
2806 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2807 null, "clear")) {
2808 i--;
2809 }
2810 }
2811 }
2812
2813 // Finally, if this is a normal launch mode (that is, not
2814 // expecting onNewIntent()), then we will finish the current
2815 // instance of the activity so a new fresh one can be started.
2816 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2817 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002818 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 if (index >= 0) {
2820 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2821 null, "clear");
2822 }
2823 return null;
2824 }
2825 }
2826
2827 return ret;
2828 }
2829 }
2830
2831 return null;
2832 }
2833
2834 /**
2835 * Find the activity in the history stack within the given task. Returns
2836 * the index within the history at which it's found, or < 0 if not found.
2837 */
2838 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2839 int i = mHistory.size();
2840 while (i > 0) {
2841 i--;
2842 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2843 if (candidate.task.taskId != task) {
2844 break;
2845 }
2846 if (candidate.realActivity.equals(r.realActivity)) {
2847 return i;
2848 }
2849 }
2850
2851 return -1;
2852 }
2853
2854 /**
2855 * Reorder the history stack so that the activity at the given index is
2856 * brought to the front.
2857 */
2858 private final HistoryRecord moveActivityToFrontLocked(int where) {
2859 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2860 int top = mHistory.size();
2861 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2862 mHistory.add(top, newTop);
2863 oldTop.frontOfTask = false;
2864 newTop.frontOfTask = true;
2865 return newTop;
2866 }
2867
2868 /**
2869 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2870 * method will be called at the proper time.
2871 */
2872 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2873 boolean sent = false;
2874 if (r.state == ActivityState.RESUMED
2875 && r.app != null && r.app.thread != null) {
2876 try {
2877 ArrayList<Intent> ar = new ArrayList<Intent>();
2878 ar.add(new Intent(intent));
2879 r.app.thread.scheduleNewIntent(ar, r);
2880 sent = true;
2881 } catch (Exception e) {
2882 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2883 }
2884 }
2885 if (!sent) {
2886 r.addNewIntentLocked(new Intent(intent));
2887 }
2888 }
2889
2890 private final void logStartActivity(int tag, HistoryRecord r,
2891 TaskRecord task) {
2892 EventLog.writeEvent(tag,
2893 System.identityHashCode(r), task.taskId,
2894 r.shortComponentName, r.intent.getAction(),
2895 r.intent.getType(), r.intent.getDataString(),
2896 r.intent.getFlags());
2897 }
2898
2899 private final int startActivityLocked(IApplicationThread caller,
2900 Intent intent, String resolvedType,
2901 Uri[] grantedUriPermissions,
2902 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2903 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002904 int callingPid, int callingUid, boolean onlyIfNeeded,
2905 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002906 Log.i(TAG, "Starting activity: " + intent);
2907
2908 HistoryRecord sourceRecord = null;
2909 HistoryRecord resultRecord = null;
2910 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002911 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002912 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2914 if (index >= 0) {
2915 sourceRecord = (HistoryRecord)mHistory.get(index);
2916 if (requestCode >= 0 && !sourceRecord.finishing) {
2917 resultRecord = sourceRecord;
2918 }
2919 }
2920 }
2921
2922 int launchFlags = intent.getFlags();
2923
2924 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2925 && sourceRecord != null) {
2926 // Transfer the result target from the source activity to the new
2927 // one being started, including any failures.
2928 if (requestCode >= 0) {
2929 return START_FORWARD_AND_REQUEST_CONFLICT;
2930 }
2931 resultRecord = sourceRecord.resultTo;
2932 resultWho = sourceRecord.resultWho;
2933 requestCode = sourceRecord.requestCode;
2934 sourceRecord.resultTo = null;
2935 if (resultRecord != null) {
2936 resultRecord.removeResultsLocked(
2937 sourceRecord, resultWho, requestCode);
2938 }
2939 }
2940
2941 int err = START_SUCCESS;
2942
2943 if (intent.getComponent() == null) {
2944 // We couldn't find a class that can handle the given Intent.
2945 // That's the end of that!
2946 err = START_INTENT_NOT_RESOLVED;
2947 }
2948
2949 if (err == START_SUCCESS && aInfo == null) {
2950 // We couldn't find the specific class specified in the Intent.
2951 // Also the end of the line.
2952 err = START_CLASS_NOT_FOUND;
2953 }
2954
2955 ProcessRecord callerApp = null;
2956 if (err == START_SUCCESS && caller != null) {
2957 callerApp = getRecordForAppLocked(caller);
2958 if (callerApp != null) {
2959 callingPid = callerApp.pid;
2960 callingUid = callerApp.info.uid;
2961 } else {
2962 Log.w(TAG, "Unable to find app for caller " + caller
2963 + " (pid=" + callingPid + ") when starting: "
2964 + intent.toString());
2965 err = START_PERMISSION_DENIED;
2966 }
2967 }
2968
2969 if (err != START_SUCCESS) {
2970 if (resultRecord != null) {
2971 sendActivityResultLocked(-1,
2972 resultRecord, resultWho, requestCode,
2973 Activity.RESULT_CANCELED, null);
2974 }
2975 return err;
2976 }
2977
2978 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2979 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2980 if (perm != PackageManager.PERMISSION_GRANTED) {
2981 if (resultRecord != null) {
2982 sendActivityResultLocked(-1,
2983 resultRecord, resultWho, requestCode,
2984 Activity.RESULT_CANCELED, null);
2985 }
2986 String msg = "Permission Denial: starting " + intent.toString()
2987 + " from " + callerApp + " (pid=" + callingPid
2988 + ", uid=" + callingUid + ")"
2989 + " requires " + aInfo.permission;
2990 Log.w(TAG, msg);
2991 throw new SecurityException(msg);
2992 }
2993
2994 if (mWatcher != null) {
2995 boolean abort = false;
2996 try {
2997 // The Intent we give to the watcher has the extra data
2998 // stripped off, since it can contain private information.
2999 Intent watchIntent = intent.cloneFilter();
3000 abort = !mWatcher.activityStarting(watchIntent,
3001 aInfo.applicationInfo.packageName);
3002 } catch (RemoteException e) {
3003 mWatcher = null;
3004 }
3005
3006 if (abort) {
3007 if (resultRecord != null) {
3008 sendActivityResultLocked(-1,
3009 resultRecord, resultWho, requestCode,
3010 Activity.RESULT_CANCELED, null);
3011 }
3012 // We pretend to the caller that it was really started, but
3013 // they will just get a cancel result.
3014 return START_SUCCESS;
3015 }
3016 }
3017
3018 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3019 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003020 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003021
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003022 if (mResumedActivity == null
3023 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3024 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3025 PendingActivityLaunch pal = new PendingActivityLaunch();
3026 pal.r = r;
3027 pal.sourceRecord = sourceRecord;
3028 pal.grantedUriPermissions = grantedUriPermissions;
3029 pal.grantedMode = grantedMode;
3030 pal.onlyIfNeeded = onlyIfNeeded;
3031 mPendingActivityLaunches.add(pal);
3032 return START_SWITCHES_CANCELED;
3033 }
3034 }
3035
3036 if (mDidAppSwitch) {
3037 // This is the second allowed switch since we stopped switches,
3038 // so now just generally allow switches. Use case: user presses
3039 // home (switches disabled, switch to home, mDidAppSwitch now true);
3040 // user taps a home icon (coming from home so allowed, we hit here
3041 // and now allow anyone to switch again).
3042 mAppSwitchesAllowedTime = 0;
3043 } else {
3044 mDidAppSwitch = true;
3045 }
3046
3047 doPendingActivityLaunchesLocked(false);
3048
3049 return startActivityUncheckedLocked(r, sourceRecord,
3050 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3051 }
3052
3053 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3054 final int N = mPendingActivityLaunches.size();
3055 if (N <= 0) {
3056 return;
3057 }
3058 for (int i=0; i<N; i++) {
3059 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3060 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3061 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3062 doResume && i == (N-1));
3063 }
3064 mPendingActivityLaunches.clear();
3065 }
3066
3067 private final int startActivityUncheckedLocked(HistoryRecord r,
3068 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3069 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3070 final Intent intent = r.intent;
3071 final int callingUid = r.launchedFromUid;
3072
3073 int launchFlags = intent.getFlags();
3074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 // We'll invoke onUserLeaving before onPause only if the launching
3076 // activity did not explicitly state that this is an automated launch.
3077 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3078 if (DEBUG_USER_LEAVING) Log.v(TAG,
3079 "startActivity() => mUserLeaving=" + mUserLeaving);
3080
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003081 // If the caller has asked not to resume at this point, we make note
3082 // of this in the record so that we can skip it when trying to find
3083 // the top running activity.
3084 if (!doResume) {
3085 r.delayedResume = true;
3086 }
3087
3088 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3089 != 0 ? r : null;
3090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 // If the onlyIfNeeded flag is set, then we can do this if the activity
3092 // being launched is the same as the one making the call... or, as
3093 // a special case, if we do not know the caller then we count the
3094 // current top activity as the caller.
3095 if (onlyIfNeeded) {
3096 HistoryRecord checkedCaller = sourceRecord;
3097 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003098 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 }
3100 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3101 // Caller is not the same as launcher, so always needed.
3102 onlyIfNeeded = false;
3103 }
3104 }
3105
3106 if (grantedUriPermissions != null && callingUid > 0) {
3107 for (int i=0; i<grantedUriPermissions.length; i++) {
3108 grantUriPermissionLocked(callingUid, r.packageName,
3109 grantedUriPermissions[i], grantedMode, r);
3110 }
3111 }
3112
3113 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3114 intent, r);
3115
3116 if (sourceRecord == null) {
3117 // This activity is not being started from another... in this
3118 // case we -always- start a new task.
3119 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3120 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3121 + intent);
3122 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3123 }
3124 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3125 // The original activity who is starting us is running as a single
3126 // instance... this new activity it is starting must go on its
3127 // own task.
3128 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3129 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3130 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3131 // The activity being started is a single instance... it always
3132 // gets launched into its own task.
3133 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3134 }
3135
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003136 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003137 // For whatever reason this activity is being launched into a new
3138 // task... yet the caller has requested a result back. Well, that
3139 // is pretty messed up, so instead immediately send back a cancel
3140 // and let the new task continue launched as normal without a
3141 // dependency on its originator.
3142 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3143 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003144 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 Activity.RESULT_CANCELED, null);
3146 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 }
3148
3149 boolean addingToTask = false;
3150 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3151 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3152 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3153 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3154 // If bring to front is requested, and no result is requested, and
3155 // we can find a task that was started with this same
3156 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003157 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 // See if there is a task to bring to the front. If this is
3159 // a SINGLE_INSTANCE activity, there can be one and only one
3160 // instance of it in the history, and it is always in its own
3161 // unique task, so we do a special search.
3162 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3163 ? findTaskLocked(intent, r.info)
3164 : findActivityLocked(intent, r.info);
3165 if (taskTop != null) {
3166 if (taskTop.task.intent == null) {
3167 // This task was started because of movement of
3168 // the activity based on affinity... now that we
3169 // are actually launching it, we can assign the
3170 // base intent.
3171 taskTop.task.setIntent(intent, r.info);
3172 }
3173 // If the target task is not in the front, then we need
3174 // to bring it to the front... except... well, with
3175 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3176 // to have the same behavior as if a new instance was
3177 // being started, which means not bringing it to the front
3178 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003179 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 if (curTop.task != taskTop.task) {
3181 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3182 boolean callerAtFront = sourceRecord == null
3183 || curTop.task == sourceRecord.task;
3184 if (callerAtFront) {
3185 // We really do want to push this one into the
3186 // user's face, right now.
3187 moveTaskToFrontLocked(taskTop.task);
3188 }
3189 }
3190 // If the caller has requested that the target task be
3191 // reset, then do so.
3192 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3193 taskTop = resetTaskIfNeededLocked(taskTop, r);
3194 }
3195 if (onlyIfNeeded) {
3196 // We don't need to start a new activity, and
3197 // the client said not to do anything if that
3198 // is the case, so this is it! And for paranoia, make
3199 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003200 if (doResume) {
3201 resumeTopActivityLocked(null);
3202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 return START_RETURN_INTENT_TO_CALLER;
3204 }
3205 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3206 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3207 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3208 // In this situation we want to remove all activities
3209 // from the task up to the one being started. In most
3210 // cases this means we are resetting the task to its
3211 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003212 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003213 taskTop.task.taskId, r, true);
3214 if (top != null) {
3215 if (top.frontOfTask) {
3216 // Activity aliases may mean we use different
3217 // intents for the top activity, so make sure
3218 // the task now has the identity of the new
3219 // intent.
3220 top.task.setIntent(r.intent, r.info);
3221 }
3222 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3223 deliverNewIntentLocked(top, r.intent);
3224 } else {
3225 // A special case: we need to
3226 // start the activity because it is not currently
3227 // running, and the caller has asked to clear the
3228 // current task to have this activity at the top.
3229 addingToTask = true;
3230 // Now pretend like this activity is being started
3231 // by the top of its task, so it is put in the
3232 // right place.
3233 sourceRecord = taskTop;
3234 }
3235 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3236 // In this case the top activity on the task is the
3237 // same as the one being launched, so we take that
3238 // as a request to bring the task to the foreground.
3239 // If the top activity in the task is the root
3240 // activity, deliver this new intent to it if it
3241 // desires.
3242 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3243 && taskTop.realActivity.equals(r.realActivity)) {
3244 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3245 if (taskTop.frontOfTask) {
3246 taskTop.task.setIntent(r.intent, r.info);
3247 }
3248 deliverNewIntentLocked(taskTop, r.intent);
3249 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3250 // In this case we are launching the root activity
3251 // of the task, but with a different intent. We
3252 // should start a new instance on top.
3253 addingToTask = true;
3254 sourceRecord = taskTop;
3255 }
3256 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3257 // In this case an activity is being launched in to an
3258 // existing task, without resetting that task. This
3259 // is typically the situation of launching an activity
3260 // from a notification or shortcut. We want to place
3261 // the new activity on top of the current task.
3262 addingToTask = true;
3263 sourceRecord = taskTop;
3264 } else if (!taskTop.task.rootWasReset) {
3265 // In this case we are launching in to an existing task
3266 // that has not yet been started from its front door.
3267 // The current task has been brought to the front.
3268 // Ideally, we'd probably like to place this new task
3269 // at the bottom of its stack, but that's a little hard
3270 // to do with the current organization of the code so
3271 // for now we'll just drop it.
3272 taskTop.task.setIntent(r.intent, r.info);
3273 }
3274 if (!addingToTask) {
3275 // We didn't do anything... but it was needed (a.k.a., client
3276 // don't use that intent!) And for paranoia, make
3277 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003278 if (doResume) {
3279 resumeTopActivityLocked(null);
3280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 return START_TASK_TO_FRONT;
3282 }
3283 }
3284 }
3285 }
3286
3287 //String uri = r.intent.toURI();
3288 //Intent intent2 = new Intent(uri);
3289 //Log.i(TAG, "Given intent: " + r.intent);
3290 //Log.i(TAG, "URI is: " + uri);
3291 //Log.i(TAG, "To intent: " + intent2);
3292
3293 if (r.packageName != null) {
3294 // If the activity being launched is the same as the one currently
3295 // at the top, then we need to check if it should only be launched
3296 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003297 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3298 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 if (top.realActivity.equals(r.realActivity)) {
3300 if (top.app != null && top.app.thread != null) {
3301 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3302 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3303 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3304 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3305 // For paranoia, make sure we have correctly
3306 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003307 if (doResume) {
3308 resumeTopActivityLocked(null);
3309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 if (onlyIfNeeded) {
3311 // We don't need to start a new activity, and
3312 // the client said not to do anything if that
3313 // is the case, so this is it!
3314 return START_RETURN_INTENT_TO_CALLER;
3315 }
3316 deliverNewIntentLocked(top, r.intent);
3317 return START_DELIVERED_TO_TOP;
3318 }
3319 }
3320 }
3321 }
3322
3323 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003324 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003326 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 Activity.RESULT_CANCELED, null);
3328 }
3329 return START_CLASS_NOT_FOUND;
3330 }
3331
3332 boolean newTask = false;
3333
3334 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003335 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3337 // todo: should do better management of integers.
3338 mCurTask++;
3339 if (mCurTask <= 0) {
3340 mCurTask = 1;
3341 }
3342 r.task = new TaskRecord(mCurTask, r.info, intent,
3343 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3344 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3345 + " in new task " + r.task);
3346 newTask = true;
3347 addRecentTask(r.task);
3348
3349 } else if (sourceRecord != null) {
3350 if (!addingToTask &&
3351 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3352 // In this case, we are adding the activity to an existing
3353 // task, but the caller has asked to clear that task if the
3354 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003355 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003356 sourceRecord.task.taskId, r, true);
3357 if (top != null) {
3358 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3359 deliverNewIntentLocked(top, r.intent);
3360 // For paranoia, make sure we have correctly
3361 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003362 if (doResume) {
3363 resumeTopActivityLocked(null);
3364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 return START_DELIVERED_TO_TOP;
3366 }
3367 } else if (!addingToTask &&
3368 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3369 // In this case, we are launching an activity in our own task
3370 // that may already be running somewhere in the history, and
3371 // we want to shuffle it to the front of the stack if so.
3372 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3373 if (where >= 0) {
3374 HistoryRecord top = moveActivityToFrontLocked(where);
3375 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3376 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003377 if (doResume) {
3378 resumeTopActivityLocked(null);
3379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 return START_DELIVERED_TO_TOP;
3381 }
3382 }
3383 // An existing activity is starting this new activity, so we want
3384 // to keep the new one in the same task as the one that is starting
3385 // it.
3386 r.task = sourceRecord.task;
3387 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3388 + " in existing task " + r.task);
3389
3390 } else {
3391 // This not being started from an existing activity, and not part
3392 // of a new task... just put it in the top task, though these days
3393 // this case should never happen.
3394 final int N = mHistory.size();
3395 HistoryRecord prev =
3396 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3397 r.task = prev != null
3398 ? prev.task
3399 : new TaskRecord(mCurTask, r.info, intent,
3400 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3401 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3402 + " in new guessed " + r.task);
3403 }
3404 if (newTask) {
3405 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3406 }
3407 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003408 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003409 return START_SUCCESS;
3410 }
3411
3412 public final int startActivity(IApplicationThread caller,
3413 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3414 int grantedMode, IBinder resultTo,
3415 String resultWho, int requestCode, boolean onlyIfNeeded,
3416 boolean debug) {
3417 // Refuse possible leaked file descriptors
3418 if (intent != null && intent.hasFileDescriptors()) {
3419 throw new IllegalArgumentException("File descriptors passed in Intent");
3420 }
3421
The Android Open Source Project4df24232009-03-05 14:34:35 -08003422 final boolean componentSpecified = intent.getComponent() != null;
3423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 // Don't modify the client's object!
3425 intent = new Intent(intent);
3426
3427 // Collect information about the target of the Intent.
3428 // Must do this before locking, because resolving the intent
3429 // may require launching a process to run its content provider.
3430 ActivityInfo aInfo;
3431 try {
3432 ResolveInfo rInfo =
3433 ActivityThread.getPackageManager().resolveIntent(
3434 intent, resolvedType,
3435 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003436 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 aInfo = rInfo != null ? rInfo.activityInfo : null;
3438 } catch (RemoteException e) {
3439 aInfo = null;
3440 }
3441
3442 if (aInfo != null) {
3443 // Store the found target back into the intent, because now that
3444 // we have it we never want to do this again. For example, if the
3445 // user navigates back to this point in the history, we should
3446 // always restart the exact same activity.
3447 intent.setComponent(new ComponentName(
3448 aInfo.applicationInfo.packageName, aInfo.name));
3449
3450 // Don't debug things in the system process
3451 if (debug) {
3452 if (!aInfo.processName.equals("system")) {
3453 setDebugApp(aInfo.processName, true, false);
3454 }
3455 }
3456 }
3457
3458 synchronized(this) {
3459 final long origId = Binder.clearCallingIdentity();
3460 int res = startActivityLocked(caller, intent, resolvedType,
3461 grantedUriPermissions, grantedMode, aInfo,
3462 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003463 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003464 Binder.restoreCallingIdentity(origId);
3465 return res;
3466 }
3467 }
3468
3469 public boolean startNextMatchingActivity(IBinder callingActivity,
3470 Intent intent) {
3471 // Refuse possible leaked file descriptors
3472 if (intent != null && intent.hasFileDescriptors() == true) {
3473 throw new IllegalArgumentException("File descriptors passed in Intent");
3474 }
3475
3476 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003477 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 if (index < 0) {
3479 return false;
3480 }
3481 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3482 if (r.app == null || r.app.thread == null) {
3483 // The caller is not running... d'oh!
3484 return false;
3485 }
3486 intent = new Intent(intent);
3487 // The caller is not allowed to change the data.
3488 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3489 // And we are resetting to find the next component...
3490 intent.setComponent(null);
3491
3492 ActivityInfo aInfo = null;
3493 try {
3494 List<ResolveInfo> resolves =
3495 ActivityThread.getPackageManager().queryIntentActivities(
3496 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003497 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498
3499 // Look for the original activity in the list...
3500 final int N = resolves != null ? resolves.size() : 0;
3501 for (int i=0; i<N; i++) {
3502 ResolveInfo rInfo = resolves.get(i);
3503 if (rInfo.activityInfo.packageName.equals(r.packageName)
3504 && rInfo.activityInfo.name.equals(r.info.name)) {
3505 // We found the current one... the next matching is
3506 // after it.
3507 i++;
3508 if (i<N) {
3509 aInfo = resolves.get(i).activityInfo;
3510 }
3511 break;
3512 }
3513 }
3514 } catch (RemoteException e) {
3515 }
3516
3517 if (aInfo == null) {
3518 // Nobody who is next!
3519 return false;
3520 }
3521
3522 intent.setComponent(new ComponentName(
3523 aInfo.applicationInfo.packageName, aInfo.name));
3524 intent.setFlags(intent.getFlags()&~(
3525 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3526 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3527 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3528 Intent.FLAG_ACTIVITY_NEW_TASK));
3529
3530 // Okay now we need to start the new activity, replacing the
3531 // currently running activity. This is a little tricky because
3532 // we want to start the new one as if the current one is finished,
3533 // but not finish the current one first so that there is no flicker.
3534 // And thus...
3535 final boolean wasFinishing = r.finishing;
3536 r.finishing = true;
3537
3538 // Propagate reply information over to the new activity.
3539 final HistoryRecord resultTo = r.resultTo;
3540 final String resultWho = r.resultWho;
3541 final int requestCode = r.requestCode;
3542 r.resultTo = null;
3543 if (resultTo != null) {
3544 resultTo.removeResultsLocked(r, resultWho, requestCode);
3545 }
3546
3547 final long origId = Binder.clearCallingIdentity();
3548 // XXX we are not dealing with propagating grantedUriPermissions...
3549 // those are not yet exposed to user code, so there is no need.
3550 int res = startActivityLocked(r.app.thread, intent,
3551 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003552 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 Binder.restoreCallingIdentity(origId);
3554
3555 r.finishing = wasFinishing;
3556 if (res != START_SUCCESS) {
3557 return false;
3558 }
3559 return true;
3560 }
3561 }
3562
3563 final int startActivityInPackage(int uid,
3564 Intent intent, String resolvedType, IBinder resultTo,
3565 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003566 final boolean componentSpecified = intent.getComponent() != null;
3567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 // Don't modify the client's object!
3569 intent = new Intent(intent);
3570
3571 // Collect information about the target of the Intent.
3572 // Must do this before locking, because resolving the intent
3573 // may require launching a process to run its content provider.
3574 ActivityInfo aInfo;
3575 try {
3576 ResolveInfo rInfo =
3577 ActivityThread.getPackageManager().resolveIntent(
3578 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003579 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 aInfo = rInfo != null ? rInfo.activityInfo : null;
3581 } catch (RemoteException e) {
3582 aInfo = null;
3583 }
3584
3585 if (aInfo != null) {
3586 // Store the found target back into the intent, because now that
3587 // we have it we never want to do this again. For example, if the
3588 // user navigates back to this point in the history, we should
3589 // always restart the exact same activity.
3590 intent.setComponent(new ComponentName(
3591 aInfo.applicationInfo.packageName, aInfo.name));
3592 }
3593
3594 synchronized(this) {
3595 return startActivityLocked(null, intent, resolvedType,
3596 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003597 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 }
3599 }
3600
3601 private final void addRecentTask(TaskRecord task) {
3602 // Remove any existing entries that are the same kind of task.
3603 int N = mRecentTasks.size();
3604 for (int i=0; i<N; i++) {
3605 TaskRecord tr = mRecentTasks.get(i);
3606 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3607 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3608 mRecentTasks.remove(i);
3609 i--;
3610 N--;
3611 if (task.intent == null) {
3612 // If the new recent task we are adding is not fully
3613 // specified, then replace it with the existing recent task.
3614 task = tr;
3615 }
3616 }
3617 }
3618 if (N >= MAX_RECENT_TASKS) {
3619 mRecentTasks.remove(N-1);
3620 }
3621 mRecentTasks.add(0, task);
3622 }
3623
3624 public void setRequestedOrientation(IBinder token,
3625 int requestedOrientation) {
3626 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003627 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003628 if (index < 0) {
3629 return;
3630 }
3631 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3632 final long origId = Binder.clearCallingIdentity();
3633 mWindowManager.setAppOrientation(r, requestedOrientation);
3634 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003635 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003636 r.mayFreezeScreenLocked(r.app) ? r : null);
3637 if (config != null) {
3638 r.frozenBeforeDestroy = true;
3639 if (!updateConfigurationLocked(config, r)) {
3640 resumeTopActivityLocked(null);
3641 }
3642 }
3643 Binder.restoreCallingIdentity(origId);
3644 }
3645 }
3646
3647 public int getRequestedOrientation(IBinder token) {
3648 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003649 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 if (index < 0) {
3651 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3652 }
3653 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3654 return mWindowManager.getAppOrientation(r);
3655 }
3656 }
3657
3658 private final void stopActivityLocked(HistoryRecord r) {
3659 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3660 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3661 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3662 if (!r.finishing) {
3663 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3664 "no-history");
3665 }
3666 } else if (r.app != null && r.app.thread != null) {
3667 if (mFocusedActivity == r) {
3668 setFocusedActivityLocked(topRunningActivityLocked(null));
3669 }
3670 r.resumeKeyDispatchingLocked();
3671 try {
3672 r.stopped = false;
3673 r.state = ActivityState.STOPPING;
3674 if (DEBUG_VISBILITY) Log.v(
3675 TAG, "Stopping visible=" + r.visible + " for " + r);
3676 if (!r.visible) {
3677 mWindowManager.setAppVisibility(r, false);
3678 }
3679 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3680 } catch (Exception e) {
3681 // Maybe just ignore exceptions here... if the process
3682 // has crashed, our death notification will clean things
3683 // up.
3684 Log.w(TAG, "Exception thrown during pause", e);
3685 // Just in case, assume it to be stopped.
3686 r.stopped = true;
3687 r.state = ActivityState.STOPPED;
3688 if (r.configDestroy) {
3689 destroyActivityLocked(r, true);
3690 }
3691 }
3692 }
3693 }
3694
3695 /**
3696 * @return Returns true if the activity is being finished, false if for
3697 * some reason it is being left as-is.
3698 */
3699 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3700 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003701 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003702 TAG, "Finishing activity: token=" + token
3703 + ", result=" + resultCode + ", data=" + resultData);
3704
Dianne Hackborn75b03852009-06-12 15:43:26 -07003705 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 if (index < 0) {
3707 return false;
3708 }
3709 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3710
3711 // Is this the last activity left?
3712 boolean lastActivity = true;
3713 for (int i=mHistory.size()-1; i>=0; i--) {
3714 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3715 if (!p.finishing && p != r) {
3716 lastActivity = false;
3717 break;
3718 }
3719 }
3720
3721 // If this is the last activity, but it is the home activity, then
3722 // just don't finish it.
3723 if (lastActivity) {
3724 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3725 return false;
3726 }
3727 }
3728
3729 finishActivityLocked(r, index, resultCode, resultData, reason);
3730 return true;
3731 }
3732
3733 /**
3734 * @return Returns true if this activity has been removed from the history
3735 * list, or false if it is still in the list and will be removed later.
3736 */
3737 private final boolean finishActivityLocked(HistoryRecord r, int index,
3738 int resultCode, Intent resultData, String reason) {
3739 if (r.finishing) {
3740 Log.w(TAG, "Duplicate finish request for " + r);
3741 return false;
3742 }
3743
3744 r.finishing = true;
3745 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3746 System.identityHashCode(r),
3747 r.task.taskId, r.shortComponentName, reason);
3748 r.task.numActivities--;
3749 if (r.frontOfTask && index < (mHistory.size()-1)) {
3750 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3751 if (next.task == r.task) {
3752 next.frontOfTask = true;
3753 }
3754 }
3755
3756 r.pauseKeyDispatchingLocked();
3757 if (mFocusedActivity == r) {
3758 setFocusedActivityLocked(topRunningActivityLocked(null));
3759 }
3760
3761 // send the result
3762 HistoryRecord resultTo = r.resultTo;
3763 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003764 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3765 + " who=" + r.resultWho + " req=" + r.requestCode
3766 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 if (r.info.applicationInfo.uid > 0) {
3768 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3769 r.packageName, resultData, r);
3770 }
3771 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3772 resultData);
3773 r.resultTo = null;
3774 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003775 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776
3777 // Make sure this HistoryRecord is not holding on to other resources,
3778 // because clients have remote IPC references to this object so we
3779 // can't assume that will go away and want to avoid circular IPC refs.
3780 r.results = null;
3781 r.pendingResults = null;
3782 r.newIntents = null;
3783 r.icicle = null;
3784
3785 if (mPendingThumbnails.size() > 0) {
3786 // There are clients waiting to receive thumbnails so, in case
3787 // this is an activity that someone is waiting for, add it
3788 // to the pending list so we can correctly update the clients.
3789 mCancelledThumbnails.add(r);
3790 }
3791
3792 if (mResumedActivity == r) {
3793 boolean endTask = index <= 0
3794 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3795 if (DEBUG_TRANSITION) Log.v(TAG,
3796 "Prepare close transition: finishing " + r);
3797 mWindowManager.prepareAppTransition(endTask
3798 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3799 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3800
3801 // Tell window manager to prepare for this one to be removed.
3802 mWindowManager.setAppVisibility(r, false);
3803
3804 if (mPausingActivity == null) {
3805 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3806 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3807 startPausingLocked(false, false);
3808 }
3809
3810 } else if (r.state != ActivityState.PAUSING) {
3811 // If the activity is PAUSING, we will complete the finish once
3812 // it is done pausing; else we can just directly finish it here.
3813 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3814 return finishCurrentActivityLocked(r, index,
3815 FINISH_AFTER_PAUSE) == null;
3816 } else {
3817 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3818 }
3819
3820 return false;
3821 }
3822
3823 private static final int FINISH_IMMEDIATELY = 0;
3824 private static final int FINISH_AFTER_PAUSE = 1;
3825 private static final int FINISH_AFTER_VISIBLE = 2;
3826
3827 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3828 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003829 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 if (index < 0) {
3831 return null;
3832 }
3833
3834 return finishCurrentActivityLocked(r, index, mode);
3835 }
3836
3837 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3838 int index, int mode) {
3839 // First things first: if this activity is currently visible,
3840 // and the resumed activity is not yet visible, then hold off on
3841 // finishing until the resumed one becomes visible.
3842 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3843 if (!mStoppingActivities.contains(r)) {
3844 mStoppingActivities.add(r);
3845 if (mStoppingActivities.size() > 3) {
3846 // If we already have a few activities waiting to stop,
3847 // then give up on things going idle and start clearing
3848 // them out.
3849 Message msg = Message.obtain();
3850 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3851 mHandler.sendMessage(msg);
3852 }
3853 }
3854 r.state = ActivityState.STOPPING;
3855 updateOomAdjLocked();
3856 return r;
3857 }
3858
3859 // make sure the record is cleaned out of other places.
3860 mStoppingActivities.remove(r);
3861 mWaitingVisibleActivities.remove(r);
3862 if (mResumedActivity == r) {
3863 mResumedActivity = null;
3864 }
3865 final ActivityState prevState = r.state;
3866 r.state = ActivityState.FINISHING;
3867
3868 if (mode == FINISH_IMMEDIATELY
3869 || prevState == ActivityState.STOPPED
3870 || prevState == ActivityState.INITIALIZING) {
3871 // If this activity is already stopped, we can just finish
3872 // it right now.
3873 return destroyActivityLocked(r, true) ? null : r;
3874 } else {
3875 // Need to go through the full pause cycle to get this
3876 // activity into the stopped state and then finish it.
3877 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3878 mFinishingActivities.add(r);
3879 resumeTopActivityLocked(null);
3880 }
3881 return r;
3882 }
3883
3884 /**
3885 * This is the internal entry point for handling Activity.finish().
3886 *
3887 * @param token The Binder token referencing the Activity we want to finish.
3888 * @param resultCode Result code, if any, from this Activity.
3889 * @param resultData Result data (Intent), if any, from this Activity.
3890 *
3891 * @result Returns true if the activity successfully finished, or false if it is still running.
3892 */
3893 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3894 // Refuse possible leaked file descriptors
3895 if (resultData != null && resultData.hasFileDescriptors() == true) {
3896 throw new IllegalArgumentException("File descriptors passed in Intent");
3897 }
3898
3899 synchronized(this) {
3900 if (mWatcher != null) {
3901 // Find the first activity that is not finishing.
3902 HistoryRecord next = topRunningActivityLocked(token, 0);
3903 if (next != null) {
3904 // ask watcher if this is allowed
3905 boolean resumeOK = true;
3906 try {
3907 resumeOK = mWatcher.activityResuming(next.packageName);
3908 } catch (RemoteException e) {
3909 mWatcher = null;
3910 }
3911
3912 if (!resumeOK) {
3913 return false;
3914 }
3915 }
3916 }
3917 final long origId = Binder.clearCallingIdentity();
3918 boolean res = requestFinishActivityLocked(token, resultCode,
3919 resultData, "app-request");
3920 Binder.restoreCallingIdentity(origId);
3921 return res;
3922 }
3923 }
3924
3925 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3926 String resultWho, int requestCode, int resultCode, Intent data) {
3927
3928 if (callingUid > 0) {
3929 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3930 data, r);
3931 }
3932
The Android Open Source Project10592532009-03-18 17:39:46 -07003933 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3934 + " : who=" + resultWho + " req=" + requestCode
3935 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003936 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3937 try {
3938 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3939 list.add(new ResultInfo(resultWho, requestCode,
3940 resultCode, data));
3941 r.app.thread.scheduleSendResult(r, list);
3942 return;
3943 } catch (Exception e) {
3944 Log.w(TAG, "Exception thrown sending result to " + r, e);
3945 }
3946 }
3947
3948 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3949 }
3950
3951 public final void finishSubActivity(IBinder token, String resultWho,
3952 int requestCode) {
3953 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003954 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003955 if (index < 0) {
3956 return;
3957 }
3958 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3959
3960 final long origId = Binder.clearCallingIdentity();
3961
3962 int i;
3963 for (i=mHistory.size()-1; i>=0; i--) {
3964 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3965 if (r.resultTo == self && r.requestCode == requestCode) {
3966 if ((r.resultWho == null && resultWho == null) ||
3967 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3968 finishActivityLocked(r, i,
3969 Activity.RESULT_CANCELED, null, "request-sub");
3970 }
3971 }
3972 }
3973
3974 Binder.restoreCallingIdentity(origId);
3975 }
3976 }
3977
3978 /**
3979 * Perform clean-up of service connections in an activity record.
3980 */
3981 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3982 // Throw away any services that have been bound by this activity.
3983 if (r.connections != null) {
3984 Iterator<ConnectionRecord> it = r.connections.iterator();
3985 while (it.hasNext()) {
3986 ConnectionRecord c = it.next();
3987 removeConnectionLocked(c, null, r);
3988 }
3989 r.connections = null;
3990 }
3991 }
3992
3993 /**
3994 * Perform the common clean-up of an activity record. This is called both
3995 * as part of destroyActivityLocked() (when destroying the client-side
3996 * representation) and cleaning things up as a result of its hosting
3997 * processing going away, in which case there is no remaining client-side
3998 * state to destroy so only the cleanup here is needed.
3999 */
4000 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4001 if (mResumedActivity == r) {
4002 mResumedActivity = null;
4003 }
4004 if (mFocusedActivity == r) {
4005 mFocusedActivity = null;
4006 }
4007
4008 r.configDestroy = false;
4009 r.frozenBeforeDestroy = false;
4010
4011 // Make sure this record is no longer in the pending finishes list.
4012 // This could happen, for example, if we are trimming activities
4013 // down to the max limit while they are still waiting to finish.
4014 mFinishingActivities.remove(r);
4015 mWaitingVisibleActivities.remove(r);
4016
4017 // Remove any pending results.
4018 if (r.finishing && r.pendingResults != null) {
4019 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4020 PendingIntentRecord rec = apr.get();
4021 if (rec != null) {
4022 cancelIntentSenderLocked(rec, false);
4023 }
4024 }
4025 r.pendingResults = null;
4026 }
4027
4028 if (cleanServices) {
4029 cleanUpActivityServicesLocked(r);
4030 }
4031
4032 if (mPendingThumbnails.size() > 0) {
4033 // There are clients waiting to receive thumbnails so, in case
4034 // this is an activity that someone is waiting for, add it
4035 // to the pending list so we can correctly update the clients.
4036 mCancelledThumbnails.add(r);
4037 }
4038
4039 // Get rid of any pending idle timeouts.
4040 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4041 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4042 }
4043
4044 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4045 if (r.state != ActivityState.DESTROYED) {
4046 mHistory.remove(r);
4047 r.inHistory = false;
4048 r.state = ActivityState.DESTROYED;
4049 mWindowManager.removeAppToken(r);
4050 if (VALIDATE_TOKENS) {
4051 mWindowManager.validateAppTokens(mHistory);
4052 }
4053 cleanUpActivityServicesLocked(r);
4054 removeActivityUriPermissionsLocked(r);
4055 }
4056 }
4057
4058 /**
4059 * Destroy the current CLIENT SIDE instance of an activity. This may be
4060 * called both when actually finishing an activity, or when performing
4061 * a configuration switch where we destroy the current client-side object
4062 * but then create a new client-side object for this same HistoryRecord.
4063 */
4064 private final boolean destroyActivityLocked(HistoryRecord r,
4065 boolean removeFromApp) {
4066 if (DEBUG_SWITCH) Log.v(
4067 TAG, "Removing activity: token=" + r
4068 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4069 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4070 System.identityHashCode(r),
4071 r.task.taskId, r.shortComponentName);
4072
4073 boolean removedFromHistory = false;
4074
4075 cleanUpActivityLocked(r, false);
4076
4077 if (r.app != null) {
4078 if (removeFromApp) {
4079 int idx = r.app.activities.indexOf(r);
4080 if (idx >= 0) {
4081 r.app.activities.remove(idx);
4082 }
4083 if (r.persistent) {
4084 decPersistentCountLocked(r.app);
4085 }
4086 }
4087
4088 boolean skipDestroy = false;
4089
4090 try {
4091 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4092 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4093 r.configChangeFlags);
4094 } catch (Exception e) {
4095 // We can just ignore exceptions here... if the process
4096 // has crashed, our death notification will clean things
4097 // up.
4098 //Log.w(TAG, "Exception thrown during finish", e);
4099 if (r.finishing) {
4100 removeActivityFromHistoryLocked(r);
4101 removedFromHistory = true;
4102 skipDestroy = true;
4103 }
4104 }
4105
4106 r.app = null;
4107 r.nowVisible = false;
4108
4109 if (r.finishing && !skipDestroy) {
4110 r.state = ActivityState.DESTROYING;
4111 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4112 msg.obj = r;
4113 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4114 } else {
4115 r.state = ActivityState.DESTROYED;
4116 }
4117 } else {
4118 // remove this record from the history.
4119 if (r.finishing) {
4120 removeActivityFromHistoryLocked(r);
4121 removedFromHistory = true;
4122 } else {
4123 r.state = ActivityState.DESTROYED;
4124 }
4125 }
4126
4127 r.configChangeFlags = 0;
4128
4129 if (!mLRUActivities.remove(r)) {
4130 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4131 }
4132
4133 return removedFromHistory;
4134 }
4135
4136 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4137 ProcessRecord app)
4138 {
4139 int i = list.size();
4140 if (localLOGV) Log.v(
4141 TAG, "Removing app " + app + " from list " + list
4142 + " with " + i + " entries");
4143 while (i > 0) {
4144 i--;
4145 HistoryRecord r = (HistoryRecord)list.get(i);
4146 if (localLOGV) Log.v(
4147 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4148 if (r.app == app) {
4149 if (localLOGV) Log.v(TAG, "Removing this entry!");
4150 list.remove(i);
4151 }
4152 }
4153 }
4154
4155 /**
4156 * Main function for removing an existing process from the activity manager
4157 * as a result of that process going away. Clears out all connections
4158 * to the process.
4159 */
4160 private final void handleAppDiedLocked(ProcessRecord app,
4161 boolean restarting) {
4162 cleanUpApplicationRecordLocked(app, restarting, -1);
4163 if (!restarting) {
4164 mLRUProcesses.remove(app);
4165 }
4166
4167 // Just in case...
4168 if (mPausingActivity != null && mPausingActivity.app == app) {
4169 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4170 mPausingActivity = null;
4171 }
4172 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4173 mLastPausedActivity = null;
4174 }
4175
4176 // Remove this application's activities from active lists.
4177 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4178 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4179 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4180 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4181
4182 boolean atTop = true;
4183 boolean hasVisibleActivities = false;
4184
4185 // Clean out the history list.
4186 int i = mHistory.size();
4187 if (localLOGV) Log.v(
4188 TAG, "Removing app " + app + " from history with " + i + " entries");
4189 while (i > 0) {
4190 i--;
4191 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4192 if (localLOGV) Log.v(
4193 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4194 if (r.app == app) {
4195 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4196 if (localLOGV) Log.v(
4197 TAG, "Removing this entry! frozen=" + r.haveState
4198 + " finishing=" + r.finishing);
4199 mHistory.remove(i);
4200
4201 r.inHistory = false;
4202 mWindowManager.removeAppToken(r);
4203 if (VALIDATE_TOKENS) {
4204 mWindowManager.validateAppTokens(mHistory);
4205 }
4206 removeActivityUriPermissionsLocked(r);
4207
4208 } else {
4209 // We have the current state for this activity, so
4210 // it can be restarted later when needed.
4211 if (localLOGV) Log.v(
4212 TAG, "Keeping entry, setting app to null");
4213 if (r.visible) {
4214 hasVisibleActivities = true;
4215 }
4216 r.app = null;
4217 r.nowVisible = false;
4218 if (!r.haveState) {
4219 r.icicle = null;
4220 }
4221 }
4222
4223 cleanUpActivityLocked(r, true);
4224 r.state = ActivityState.STOPPED;
4225 }
4226 atTop = false;
4227 }
4228
4229 app.activities.clear();
4230
4231 if (app.instrumentationClass != null) {
4232 Log.w(TAG, "Crash of app " + app.processName
4233 + " running instrumentation " + app.instrumentationClass);
4234 Bundle info = new Bundle();
4235 info.putString("shortMsg", "Process crashed.");
4236 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4237 }
4238
4239 if (!restarting) {
4240 if (!resumeTopActivityLocked(null)) {
4241 // If there was nothing to resume, and we are not already
4242 // restarting this process, but there is a visible activity that
4243 // is hosted by the process... then make sure all visible
4244 // activities are running, taking care of restarting this
4245 // process.
4246 if (hasVisibleActivities) {
4247 ensureActivitiesVisibleLocked(null, 0);
4248 }
4249 }
4250 }
4251 }
4252
4253 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4254 IBinder threadBinder = thread.asBinder();
4255
4256 // Find the application record.
4257 int count = mLRUProcesses.size();
4258 int i;
4259 for (i=0; i<count; i++) {
4260 ProcessRecord rec = mLRUProcesses.get(i);
4261 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4262 return i;
4263 }
4264 }
4265 return -1;
4266 }
4267
4268 private final ProcessRecord getRecordForAppLocked(
4269 IApplicationThread thread) {
4270 if (thread == null) {
4271 return null;
4272 }
4273
4274 int appIndex = getLRURecordIndexForAppLocked(thread);
4275 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4276 }
4277
4278 private final void appDiedLocked(ProcessRecord app, int pid,
4279 IApplicationThread thread) {
4280
4281 mProcDeaths[0]++;
4282
4283 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4284 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4285 + ") has died.");
4286 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4287 if (localLOGV) Log.v(
4288 TAG, "Dying app: " + app + ", pid: " + pid
4289 + ", thread: " + thread.asBinder());
4290 boolean doLowMem = app.instrumentationClass == null;
4291 handleAppDiedLocked(app, false);
4292
4293 if (doLowMem) {
4294 // If there are no longer any background processes running,
4295 // and the app that died was not running instrumentation,
4296 // then tell everyone we are now low on memory.
4297 boolean haveBg = false;
4298 int count = mLRUProcesses.size();
4299 int i;
4300 for (i=0; i<count; i++) {
4301 ProcessRecord rec = mLRUProcesses.get(i);
4302 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4303 haveBg = true;
4304 break;
4305 }
4306 }
4307
4308 if (!haveBg) {
4309 Log.i(TAG, "Low Memory: No more background processes.");
4310 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4311 for (i=0; i<count; i++) {
4312 ProcessRecord rec = mLRUProcesses.get(i);
4313 if (rec.thread != null) {
4314 rec.lastRequestedGc = SystemClock.uptimeMillis();
4315 try {
4316 rec.thread.scheduleLowMemory();
4317 } catch (RemoteException e) {
4318 // Don't care if the process is gone.
4319 }
4320 }
4321 }
4322 }
4323 }
4324 } else if (Config.LOGD) {
4325 Log.d(TAG, "Received spurious death notification for thread "
4326 + thread.asBinder());
4327 }
4328 }
4329
4330 final String readFile(String filename) {
4331 try {
4332 FileInputStream fs = new FileInputStream(filename);
4333 byte[] inp = new byte[8192];
4334 int size = fs.read(inp);
4335 fs.close();
4336 return new String(inp, 0, 0, size);
4337 } catch (java.io.IOException e) {
4338 }
4339 return "";
4340 }
4341
4342 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4343 final String annotation) {
4344 if (app.notResponding || app.crashing) {
4345 return;
4346 }
4347
4348 // Log the ANR to the event log.
4349 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4350
4351 // If we are on a secure build and the application is not interesting to the user (it is
4352 // not visible or in the background), just kill it instead of displaying a dialog.
4353 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4354 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4355 Process.killProcess(app.pid);
4356 return;
4357 }
4358
4359 // DeviceMonitor.start();
4360
4361 String processInfo = null;
4362 if (MONITOR_CPU_USAGE) {
4363 updateCpuStatsNow();
4364 synchronized (mProcessStatsThread) {
4365 processInfo = mProcessStats.printCurrentState();
4366 }
4367 }
4368
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004369 StringBuilder info = mStringBuilder;
4370 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004371 info.append("ANR (application not responding) in process: ");
4372 info.append(app.processName);
4373 if (annotation != null) {
4374 info.append("\nAnnotation: ");
4375 info.append(annotation);
4376 }
4377 if (MONITOR_CPU_USAGE) {
4378 info.append("\nCPU usage:\n");
4379 info.append(processInfo);
4380 }
4381 Log.i(TAG, info.toString());
4382
4383 // The application is not responding. Dump as many thread traces as we can.
4384 boolean fileDump = prepareTraceFile(true);
4385 if (!fileDump) {
4386 // Dumping traces to the log, just dump the process that isn't responding so
4387 // we don't overflow the log
4388 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4389 } else {
4390 // Dumping traces to a file so dump all active processes we know about
4391 synchronized (this) {
4392 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4393 ProcessRecord r = mLRUProcesses.get(i);
4394 if (r.thread != null) {
4395 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4396 }
4397 }
4398 }
4399 }
4400
4401 if (mWatcher != null) {
4402 try {
4403 int res = mWatcher.appNotResponding(app.processName,
4404 app.pid, info.toString());
4405 if (res != 0) {
4406 if (res < 0) {
4407 // wait until the SIGQUIT has had a chance to process before killing the
4408 // process.
4409 try {
4410 wait(2000);
4411 } catch (InterruptedException e) {
4412 }
4413
4414 Process.killProcess(app.pid);
4415 return;
4416 }
4417 }
4418 } catch (RemoteException e) {
4419 mWatcher = null;
4420 }
4421 }
4422
4423 makeAppNotRespondingLocked(app,
4424 activity != null ? activity.shortComponentName : null,
4425 annotation != null ? "ANR " + annotation : "ANR",
4426 info.toString(), null);
4427 Message msg = Message.obtain();
4428 HashMap map = new HashMap();
4429 msg.what = SHOW_NOT_RESPONDING_MSG;
4430 msg.obj = map;
4431 map.put("app", app);
4432 if (activity != null) {
4433 map.put("activity", activity);
4434 }
4435
4436 mHandler.sendMessage(msg);
4437 return;
4438 }
4439
4440 /**
4441 * If a stack trace file has been configured, prepare the filesystem
4442 * by creating the directory if it doesn't exist and optionally
4443 * removing the old trace file.
4444 *
4445 * @param removeExisting If set, the existing trace file will be removed.
4446 * @return Returns true if the trace file preparations succeeded
4447 */
4448 public static boolean prepareTraceFile(boolean removeExisting) {
4449 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4450 boolean fileReady = false;
4451 if (!TextUtils.isEmpty(tracesPath)) {
4452 File f = new File(tracesPath);
4453 if (!f.exists()) {
4454 // Ensure the enclosing directory exists
4455 File dir = f.getParentFile();
4456 if (!dir.exists()) {
4457 fileReady = dir.mkdirs();
4458 FileUtils.setPermissions(dir.getAbsolutePath(),
4459 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4460 } else if (dir.isDirectory()) {
4461 fileReady = true;
4462 }
4463 } else if (removeExisting) {
4464 // Remove the previous traces file, so we don't fill the disk.
4465 // The VM will recreate it
4466 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4467 fileReady = f.delete();
4468 }
4469 }
4470
4471 return fileReady;
4472 }
4473
4474
4475 private final void decPersistentCountLocked(ProcessRecord app)
4476 {
4477 app.persistentActivities--;
4478 if (app.persistentActivities > 0) {
4479 // Still more of 'em...
4480 return;
4481 }
4482 if (app.persistent) {
4483 // Ah, but the application itself is persistent. Whatever!
4484 return;
4485 }
4486
4487 // App is no longer persistent... make sure it and the ones
4488 // following it in the LRU list have the correc oom_adj.
4489 updateOomAdjLocked();
4490 }
4491
4492 public void setPersistent(IBinder token, boolean isPersistent) {
4493 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4494 != PackageManager.PERMISSION_GRANTED) {
4495 String msg = "Permission Denial: setPersistent() from pid="
4496 + Binder.getCallingPid()
4497 + ", uid=" + Binder.getCallingUid()
4498 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4499 Log.w(TAG, msg);
4500 throw new SecurityException(msg);
4501 }
4502
4503 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004504 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 if (index < 0) {
4506 return;
4507 }
4508 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4509 ProcessRecord app = r.app;
4510
4511 if (localLOGV) Log.v(
4512 TAG, "Setting persistence " + isPersistent + ": " + r);
4513
4514 if (isPersistent) {
4515 if (r.persistent) {
4516 // Okay okay, I heard you already!
4517 if (localLOGV) Log.v(TAG, "Already persistent!");
4518 return;
4519 }
4520 r.persistent = true;
4521 app.persistentActivities++;
4522 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4523 if (app.persistentActivities > 1) {
4524 // We aren't the first...
4525 if (localLOGV) Log.v(TAG, "Not the first!");
4526 return;
4527 }
4528 if (app.persistent) {
4529 // This would be redundant.
4530 if (localLOGV) Log.v(TAG, "App is persistent!");
4531 return;
4532 }
4533
4534 // App is now persistent... make sure it and the ones
4535 // following it now have the correct oom_adj.
4536 final long origId = Binder.clearCallingIdentity();
4537 updateOomAdjLocked();
4538 Binder.restoreCallingIdentity(origId);
4539
4540 } else {
4541 if (!r.persistent) {
4542 // Okay okay, I heard you already!
4543 return;
4544 }
4545 r.persistent = false;
4546 final long origId = Binder.clearCallingIdentity();
4547 decPersistentCountLocked(app);
4548 Binder.restoreCallingIdentity(origId);
4549
4550 }
4551 }
4552 }
4553
4554 public boolean clearApplicationUserData(final String packageName,
4555 final IPackageDataObserver observer) {
4556 int uid = Binder.getCallingUid();
4557 int pid = Binder.getCallingPid();
4558 long callingId = Binder.clearCallingIdentity();
4559 try {
4560 IPackageManager pm = ActivityThread.getPackageManager();
4561 int pkgUid = -1;
4562 synchronized(this) {
4563 try {
4564 pkgUid = pm.getPackageUid(packageName);
4565 } catch (RemoteException e) {
4566 }
4567 if (pkgUid == -1) {
4568 Log.w(TAG, "Invalid packageName:" + packageName);
4569 return false;
4570 }
4571 if (uid == pkgUid || checkComponentPermission(
4572 android.Manifest.permission.CLEAR_APP_USER_DATA,
4573 pid, uid, -1)
4574 == PackageManager.PERMISSION_GRANTED) {
4575 restartPackageLocked(packageName, pkgUid);
4576 } else {
4577 throw new SecurityException(pid+" does not have permission:"+
4578 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4579 "for process:"+packageName);
4580 }
4581 }
4582
4583 try {
4584 //clear application user data
4585 pm.clearApplicationUserData(packageName, observer);
4586 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4587 Uri.fromParts("package", packageName, null));
4588 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4589 broadcastIntentLocked(null, null, intent,
4590 null, null, 0, null, null, null,
4591 false, false, MY_PID, Process.SYSTEM_UID);
4592 } catch (RemoteException e) {
4593 }
4594 } finally {
4595 Binder.restoreCallingIdentity(callingId);
4596 }
4597 return true;
4598 }
4599
4600 public void restartPackage(final String packageName) {
4601 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4602 != PackageManager.PERMISSION_GRANTED) {
4603 String msg = "Permission Denial: restartPackage() from pid="
4604 + Binder.getCallingPid()
4605 + ", uid=" + Binder.getCallingUid()
4606 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4607 Log.w(TAG, msg);
4608 throw new SecurityException(msg);
4609 }
4610
4611 long callingId = Binder.clearCallingIdentity();
4612 try {
4613 IPackageManager pm = ActivityThread.getPackageManager();
4614 int pkgUid = -1;
4615 synchronized(this) {
4616 try {
4617 pkgUid = pm.getPackageUid(packageName);
4618 } catch (RemoteException e) {
4619 }
4620 if (pkgUid == -1) {
4621 Log.w(TAG, "Invalid packageName: " + packageName);
4622 return;
4623 }
4624 restartPackageLocked(packageName, pkgUid);
4625 }
4626 } finally {
4627 Binder.restoreCallingIdentity(callingId);
4628 }
4629 }
4630
4631 private void restartPackageLocked(final String packageName, int uid) {
4632 uninstallPackageLocked(packageName, uid, false);
4633 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4634 Uri.fromParts("package", packageName, null));
4635 intent.putExtra(Intent.EXTRA_UID, uid);
4636 broadcastIntentLocked(null, null, intent,
4637 null, null, 0, null, null, null,
4638 false, false, MY_PID, Process.SYSTEM_UID);
4639 }
4640
4641 private final void uninstallPackageLocked(String name, int uid,
4642 boolean callerWillRestart) {
4643 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4644
4645 int i, N;
4646
4647 final String procNamePrefix = name + ":";
4648 if (uid < 0) {
4649 try {
4650 uid = ActivityThread.getPackageManager().getPackageUid(name);
4651 } catch (RemoteException e) {
4652 }
4653 }
4654
4655 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4656 while (badApps.hasNext()) {
4657 SparseArray<Long> ba = badApps.next();
4658 if (ba.get(uid) != null) {
4659 badApps.remove();
4660 }
4661 }
4662
4663 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4664
4665 // Remove all processes this package may have touched: all with the
4666 // same UID (except for the system or root user), and all whose name
4667 // matches the package name.
4668 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4669 final int NA = apps.size();
4670 for (int ia=0; ia<NA; ia++) {
4671 ProcessRecord app = apps.valueAt(ia);
4672 if (app.removed) {
4673 procs.add(app);
4674 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4675 || app.processName.equals(name)
4676 || app.processName.startsWith(procNamePrefix)) {
4677 app.removed = true;
4678 procs.add(app);
4679 }
4680 }
4681 }
4682
4683 N = procs.size();
4684 for (i=0; i<N; i++) {
4685 removeProcessLocked(procs.get(i), callerWillRestart);
4686 }
4687
4688 for (i=mHistory.size()-1; i>=0; i--) {
4689 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4690 if (r.packageName.equals(name)) {
4691 if (Config.LOGD) Log.d(
4692 TAG, " Force finishing activity "
4693 + r.intent.getComponent().flattenToShortString());
4694 if (r.app != null) {
4695 r.app.removed = true;
4696 }
4697 r.app = null;
4698 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4699 }
4700 }
4701
4702 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4703 for (ServiceRecord service : mServices.values()) {
4704 if (service.packageName.equals(name)) {
4705 if (service.app != null) {
4706 service.app.removed = true;
4707 }
4708 service.app = null;
4709 services.add(service);
4710 }
4711 }
4712
4713 N = services.size();
4714 for (i=0; i<N; i++) {
4715 bringDownServiceLocked(services.get(i), true);
4716 }
4717
4718 resumeTopActivityLocked(null);
4719 }
4720
4721 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4722 final String name = app.processName;
4723 final int uid = app.info.uid;
4724 if (Config.LOGD) Log.d(
4725 TAG, "Force removing process " + app + " (" + name
4726 + "/" + uid + ")");
4727
4728 mProcessNames.remove(name, uid);
4729 boolean needRestart = false;
4730 if (app.pid > 0 && app.pid != MY_PID) {
4731 int pid = app.pid;
4732 synchronized (mPidsSelfLocked) {
4733 mPidsSelfLocked.remove(pid);
4734 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4735 }
4736 handleAppDiedLocked(app, true);
4737 mLRUProcesses.remove(app);
4738 Process.killProcess(pid);
4739
4740 if (app.persistent) {
4741 if (!callerWillRestart) {
4742 addAppLocked(app.info);
4743 } else {
4744 needRestart = true;
4745 }
4746 }
4747 } else {
4748 mRemovedProcesses.add(app);
4749 }
4750
4751 return needRestart;
4752 }
4753
4754 private final void processStartTimedOutLocked(ProcessRecord app) {
4755 final int pid = app.pid;
4756 boolean gone = false;
4757 synchronized (mPidsSelfLocked) {
4758 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4759 if (knownApp != null && knownApp.thread == null) {
4760 mPidsSelfLocked.remove(pid);
4761 gone = true;
4762 }
4763 }
4764
4765 if (gone) {
4766 Log.w(TAG, "Process " + app + " failed to attach");
4767 mProcessNames.remove(app.processName, app.info.uid);
4768 Process.killProcess(pid);
4769 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4770 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4771 mPendingBroadcast = null;
4772 scheduleBroadcastsLocked();
4773 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004774 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4775 Log.w(TAG, "Unattached app died before backup, skipping");
4776 try {
4777 IBackupManager bm = IBackupManager.Stub.asInterface(
4778 ServiceManager.getService(Context.BACKUP_SERVICE));
4779 bm.agentDisconnected(app.info.packageName);
4780 } catch (RemoteException e) {
4781 // Can't happen; the backup manager is local
4782 }
4783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004784 } else {
4785 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4786 }
4787 }
4788
4789 private final boolean attachApplicationLocked(IApplicationThread thread,
4790 int pid) {
4791
4792 // Find the application record that is being attached... either via
4793 // the pid if we are running in multiple processes, or just pull the
4794 // next app record if we are emulating process with anonymous threads.
4795 ProcessRecord app;
4796 if (pid != MY_PID && pid >= 0) {
4797 synchronized (mPidsSelfLocked) {
4798 app = mPidsSelfLocked.get(pid);
4799 }
4800 } else if (mStartingProcesses.size() > 0) {
4801 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004802 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004803 } else {
4804 app = null;
4805 }
4806
4807 if (app == null) {
4808 Log.w(TAG, "No pending application record for pid " + pid
4809 + " (IApplicationThread " + thread + "); dropping process");
4810 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4811 if (pid > 0 && pid != MY_PID) {
4812 Process.killProcess(pid);
4813 } else {
4814 try {
4815 thread.scheduleExit();
4816 } catch (Exception e) {
4817 // Ignore exceptions.
4818 }
4819 }
4820 return false;
4821 }
4822
4823 // If this application record is still attached to a previous
4824 // process, clean it up now.
4825 if (app.thread != null) {
4826 handleAppDiedLocked(app, true);
4827 }
4828
4829 // Tell the process all about itself.
4830
4831 if (localLOGV) Log.v(
4832 TAG, "Binding process pid " + pid + " to record " + app);
4833
4834 String processName = app.processName;
4835 try {
4836 thread.asBinder().linkToDeath(new AppDeathRecipient(
4837 app, pid, thread), 0);
4838 } catch (RemoteException e) {
4839 app.resetPackageList();
4840 startProcessLocked(app, "link fail", processName);
4841 return false;
4842 }
4843
4844 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4845
4846 app.thread = thread;
4847 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004848 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004849 app.forcingToForeground = null;
4850 app.foregroundServices = false;
4851 app.debugging = false;
4852
4853 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4854
4855 List providers = generateApplicationProvidersLocked(app);
4856
4857 if (localLOGV) Log.v(
4858 TAG, "New app record " + app
4859 + " thread=" + thread.asBinder() + " pid=" + pid);
4860 try {
4861 int testMode = IApplicationThread.DEBUG_OFF;
4862 if (mDebugApp != null && mDebugApp.equals(processName)) {
4863 testMode = mWaitForDebugger
4864 ? IApplicationThread.DEBUG_WAIT
4865 : IApplicationThread.DEBUG_ON;
4866 app.debugging = true;
4867 if (mDebugTransient) {
4868 mDebugApp = mOrigDebugApp;
4869 mWaitForDebugger = mOrigWaitForDebugger;
4870 }
4871 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004872 // If the app is being launched for restore or full backup, set it up specially
4873 boolean isRestrictedBackupMode = false;
4874 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4875 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4876 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4877 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004878 ensurePackageDexOpt(app.info.packageName);
4879 if (app.instrumentationInfo != null) {
4880 ensurePackageDexOpt(app.instrumentationInfo.packageName);
4881 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004882 thread.bindApplication(processName, app.instrumentationInfo != null
4883 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004884 app.instrumentationClass, app.instrumentationProfileFile,
4885 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004886 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004887 updateLRUListLocked(app, false);
4888 app.lastRequestedGc = SystemClock.uptimeMillis();
4889 } catch (Exception e) {
4890 // todo: Yikes! What should we do? For now we will try to
4891 // start another process, but that could easily get us in
4892 // an infinite loop of restarting processes...
4893 Log.w(TAG, "Exception thrown during bind!", e);
4894
4895 app.resetPackageList();
4896 startProcessLocked(app, "bind fail", processName);
4897 return false;
4898 }
4899
4900 // Remove this record from the list of starting applications.
4901 mPersistentStartingProcesses.remove(app);
4902 mProcessesOnHold.remove(app);
4903
4904 boolean badApp = false;
4905 boolean didSomething = false;
4906
4907 // See if the top visible activity is waiting to run in this process...
4908 HistoryRecord hr = topRunningActivityLocked(null);
4909 if (hr != null) {
4910 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4911 && processName.equals(hr.processName)) {
4912 try {
4913 if (realStartActivityLocked(hr, app, true, true)) {
4914 didSomething = true;
4915 }
4916 } catch (Exception e) {
4917 Log.w(TAG, "Exception in new application when starting activity "
4918 + hr.intent.getComponent().flattenToShortString(), e);
4919 badApp = true;
4920 }
4921 } else {
4922 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4923 }
4924 }
4925
4926 // Find any services that should be running in this process...
4927 if (!badApp && mPendingServices.size() > 0) {
4928 ServiceRecord sr = null;
4929 try {
4930 for (int i=0; i<mPendingServices.size(); i++) {
4931 sr = mPendingServices.get(i);
4932 if (app.info.uid != sr.appInfo.uid
4933 || !processName.equals(sr.processName)) {
4934 continue;
4935 }
4936
4937 mPendingServices.remove(i);
4938 i--;
4939 realStartServiceLocked(sr, app);
4940 didSomething = true;
4941 }
4942 } catch (Exception e) {
4943 Log.w(TAG, "Exception in new application when starting service "
4944 + sr.shortName, e);
4945 badApp = true;
4946 }
4947 }
4948
4949 // Check if the next broadcast receiver is in this process...
4950 BroadcastRecord br = mPendingBroadcast;
4951 if (!badApp && br != null && br.curApp == app) {
4952 try {
4953 mPendingBroadcast = null;
4954 processCurBroadcastLocked(br, app);
4955 didSomething = true;
4956 } catch (Exception e) {
4957 Log.w(TAG, "Exception in new application when starting receiver "
4958 + br.curComponent.flattenToShortString(), e);
4959 badApp = true;
4960 logBroadcastReceiverDiscard(br);
4961 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4962 br.resultExtras, br.resultAbort, true);
4963 scheduleBroadcastsLocked();
4964 }
4965 }
4966
Christopher Tate181fafa2009-05-14 11:12:14 -07004967 // Check whether the next backup agent is in this process...
4968 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4969 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004970 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07004971 try {
4972 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4973 } catch (Exception e) {
4974 Log.w(TAG, "Exception scheduling backup agent creation: ");
4975 e.printStackTrace();
4976 }
4977 }
4978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004979 if (badApp) {
4980 // todo: Also need to kill application to deal with all
4981 // kinds of exceptions.
4982 handleAppDiedLocked(app, false);
4983 return false;
4984 }
4985
4986 if (!didSomething) {
4987 updateOomAdjLocked();
4988 }
4989
4990 return true;
4991 }
4992
4993 public final void attachApplication(IApplicationThread thread) {
4994 synchronized (this) {
4995 int callingPid = Binder.getCallingPid();
4996 final long origId = Binder.clearCallingIdentity();
4997 attachApplicationLocked(thread, callingPid);
4998 Binder.restoreCallingIdentity(origId);
4999 }
5000 }
5001
5002 public final void activityIdle(IBinder token) {
5003 final long origId = Binder.clearCallingIdentity();
5004 activityIdleInternal(token, false);
5005 Binder.restoreCallingIdentity(origId);
5006 }
5007
5008 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5009 boolean remove) {
5010 int N = mStoppingActivities.size();
5011 if (N <= 0) return null;
5012
5013 ArrayList<HistoryRecord> stops = null;
5014
5015 final boolean nowVisible = mResumedActivity != null
5016 && mResumedActivity.nowVisible
5017 && !mResumedActivity.waitingVisible;
5018 for (int i=0; i<N; i++) {
5019 HistoryRecord s = mStoppingActivities.get(i);
5020 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5021 + nowVisible + " waitingVisible=" + s.waitingVisible
5022 + " finishing=" + s.finishing);
5023 if (s.waitingVisible && nowVisible) {
5024 mWaitingVisibleActivities.remove(s);
5025 s.waitingVisible = false;
5026 if (s.finishing) {
5027 // If this activity is finishing, it is sitting on top of
5028 // everyone else but we now know it is no longer needed...
5029 // so get rid of it. Otherwise, we need to go through the
5030 // normal flow and hide it once we determine that it is
5031 // hidden by the activities in front of it.
5032 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5033 mWindowManager.setAppVisibility(s, false);
5034 }
5035 }
5036 if (!s.waitingVisible && remove) {
5037 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5038 if (stops == null) {
5039 stops = new ArrayList<HistoryRecord>();
5040 }
5041 stops.add(s);
5042 mStoppingActivities.remove(i);
5043 N--;
5044 i--;
5045 }
5046 }
5047
5048 return stops;
5049 }
5050
5051 void enableScreenAfterBoot() {
5052 mWindowManager.enableScreenAfterBoot();
5053 }
5054
5055 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5056 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5057
5058 ArrayList<HistoryRecord> stops = null;
5059 ArrayList<HistoryRecord> finishes = null;
5060 ArrayList<HistoryRecord> thumbnails = null;
5061 int NS = 0;
5062 int NF = 0;
5063 int NT = 0;
5064 IApplicationThread sendThumbnail = null;
5065 boolean booting = false;
5066 boolean enableScreen = false;
5067
5068 synchronized (this) {
5069 if (token != null) {
5070 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5071 }
5072
5073 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005074 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005075 if (index >= 0) {
5076 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5077
5078 // No longer need to keep the device awake.
5079 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5080 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5081 mLaunchingActivity.release();
5082 }
5083
5084 // We are now idle. If someone is waiting for a thumbnail from
5085 // us, we can now deliver.
5086 r.idle = true;
5087 scheduleAppGcsLocked();
5088 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5089 sendThumbnail = r.app.thread;
5090 r.thumbnailNeeded = false;
5091 }
5092
5093 // If this activity is fullscreen, set up to hide those under it.
5094
5095 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5096 ensureActivitiesVisibleLocked(null, 0);
5097
5098 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5099 if (!mBooted && !fromTimeout) {
5100 mBooted = true;
5101 enableScreen = true;
5102 }
5103 }
5104
5105 // Atomically retrieve all of the other things to do.
5106 stops = processStoppingActivitiesLocked(true);
5107 NS = stops != null ? stops.size() : 0;
5108 if ((NF=mFinishingActivities.size()) > 0) {
5109 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5110 mFinishingActivities.clear();
5111 }
5112 if ((NT=mCancelledThumbnails.size()) > 0) {
5113 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5114 mCancelledThumbnails.clear();
5115 }
5116
5117 booting = mBooting;
5118 mBooting = false;
5119 }
5120
5121 int i;
5122
5123 // Send thumbnail if requested.
5124 if (sendThumbnail != null) {
5125 try {
5126 sendThumbnail.requestThumbnail(token);
5127 } catch (Exception e) {
5128 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5129 sendPendingThumbnail(null, token, null, null, true);
5130 }
5131 }
5132
5133 // Stop any activities that are scheduled to do so but have been
5134 // waiting for the next one to start.
5135 for (i=0; i<NS; i++) {
5136 HistoryRecord r = (HistoryRecord)stops.get(i);
5137 synchronized (this) {
5138 if (r.finishing) {
5139 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5140 } else {
5141 stopActivityLocked(r);
5142 }
5143 }
5144 }
5145
5146 // Finish any activities that are scheduled to do so but have been
5147 // waiting for the next one to start.
5148 for (i=0; i<NF; i++) {
5149 HistoryRecord r = (HistoryRecord)finishes.get(i);
5150 synchronized (this) {
5151 destroyActivityLocked(r, true);
5152 }
5153 }
5154
5155 // Report back to any thumbnail receivers.
5156 for (i=0; i<NT; i++) {
5157 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5158 sendPendingThumbnail(r, null, null, null, true);
5159 }
5160
5161 if (booting) {
5162 // Ensure that any processes we had put on hold are now started
5163 // up.
5164 final int NP = mProcessesOnHold.size();
5165 if (NP > 0) {
5166 ArrayList<ProcessRecord> procs =
5167 new ArrayList<ProcessRecord>(mProcessesOnHold);
5168 for (int ip=0; ip<NP; ip++) {
5169 this.startProcessLocked(procs.get(ip), "on-hold", null);
5170 }
5171 }
5172 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5173 // Tell anyone interested that we are done booting!
5174 synchronized (this) {
5175 broadcastIntentLocked(null, null,
5176 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5177 null, null, 0, null, null,
5178 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5179 false, false, MY_PID, Process.SYSTEM_UID);
5180 }
5181 }
5182 }
5183
5184 trimApplications();
5185 //dump();
5186 //mWindowManager.dump();
5187
5188 if (enableScreen) {
5189 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5190 SystemClock.uptimeMillis());
5191 enableScreenAfterBoot();
5192 }
5193 }
5194
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005195 final void ensureScreenEnabled() {
5196 boolean enableScreen;
5197 synchronized (this) {
5198 enableScreen = !mBooted;
5199 mBooted = true;
5200 }
5201
5202 if (enableScreen) {
5203 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5204 SystemClock.uptimeMillis());
5205 enableScreenAfterBoot();
5206 }
5207 }
5208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 public final void activityPaused(IBinder token, Bundle icicle) {
5210 // Refuse possible leaked file descriptors
5211 if (icicle != null && icicle.hasFileDescriptors()) {
5212 throw new IllegalArgumentException("File descriptors passed in Bundle");
5213 }
5214
5215 final long origId = Binder.clearCallingIdentity();
5216 activityPaused(token, icicle, false);
5217 Binder.restoreCallingIdentity(origId);
5218 }
5219
5220 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5221 if (DEBUG_PAUSE) Log.v(
5222 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5223 + ", timeout=" + timeout);
5224
5225 HistoryRecord r = null;
5226
5227 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005228 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005229 if (index >= 0) {
5230 r = (HistoryRecord)mHistory.get(index);
5231 if (!timeout) {
5232 r.icicle = icicle;
5233 r.haveState = true;
5234 }
5235 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5236 if (mPausingActivity == r) {
5237 r.state = ActivityState.PAUSED;
5238 completePauseLocked();
5239 } else {
5240 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5241 System.identityHashCode(r), r.shortComponentName,
5242 mPausingActivity != null
5243 ? mPausingActivity.shortComponentName : "(none)");
5244 }
5245 }
5246 }
5247 }
5248
5249 public final void activityStopped(IBinder token, Bitmap thumbnail,
5250 CharSequence description) {
5251 if (localLOGV) Log.v(
5252 TAG, "Activity stopped: token=" + token);
5253
5254 HistoryRecord r = null;
5255
5256 final long origId = Binder.clearCallingIdentity();
5257
5258 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005259 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005260 if (index >= 0) {
5261 r = (HistoryRecord)mHistory.get(index);
5262 r.thumbnail = thumbnail;
5263 r.description = description;
5264 r.stopped = true;
5265 r.state = ActivityState.STOPPED;
5266 if (!r.finishing) {
5267 if (r.configDestroy) {
5268 destroyActivityLocked(r, true);
5269 resumeTopActivityLocked(null);
5270 }
5271 }
5272 }
5273 }
5274
5275 if (r != null) {
5276 sendPendingThumbnail(r, null, null, null, false);
5277 }
5278
5279 trimApplications();
5280
5281 Binder.restoreCallingIdentity(origId);
5282 }
5283
5284 public final void activityDestroyed(IBinder token) {
5285 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5286 synchronized (this) {
5287 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5288
Dianne Hackborn75b03852009-06-12 15:43:26 -07005289 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005290 if (index >= 0) {
5291 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5292 if (r.state == ActivityState.DESTROYING) {
5293 final long origId = Binder.clearCallingIdentity();
5294 removeActivityFromHistoryLocked(r);
5295 Binder.restoreCallingIdentity(origId);
5296 }
5297 }
5298 }
5299 }
5300
5301 public String getCallingPackage(IBinder token) {
5302 synchronized (this) {
5303 HistoryRecord r = getCallingRecordLocked(token);
5304 return r != null && r.app != null ? r.app.processName : null;
5305 }
5306 }
5307
5308 public ComponentName getCallingActivity(IBinder token) {
5309 synchronized (this) {
5310 HistoryRecord r = getCallingRecordLocked(token);
5311 return r != null ? r.intent.getComponent() : null;
5312 }
5313 }
5314
5315 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005316 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005317 if (index >= 0) {
5318 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5319 if (r != null) {
5320 return r.resultTo;
5321 }
5322 }
5323 return null;
5324 }
5325
5326 public ComponentName getActivityClassForToken(IBinder token) {
5327 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005328 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005329 if (index >= 0) {
5330 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5331 return r.intent.getComponent();
5332 }
5333 return null;
5334 }
5335 }
5336
5337 public String getPackageForToken(IBinder token) {
5338 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005339 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005340 if (index >= 0) {
5341 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5342 return r.packageName;
5343 }
5344 return null;
5345 }
5346 }
5347
5348 public IIntentSender getIntentSender(int type,
5349 String packageName, IBinder token, String resultWho,
5350 int requestCode, Intent intent, String resolvedType, int flags) {
5351 // Refuse possible leaked file descriptors
5352 if (intent != null && intent.hasFileDescriptors() == true) {
5353 throw new IllegalArgumentException("File descriptors passed in Intent");
5354 }
5355
5356 synchronized(this) {
5357 int callingUid = Binder.getCallingUid();
5358 try {
5359 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5360 Process.supportsProcesses()) {
5361 int uid = ActivityThread.getPackageManager()
5362 .getPackageUid(packageName);
5363 if (uid != Binder.getCallingUid()) {
5364 String msg = "Permission Denial: getIntentSender() from pid="
5365 + Binder.getCallingPid()
5366 + ", uid=" + Binder.getCallingUid()
5367 + ", (need uid=" + uid + ")"
5368 + " is not allowed to send as package " + packageName;
5369 Log.w(TAG, msg);
5370 throw new SecurityException(msg);
5371 }
5372 }
5373 } catch (RemoteException e) {
5374 throw new SecurityException(e);
5375 }
5376 HistoryRecord activity = null;
5377 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005378 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005379 if (index < 0) {
5380 return null;
5381 }
5382 activity = (HistoryRecord)mHistory.get(index);
5383 if (activity.finishing) {
5384 return null;
5385 }
5386 }
5387
5388 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5389 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5390 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5391 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5392 |PendingIntent.FLAG_UPDATE_CURRENT);
5393
5394 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5395 type, packageName, activity, resultWho,
5396 requestCode, intent, resolvedType, flags);
5397 WeakReference<PendingIntentRecord> ref;
5398 ref = mIntentSenderRecords.get(key);
5399 PendingIntentRecord rec = ref != null ? ref.get() : null;
5400 if (rec != null) {
5401 if (!cancelCurrent) {
5402 if (updateCurrent) {
5403 rec.key.requestIntent.replaceExtras(intent);
5404 }
5405 return rec;
5406 }
5407 rec.canceled = true;
5408 mIntentSenderRecords.remove(key);
5409 }
5410 if (noCreate) {
5411 return rec;
5412 }
5413 rec = new PendingIntentRecord(this, key, callingUid);
5414 mIntentSenderRecords.put(key, rec.ref);
5415 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5416 if (activity.pendingResults == null) {
5417 activity.pendingResults
5418 = new HashSet<WeakReference<PendingIntentRecord>>();
5419 }
5420 activity.pendingResults.add(rec.ref);
5421 }
5422 return rec;
5423 }
5424 }
5425
5426 public void cancelIntentSender(IIntentSender sender) {
5427 if (!(sender instanceof PendingIntentRecord)) {
5428 return;
5429 }
5430 synchronized(this) {
5431 PendingIntentRecord rec = (PendingIntentRecord)sender;
5432 try {
5433 int uid = ActivityThread.getPackageManager()
5434 .getPackageUid(rec.key.packageName);
5435 if (uid != Binder.getCallingUid()) {
5436 String msg = "Permission Denial: cancelIntentSender() from pid="
5437 + Binder.getCallingPid()
5438 + ", uid=" + Binder.getCallingUid()
5439 + " is not allowed to cancel packges "
5440 + rec.key.packageName;
5441 Log.w(TAG, msg);
5442 throw new SecurityException(msg);
5443 }
5444 } catch (RemoteException e) {
5445 throw new SecurityException(e);
5446 }
5447 cancelIntentSenderLocked(rec, true);
5448 }
5449 }
5450
5451 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5452 rec.canceled = true;
5453 mIntentSenderRecords.remove(rec.key);
5454 if (cleanActivity && rec.key.activity != null) {
5455 rec.key.activity.pendingResults.remove(rec.ref);
5456 }
5457 }
5458
5459 public String getPackageForIntentSender(IIntentSender pendingResult) {
5460 if (!(pendingResult instanceof PendingIntentRecord)) {
5461 return null;
5462 }
5463 synchronized(this) {
5464 try {
5465 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5466 return res.key.packageName;
5467 } catch (ClassCastException e) {
5468 }
5469 }
5470 return null;
5471 }
5472
5473 public void setProcessLimit(int max) {
5474 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5475 "setProcessLimit()");
5476 mProcessLimit = max;
5477 }
5478
5479 public int getProcessLimit() {
5480 return mProcessLimit;
5481 }
5482
5483 void foregroundTokenDied(ForegroundToken token) {
5484 synchronized (ActivityManagerService.this) {
5485 synchronized (mPidsSelfLocked) {
5486 ForegroundToken cur
5487 = mForegroundProcesses.get(token.pid);
5488 if (cur != token) {
5489 return;
5490 }
5491 mForegroundProcesses.remove(token.pid);
5492 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5493 if (pr == null) {
5494 return;
5495 }
5496 pr.forcingToForeground = null;
5497 pr.foregroundServices = false;
5498 }
5499 updateOomAdjLocked();
5500 }
5501 }
5502
5503 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5504 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5505 "setProcessForeground()");
5506 synchronized(this) {
5507 boolean changed = false;
5508
5509 synchronized (mPidsSelfLocked) {
5510 ProcessRecord pr = mPidsSelfLocked.get(pid);
5511 if (pr == null) {
5512 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5513 return;
5514 }
5515 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5516 if (oldToken != null) {
5517 oldToken.token.unlinkToDeath(oldToken, 0);
5518 mForegroundProcesses.remove(pid);
5519 pr.forcingToForeground = null;
5520 changed = true;
5521 }
5522 if (isForeground && token != null) {
5523 ForegroundToken newToken = new ForegroundToken() {
5524 public void binderDied() {
5525 foregroundTokenDied(this);
5526 }
5527 };
5528 newToken.pid = pid;
5529 newToken.token = token;
5530 try {
5531 token.linkToDeath(newToken, 0);
5532 mForegroundProcesses.put(pid, newToken);
5533 pr.forcingToForeground = token;
5534 changed = true;
5535 } catch (RemoteException e) {
5536 // If the process died while doing this, we will later
5537 // do the cleanup with the process death link.
5538 }
5539 }
5540 }
5541
5542 if (changed) {
5543 updateOomAdjLocked();
5544 }
5545 }
5546 }
5547
5548 // =========================================================
5549 // PERMISSIONS
5550 // =========================================================
5551
5552 static class PermissionController extends IPermissionController.Stub {
5553 ActivityManagerService mActivityManagerService;
5554 PermissionController(ActivityManagerService activityManagerService) {
5555 mActivityManagerService = activityManagerService;
5556 }
5557
5558 public boolean checkPermission(String permission, int pid, int uid) {
5559 return mActivityManagerService.checkPermission(permission, pid,
5560 uid) == PackageManager.PERMISSION_GRANTED;
5561 }
5562 }
5563
5564 /**
5565 * This can be called with or without the global lock held.
5566 */
5567 int checkComponentPermission(String permission, int pid, int uid,
5568 int reqUid) {
5569 // We might be performing an operation on behalf of an indirect binder
5570 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5571 // client identity accordingly before proceeding.
5572 Identity tlsIdentity = sCallerIdentity.get();
5573 if (tlsIdentity != null) {
5574 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5575 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5576 uid = tlsIdentity.uid;
5577 pid = tlsIdentity.pid;
5578 }
5579
5580 // Root, system server and our own process get to do everything.
5581 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5582 !Process.supportsProcesses()) {
5583 return PackageManager.PERMISSION_GRANTED;
5584 }
5585 // If the target requires a specific UID, always fail for others.
5586 if (reqUid >= 0 && uid != reqUid) {
5587 return PackageManager.PERMISSION_DENIED;
5588 }
5589 if (permission == null) {
5590 return PackageManager.PERMISSION_GRANTED;
5591 }
5592 try {
5593 return ActivityThread.getPackageManager()
5594 .checkUidPermission(permission, uid);
5595 } catch (RemoteException e) {
5596 // Should never happen, but if it does... deny!
5597 Log.e(TAG, "PackageManager is dead?!?", e);
5598 }
5599 return PackageManager.PERMISSION_DENIED;
5600 }
5601
5602 /**
5603 * As the only public entry point for permissions checking, this method
5604 * can enforce the semantic that requesting a check on a null global
5605 * permission is automatically denied. (Internally a null permission
5606 * string is used when calling {@link #checkComponentPermission} in cases
5607 * when only uid-based security is needed.)
5608 *
5609 * This can be called with or without the global lock held.
5610 */
5611 public int checkPermission(String permission, int pid, int uid) {
5612 if (permission == null) {
5613 return PackageManager.PERMISSION_DENIED;
5614 }
5615 return checkComponentPermission(permission, pid, uid, -1);
5616 }
5617
5618 /**
5619 * Binder IPC calls go through the public entry point.
5620 * This can be called with or without the global lock held.
5621 */
5622 int checkCallingPermission(String permission) {
5623 return checkPermission(permission,
5624 Binder.getCallingPid(),
5625 Binder.getCallingUid());
5626 }
5627
5628 /**
5629 * This can be called with or without the global lock held.
5630 */
5631 void enforceCallingPermission(String permission, String func) {
5632 if (checkCallingPermission(permission)
5633 == PackageManager.PERMISSION_GRANTED) {
5634 return;
5635 }
5636
5637 String msg = "Permission Denial: " + func + " from pid="
5638 + Binder.getCallingPid()
5639 + ", uid=" + Binder.getCallingUid()
5640 + " requires " + permission;
5641 Log.w(TAG, msg);
5642 throw new SecurityException(msg);
5643 }
5644
5645 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5646 ProviderInfo pi, int uid, int modeFlags) {
5647 try {
5648 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5649 if ((pi.readPermission != null) &&
5650 (pm.checkUidPermission(pi.readPermission, uid)
5651 != PackageManager.PERMISSION_GRANTED)) {
5652 return false;
5653 }
5654 }
5655 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5656 if ((pi.writePermission != null) &&
5657 (pm.checkUidPermission(pi.writePermission, uid)
5658 != PackageManager.PERMISSION_GRANTED)) {
5659 return false;
5660 }
5661 }
5662 return true;
5663 } catch (RemoteException e) {
5664 return false;
5665 }
5666 }
5667
5668 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5669 int modeFlags) {
5670 // Root gets to do everything.
5671 if (uid == 0 || !Process.supportsProcesses()) {
5672 return true;
5673 }
5674 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5675 if (perms == null) return false;
5676 UriPermission perm = perms.get(uri);
5677 if (perm == null) return false;
5678 return (modeFlags&perm.modeFlags) == modeFlags;
5679 }
5680
5681 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5682 // Another redirected-binder-call permissions check as in
5683 // {@link checkComponentPermission}.
5684 Identity tlsIdentity = sCallerIdentity.get();
5685 if (tlsIdentity != null) {
5686 uid = tlsIdentity.uid;
5687 pid = tlsIdentity.pid;
5688 }
5689
5690 // Our own process gets to do everything.
5691 if (pid == MY_PID) {
5692 return PackageManager.PERMISSION_GRANTED;
5693 }
5694 synchronized(this) {
5695 return checkUriPermissionLocked(uri, uid, modeFlags)
5696 ? PackageManager.PERMISSION_GRANTED
5697 : PackageManager.PERMISSION_DENIED;
5698 }
5699 }
5700
5701 private void grantUriPermissionLocked(int callingUid,
5702 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5703 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5704 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5705 if (modeFlags == 0) {
5706 return;
5707 }
5708
5709 final IPackageManager pm = ActivityThread.getPackageManager();
5710
5711 // If this is not a content: uri, we can't do anything with it.
5712 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5713 return;
5714 }
5715
5716 String name = uri.getAuthority();
5717 ProviderInfo pi = null;
5718 ContentProviderRecord cpr
5719 = (ContentProviderRecord)mProvidersByName.get(name);
5720 if (cpr != null) {
5721 pi = cpr.info;
5722 } else {
5723 try {
5724 pi = pm.resolveContentProvider(name,
5725 PackageManager.GET_URI_PERMISSION_PATTERNS);
5726 } catch (RemoteException ex) {
5727 }
5728 }
5729 if (pi == null) {
5730 Log.w(TAG, "No content provider found for: " + name);
5731 return;
5732 }
5733
5734 int targetUid;
5735 try {
5736 targetUid = pm.getPackageUid(targetPkg);
5737 if (targetUid < 0) {
5738 return;
5739 }
5740 } catch (RemoteException ex) {
5741 return;
5742 }
5743
5744 // First... does the target actually need this permission?
5745 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5746 // No need to grant the target this permission.
5747 return;
5748 }
5749
5750 // Second... maybe someone else has already granted the
5751 // permission?
5752 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5753 // No need to grant the target this permission.
5754 return;
5755 }
5756
5757 // Third... is the provider allowing granting of URI permissions?
5758 if (!pi.grantUriPermissions) {
5759 throw new SecurityException("Provider " + pi.packageName
5760 + "/" + pi.name
5761 + " does not allow granting of Uri permissions (uri "
5762 + uri + ")");
5763 }
5764 if (pi.uriPermissionPatterns != null) {
5765 final int N = pi.uriPermissionPatterns.length;
5766 boolean allowed = false;
5767 for (int i=0; i<N; i++) {
5768 if (pi.uriPermissionPatterns[i] != null
5769 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5770 allowed = true;
5771 break;
5772 }
5773 }
5774 if (!allowed) {
5775 throw new SecurityException("Provider " + pi.packageName
5776 + "/" + pi.name
5777 + " does not allow granting of permission to path of Uri "
5778 + uri);
5779 }
5780 }
5781
5782 // Fourth... does the caller itself have permission to access
5783 // this uri?
5784 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5785 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5786 throw new SecurityException("Uid " + callingUid
5787 + " does not have permission to uri " + uri);
5788 }
5789 }
5790
5791 // Okay! So here we are: the caller has the assumed permission
5792 // to the uri, and the target doesn't. Let's now give this to
5793 // the target.
5794
5795 HashMap<Uri, UriPermission> targetUris
5796 = mGrantedUriPermissions.get(targetUid);
5797 if (targetUris == null) {
5798 targetUris = new HashMap<Uri, UriPermission>();
5799 mGrantedUriPermissions.put(targetUid, targetUris);
5800 }
5801
5802 UriPermission perm = targetUris.get(uri);
5803 if (perm == null) {
5804 perm = new UriPermission(targetUid, uri);
5805 targetUris.put(uri, perm);
5806
5807 }
5808 perm.modeFlags |= modeFlags;
5809 if (activity == null) {
5810 perm.globalModeFlags |= modeFlags;
5811 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5812 perm.readActivities.add(activity);
5813 if (activity.readUriPermissions == null) {
5814 activity.readUriPermissions = new HashSet<UriPermission>();
5815 }
5816 activity.readUriPermissions.add(perm);
5817 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5818 perm.writeActivities.add(activity);
5819 if (activity.writeUriPermissions == null) {
5820 activity.writeUriPermissions = new HashSet<UriPermission>();
5821 }
5822 activity.writeUriPermissions.add(perm);
5823 }
5824 }
5825
5826 private void grantUriPermissionFromIntentLocked(int callingUid,
5827 String targetPkg, Intent intent, HistoryRecord activity) {
5828 if (intent == null) {
5829 return;
5830 }
5831 Uri data = intent.getData();
5832 if (data == null) {
5833 return;
5834 }
5835 grantUriPermissionLocked(callingUid, targetPkg, data,
5836 intent.getFlags(), activity);
5837 }
5838
5839 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5840 Uri uri, int modeFlags) {
5841 synchronized(this) {
5842 final ProcessRecord r = getRecordForAppLocked(caller);
5843 if (r == null) {
5844 throw new SecurityException("Unable to find app for caller "
5845 + caller
5846 + " when granting permission to uri " + uri);
5847 }
5848 if (targetPkg == null) {
5849 Log.w(TAG, "grantUriPermission: null target");
5850 return;
5851 }
5852 if (uri == null) {
5853 Log.w(TAG, "grantUriPermission: null uri");
5854 return;
5855 }
5856
5857 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5858 null);
5859 }
5860 }
5861
5862 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5863 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5864 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5865 HashMap<Uri, UriPermission> perms
5866 = mGrantedUriPermissions.get(perm.uid);
5867 if (perms != null) {
5868 perms.remove(perm.uri);
5869 if (perms.size() == 0) {
5870 mGrantedUriPermissions.remove(perm.uid);
5871 }
5872 }
5873 }
5874 }
5875
5876 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5877 if (activity.readUriPermissions != null) {
5878 for (UriPermission perm : activity.readUriPermissions) {
5879 perm.readActivities.remove(activity);
5880 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5881 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5882 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5883 removeUriPermissionIfNeededLocked(perm);
5884 }
5885 }
5886 }
5887 if (activity.writeUriPermissions != null) {
5888 for (UriPermission perm : activity.writeUriPermissions) {
5889 perm.writeActivities.remove(activity);
5890 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5891 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5892 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5893 removeUriPermissionIfNeededLocked(perm);
5894 }
5895 }
5896 }
5897 }
5898
5899 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5900 int modeFlags) {
5901 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5902 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5903 if (modeFlags == 0) {
5904 return;
5905 }
5906
5907 final IPackageManager pm = ActivityThread.getPackageManager();
5908
5909 final String authority = uri.getAuthority();
5910 ProviderInfo pi = null;
5911 ContentProviderRecord cpr
5912 = (ContentProviderRecord)mProvidersByName.get(authority);
5913 if (cpr != null) {
5914 pi = cpr.info;
5915 } else {
5916 try {
5917 pi = pm.resolveContentProvider(authority,
5918 PackageManager.GET_URI_PERMISSION_PATTERNS);
5919 } catch (RemoteException ex) {
5920 }
5921 }
5922 if (pi == null) {
5923 Log.w(TAG, "No content provider found for: " + authority);
5924 return;
5925 }
5926
5927 // Does the caller have this permission on the URI?
5928 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5929 // Right now, if you are not the original owner of the permission,
5930 // you are not allowed to revoke it.
5931 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5932 throw new SecurityException("Uid " + callingUid
5933 + " does not have permission to uri " + uri);
5934 //}
5935 }
5936
5937 // Go through all of the permissions and remove any that match.
5938 final List<String> SEGMENTS = uri.getPathSegments();
5939 if (SEGMENTS != null) {
5940 final int NS = SEGMENTS.size();
5941 int N = mGrantedUriPermissions.size();
5942 for (int i=0; i<N; i++) {
5943 HashMap<Uri, UriPermission> perms
5944 = mGrantedUriPermissions.valueAt(i);
5945 Iterator<UriPermission> it = perms.values().iterator();
5946 toploop:
5947 while (it.hasNext()) {
5948 UriPermission perm = it.next();
5949 Uri targetUri = perm.uri;
5950 if (!authority.equals(targetUri.getAuthority())) {
5951 continue;
5952 }
5953 List<String> targetSegments = targetUri.getPathSegments();
5954 if (targetSegments == null) {
5955 continue;
5956 }
5957 if (targetSegments.size() < NS) {
5958 continue;
5959 }
5960 for (int j=0; j<NS; j++) {
5961 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5962 continue toploop;
5963 }
5964 }
5965 perm.clearModes(modeFlags);
5966 if (perm.modeFlags == 0) {
5967 it.remove();
5968 }
5969 }
5970 if (perms.size() == 0) {
5971 mGrantedUriPermissions.remove(
5972 mGrantedUriPermissions.keyAt(i));
5973 N--;
5974 i--;
5975 }
5976 }
5977 }
5978 }
5979
5980 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5981 int modeFlags) {
5982 synchronized(this) {
5983 final ProcessRecord r = getRecordForAppLocked(caller);
5984 if (r == null) {
5985 throw new SecurityException("Unable to find app for caller "
5986 + caller
5987 + " when revoking permission to uri " + uri);
5988 }
5989 if (uri == null) {
5990 Log.w(TAG, "revokeUriPermission: null uri");
5991 return;
5992 }
5993
5994 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5995 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5996 if (modeFlags == 0) {
5997 return;
5998 }
5999
6000 final IPackageManager pm = ActivityThread.getPackageManager();
6001
6002 final String authority = uri.getAuthority();
6003 ProviderInfo pi = null;
6004 ContentProviderRecord cpr
6005 = (ContentProviderRecord)mProvidersByName.get(authority);
6006 if (cpr != null) {
6007 pi = cpr.info;
6008 } else {
6009 try {
6010 pi = pm.resolveContentProvider(authority,
6011 PackageManager.GET_URI_PERMISSION_PATTERNS);
6012 } catch (RemoteException ex) {
6013 }
6014 }
6015 if (pi == null) {
6016 Log.w(TAG, "No content provider found for: " + authority);
6017 return;
6018 }
6019
6020 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6021 }
6022 }
6023
6024 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6025 synchronized (this) {
6026 ProcessRecord app =
6027 who != null ? getRecordForAppLocked(who) : null;
6028 if (app == null) return;
6029
6030 Message msg = Message.obtain();
6031 msg.what = WAIT_FOR_DEBUGGER_MSG;
6032 msg.obj = app;
6033 msg.arg1 = waiting ? 1 : 0;
6034 mHandler.sendMessage(msg);
6035 }
6036 }
6037
6038 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6039 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006040 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006041 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006042 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006043 }
6044
6045 // =========================================================
6046 // TASK MANAGEMENT
6047 // =========================================================
6048
6049 public List getTasks(int maxNum, int flags,
6050 IThumbnailReceiver receiver) {
6051 ArrayList list = new ArrayList();
6052
6053 PendingThumbnailsRecord pending = null;
6054 IApplicationThread topThumbnail = null;
6055 HistoryRecord topRecord = null;
6056
6057 synchronized(this) {
6058 if (localLOGV) Log.v(
6059 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6060 + ", receiver=" + receiver);
6061
6062 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6063 != PackageManager.PERMISSION_GRANTED) {
6064 if (receiver != null) {
6065 // If the caller wants to wait for pending thumbnails,
6066 // it ain't gonna get them.
6067 try {
6068 receiver.finished();
6069 } catch (RemoteException ex) {
6070 }
6071 }
6072 String msg = "Permission Denial: getTasks() from pid="
6073 + Binder.getCallingPid()
6074 + ", uid=" + Binder.getCallingUid()
6075 + " requires " + android.Manifest.permission.GET_TASKS;
6076 Log.w(TAG, msg);
6077 throw new SecurityException(msg);
6078 }
6079
6080 int pos = mHistory.size()-1;
6081 HistoryRecord next =
6082 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6083 HistoryRecord top = null;
6084 CharSequence topDescription = null;
6085 TaskRecord curTask = null;
6086 int numActivities = 0;
6087 int numRunning = 0;
6088 while (pos >= 0 && maxNum > 0) {
6089 final HistoryRecord r = next;
6090 pos--;
6091 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6092
6093 // Initialize state for next task if needed.
6094 if (top == null ||
6095 (top.state == ActivityState.INITIALIZING
6096 && top.task == r.task)) {
6097 top = r;
6098 topDescription = r.description;
6099 curTask = r.task;
6100 numActivities = numRunning = 0;
6101 }
6102
6103 // Add 'r' into the current task.
6104 numActivities++;
6105 if (r.app != null && r.app.thread != null) {
6106 numRunning++;
6107 }
6108 if (topDescription == null) {
6109 topDescription = r.description;
6110 }
6111
6112 if (localLOGV) Log.v(
6113 TAG, r.intent.getComponent().flattenToShortString()
6114 + ": task=" + r.task);
6115
6116 // If the next one is a different task, generate a new
6117 // TaskInfo entry for what we have.
6118 if (next == null || next.task != curTask) {
6119 ActivityManager.RunningTaskInfo ci
6120 = new ActivityManager.RunningTaskInfo();
6121 ci.id = curTask.taskId;
6122 ci.baseActivity = r.intent.getComponent();
6123 ci.topActivity = top.intent.getComponent();
6124 ci.thumbnail = top.thumbnail;
6125 ci.description = topDescription;
6126 ci.numActivities = numActivities;
6127 ci.numRunning = numRunning;
6128 //System.out.println(
6129 // "#" + maxNum + ": " + " descr=" + ci.description);
6130 if (ci.thumbnail == null && receiver != null) {
6131 if (localLOGV) Log.v(
6132 TAG, "State=" + top.state + "Idle=" + top.idle
6133 + " app=" + top.app
6134 + " thr=" + (top.app != null ? top.app.thread : null));
6135 if (top.state == ActivityState.RESUMED
6136 || top.state == ActivityState.PAUSING) {
6137 if (top.idle && top.app != null
6138 && top.app.thread != null) {
6139 topRecord = top;
6140 topThumbnail = top.app.thread;
6141 } else {
6142 top.thumbnailNeeded = true;
6143 }
6144 }
6145 if (pending == null) {
6146 pending = new PendingThumbnailsRecord(receiver);
6147 }
6148 pending.pendingRecords.add(top);
6149 }
6150 list.add(ci);
6151 maxNum--;
6152 top = null;
6153 }
6154 }
6155
6156 if (pending != null) {
6157 mPendingThumbnails.add(pending);
6158 }
6159 }
6160
6161 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6162
6163 if (topThumbnail != null) {
6164 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6165 try {
6166 topThumbnail.requestThumbnail(topRecord);
6167 } catch (Exception e) {
6168 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6169 sendPendingThumbnail(null, topRecord, null, null, true);
6170 }
6171 }
6172
6173 if (pending == null && receiver != null) {
6174 // In this case all thumbnails were available and the client
6175 // is being asked to be told when the remaining ones come in...
6176 // which is unusually, since the top-most currently running
6177 // activity should never have a canned thumbnail! Oh well.
6178 try {
6179 receiver.finished();
6180 } catch (RemoteException ex) {
6181 }
6182 }
6183
6184 return list;
6185 }
6186
6187 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6188 int flags) {
6189 synchronized (this) {
6190 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6191 "getRecentTasks()");
6192
6193 final int N = mRecentTasks.size();
6194 ArrayList<ActivityManager.RecentTaskInfo> res
6195 = new ArrayList<ActivityManager.RecentTaskInfo>(
6196 maxNum < N ? maxNum : N);
6197 for (int i=0; i<N && maxNum > 0; i++) {
6198 TaskRecord tr = mRecentTasks.get(i);
6199 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6200 || (tr.intent == null)
6201 || ((tr.intent.getFlags()
6202 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6203 ActivityManager.RecentTaskInfo rti
6204 = new ActivityManager.RecentTaskInfo();
6205 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6206 rti.baseIntent = new Intent(
6207 tr.intent != null ? tr.intent : tr.affinityIntent);
6208 rti.origActivity = tr.origActivity;
6209 res.add(rti);
6210 maxNum--;
6211 }
6212 }
6213 return res;
6214 }
6215 }
6216
6217 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6218 int j;
6219 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6220 TaskRecord jt = startTask;
6221
6222 // First look backwards
6223 for (j=startIndex-1; j>=0; j--) {
6224 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6225 if (r.task != jt) {
6226 jt = r.task;
6227 if (affinity.equals(jt.affinity)) {
6228 return j;
6229 }
6230 }
6231 }
6232
6233 // Now look forwards
6234 final int N = mHistory.size();
6235 jt = startTask;
6236 for (j=startIndex+1; j<N; j++) {
6237 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6238 if (r.task != jt) {
6239 if (affinity.equals(jt.affinity)) {
6240 return j;
6241 }
6242 jt = r.task;
6243 }
6244 }
6245
6246 // Might it be at the top?
6247 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6248 return N-1;
6249 }
6250
6251 return -1;
6252 }
6253
6254 /**
6255 * Perform a reset of the given task, if needed as part of launching it.
6256 * Returns the new HistoryRecord at the top of the task.
6257 */
6258 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6259 HistoryRecord newActivity) {
6260 boolean forceReset = (newActivity.info.flags
6261 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6262 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6263 if ((newActivity.info.flags
6264 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6265 forceReset = true;
6266 }
6267 }
6268
6269 final TaskRecord task = taskTop.task;
6270
6271 // We are going to move through the history list so that we can look
6272 // at each activity 'target' with 'below' either the interesting
6273 // activity immediately below it in the stack or null.
6274 HistoryRecord target = null;
6275 int targetI = 0;
6276 int taskTopI = -1;
6277 int replyChainEnd = -1;
6278 int lastReparentPos = -1;
6279 for (int i=mHistory.size()-1; i>=-1; i--) {
6280 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6281
6282 if (below != null && below.finishing) {
6283 continue;
6284 }
6285 if (target == null) {
6286 target = below;
6287 targetI = i;
6288 // If we were in the middle of a reply chain before this
6289 // task, it doesn't appear like the root of the chain wants
6290 // anything interesting, so drop it.
6291 replyChainEnd = -1;
6292 continue;
6293 }
6294
6295 final int flags = target.info.flags;
6296
6297 final boolean finishOnTaskLaunch =
6298 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6299 final boolean allowTaskReparenting =
6300 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6301
6302 if (target.task == task) {
6303 // We are inside of the task being reset... we'll either
6304 // finish this activity, push it out for another task,
6305 // or leave it as-is. We only do this
6306 // for activities that are not the root of the task (since
6307 // if we finish the root, we may no longer have the task!).
6308 if (taskTopI < 0) {
6309 taskTopI = targetI;
6310 }
6311 if (below != null && below.task == task) {
6312 final boolean clearWhenTaskReset =
6313 (target.intent.getFlags()
6314 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006315 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006316 // If this activity is sending a reply to a previous
6317 // activity, we can't do anything with it now until
6318 // we reach the start of the reply chain.
6319 // XXX note that we are assuming the result is always
6320 // to the previous activity, which is almost always
6321 // the case but we really shouldn't count on.
6322 if (replyChainEnd < 0) {
6323 replyChainEnd = targetI;
6324 }
Ed Heyl73798232009-03-24 21:32:21 -07006325 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006326 && target.taskAffinity != null
6327 && !target.taskAffinity.equals(task.affinity)) {
6328 // If this activity has an affinity for another
6329 // task, then we need to move it out of here. We will
6330 // move it as far out of the way as possible, to the
6331 // bottom of the activity stack. This also keeps it
6332 // correctly ordered with any activities we previously
6333 // moved.
6334 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6335 if (target.taskAffinity != null
6336 && target.taskAffinity.equals(p.task.affinity)) {
6337 // If the activity currently at the bottom has the
6338 // same task affinity as the one we are moving,
6339 // then merge it into the same task.
6340 target.task = p.task;
6341 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6342 + " out to bottom task " + p.task);
6343 } else {
6344 mCurTask++;
6345 if (mCurTask <= 0) {
6346 mCurTask = 1;
6347 }
6348 target.task = new TaskRecord(mCurTask, target.info, null,
6349 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6350 target.task.affinityIntent = target.intent;
6351 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6352 + " out to new task " + target.task);
6353 }
6354 mWindowManager.setAppGroupId(target, task.taskId);
6355 if (replyChainEnd < 0) {
6356 replyChainEnd = targetI;
6357 }
6358 int dstPos = 0;
6359 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6360 p = (HistoryRecord)mHistory.get(srcPos);
6361 if (p.finishing) {
6362 continue;
6363 }
6364 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6365 + " out to target's task " + target.task);
6366 task.numActivities--;
6367 p.task = target.task;
6368 target.task.numActivities++;
6369 mHistory.remove(srcPos);
6370 mHistory.add(dstPos, p);
6371 mWindowManager.moveAppToken(dstPos, p);
6372 mWindowManager.setAppGroupId(p, p.task.taskId);
6373 dstPos++;
6374 if (VALIDATE_TOKENS) {
6375 mWindowManager.validateAppTokens(mHistory);
6376 }
6377 i++;
6378 }
6379 if (taskTop == p) {
6380 taskTop = below;
6381 }
6382 if (taskTopI == replyChainEnd) {
6383 taskTopI = -1;
6384 }
6385 replyChainEnd = -1;
6386 addRecentTask(target.task);
6387 } else if (forceReset || finishOnTaskLaunch
6388 || clearWhenTaskReset) {
6389 // If the activity should just be removed -- either
6390 // because it asks for it, or the task should be
6391 // cleared -- then finish it and anything that is
6392 // part of its reply chain.
6393 if (clearWhenTaskReset) {
6394 // In this case, we want to finish this activity
6395 // and everything above it, so be sneaky and pretend
6396 // like these are all in the reply chain.
6397 replyChainEnd = targetI+1;
6398 while (replyChainEnd < mHistory.size() &&
6399 ((HistoryRecord)mHistory.get(
6400 replyChainEnd)).task == task) {
6401 replyChainEnd++;
6402 }
6403 replyChainEnd--;
6404 } else if (replyChainEnd < 0) {
6405 replyChainEnd = targetI;
6406 }
6407 HistoryRecord p = null;
6408 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6409 p = (HistoryRecord)mHistory.get(srcPos);
6410 if (p.finishing) {
6411 continue;
6412 }
6413 if (finishActivityLocked(p, srcPos,
6414 Activity.RESULT_CANCELED, null, "reset")) {
6415 replyChainEnd--;
6416 srcPos--;
6417 }
6418 }
6419 if (taskTop == p) {
6420 taskTop = below;
6421 }
6422 if (taskTopI == replyChainEnd) {
6423 taskTopI = -1;
6424 }
6425 replyChainEnd = -1;
6426 } else {
6427 // If we were in the middle of a chain, well the
6428 // activity that started it all doesn't want anything
6429 // special, so leave it all as-is.
6430 replyChainEnd = -1;
6431 }
6432 } else {
6433 // Reached the bottom of the task -- any reply chain
6434 // should be left as-is.
6435 replyChainEnd = -1;
6436 }
6437
6438 } else if (target.resultTo != null) {
6439 // If this activity is sending a reply to a previous
6440 // activity, we can't do anything with it now until
6441 // we reach the start of the reply chain.
6442 // XXX note that we are assuming the result is always
6443 // to the previous activity, which is almost always
6444 // the case but we really shouldn't count on.
6445 if (replyChainEnd < 0) {
6446 replyChainEnd = targetI;
6447 }
6448
6449 } else if (taskTopI >= 0 && allowTaskReparenting
6450 && task.affinity != null
6451 && task.affinity.equals(target.taskAffinity)) {
6452 // We are inside of another task... if this activity has
6453 // an affinity for our task, then either remove it if we are
6454 // clearing or move it over to our task. Note that
6455 // we currently punt on the case where we are resetting a
6456 // task that is not at the top but who has activities above
6457 // with an affinity to it... this is really not a normal
6458 // case, and we will need to later pull that task to the front
6459 // and usually at that point we will do the reset and pick
6460 // up those remaining activities. (This only happens if
6461 // someone starts an activity in a new task from an activity
6462 // in a task that is not currently on top.)
6463 if (forceReset || finishOnTaskLaunch) {
6464 if (replyChainEnd < 0) {
6465 replyChainEnd = targetI;
6466 }
6467 HistoryRecord p = null;
6468 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6469 p = (HistoryRecord)mHistory.get(srcPos);
6470 if (p.finishing) {
6471 continue;
6472 }
6473 if (finishActivityLocked(p, srcPos,
6474 Activity.RESULT_CANCELED, null, "reset")) {
6475 taskTopI--;
6476 lastReparentPos--;
6477 replyChainEnd--;
6478 srcPos--;
6479 }
6480 }
6481 replyChainEnd = -1;
6482 } else {
6483 if (replyChainEnd < 0) {
6484 replyChainEnd = targetI;
6485 }
6486 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6487 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6488 if (p.finishing) {
6489 continue;
6490 }
6491 if (lastReparentPos < 0) {
6492 lastReparentPos = taskTopI;
6493 taskTop = p;
6494 } else {
6495 lastReparentPos--;
6496 }
6497 mHistory.remove(srcPos);
6498 p.task.numActivities--;
6499 p.task = task;
6500 mHistory.add(lastReparentPos, p);
6501 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6502 + " in to resetting task " + task);
6503 task.numActivities++;
6504 mWindowManager.moveAppToken(lastReparentPos, p);
6505 mWindowManager.setAppGroupId(p, p.task.taskId);
6506 if (VALIDATE_TOKENS) {
6507 mWindowManager.validateAppTokens(mHistory);
6508 }
6509 }
6510 replyChainEnd = -1;
6511
6512 // Now we've moved it in to place... but what if this is
6513 // a singleTop activity and we have put it on top of another
6514 // instance of the same activity? Then we drop the instance
6515 // below so it remains singleTop.
6516 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6517 for (int j=lastReparentPos-1; j>=0; j--) {
6518 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6519 if (p.finishing) {
6520 continue;
6521 }
6522 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6523 if (finishActivityLocked(p, j,
6524 Activity.RESULT_CANCELED, null, "replace")) {
6525 taskTopI--;
6526 lastReparentPos--;
6527 }
6528 }
6529 }
6530 }
6531 }
6532 }
6533
6534 target = below;
6535 targetI = i;
6536 }
6537
6538 return taskTop;
6539 }
6540
6541 /**
6542 * TODO: Add mWatcher hook
6543 */
6544 public void moveTaskToFront(int task) {
6545 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6546 "moveTaskToFront()");
6547
6548 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006549 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6550 Binder.getCallingUid(), "Task to front")) {
6551 return;
6552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006553 final long origId = Binder.clearCallingIdentity();
6554 try {
6555 int N = mRecentTasks.size();
6556 for (int i=0; i<N; i++) {
6557 TaskRecord tr = mRecentTasks.get(i);
6558 if (tr.taskId == task) {
6559 moveTaskToFrontLocked(tr);
6560 return;
6561 }
6562 }
6563 for (int i=mHistory.size()-1; i>=0; i--) {
6564 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6565 if (hr.task.taskId == task) {
6566 moveTaskToFrontLocked(hr.task);
6567 return;
6568 }
6569 }
6570 } finally {
6571 Binder.restoreCallingIdentity(origId);
6572 }
6573 }
6574 }
6575
6576 private final void moveTaskToFrontLocked(TaskRecord tr) {
6577 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6578
6579 final int task = tr.taskId;
6580 int top = mHistory.size()-1;
6581
6582 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6583 // nothing to do!
6584 return;
6585 }
6586
6587 if (DEBUG_TRANSITION) Log.v(TAG,
6588 "Prepare to front transition: task=" + tr);
6589 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6590
6591 ArrayList moved = new ArrayList();
6592
6593 // Applying the affinities may have removed entries from the history,
6594 // so get the size again.
6595 top = mHistory.size()-1;
6596 int pos = top;
6597
6598 // Shift all activities with this task up to the top
6599 // of the stack, keeping them in the same internal order.
6600 while (pos >= 0) {
6601 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6602 if (localLOGV) Log.v(
6603 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6604 boolean first = true;
6605 if (r.task.taskId == task) {
6606 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6607 mHistory.remove(pos);
6608 mHistory.add(top, r);
6609 moved.add(0, r);
6610 top--;
6611 if (first) {
6612 addRecentTask(r.task);
6613 first = false;
6614 }
6615 }
6616 pos--;
6617 }
6618
6619 mWindowManager.moveAppTokensToTop(moved);
6620 if (VALIDATE_TOKENS) {
6621 mWindowManager.validateAppTokens(mHistory);
6622 }
6623
6624 finishTaskMove(task);
6625 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6626 }
6627
6628 private final void finishTaskMove(int task) {
6629 resumeTopActivityLocked(null);
6630 }
6631
6632 public void moveTaskToBack(int task) {
6633 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6634 "moveTaskToBack()");
6635
6636 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006637 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6638 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6639 Binder.getCallingUid(), "Task to back")) {
6640 return;
6641 }
6642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006643 final long origId = Binder.clearCallingIdentity();
6644 moveTaskToBackLocked(task);
6645 Binder.restoreCallingIdentity(origId);
6646 }
6647 }
6648
6649 /**
6650 * Moves an activity, and all of the other activities within the same task, to the bottom
6651 * of the history stack. The activity's order within the task is unchanged.
6652 *
6653 * @param token A reference to the activity we wish to move
6654 * @param nonRoot If false then this only works if the activity is the root
6655 * of a task; if true it will work for any activity in a task.
6656 * @return Returns true if the move completed, false if not.
6657 */
6658 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6659 synchronized(this) {
6660 final long origId = Binder.clearCallingIdentity();
6661 int taskId = getTaskForActivityLocked(token, !nonRoot);
6662 if (taskId >= 0) {
6663 return moveTaskToBackLocked(taskId);
6664 }
6665 Binder.restoreCallingIdentity(origId);
6666 }
6667 return false;
6668 }
6669
6670 /**
6671 * Worker method for rearranging history stack. Implements the function of moving all
6672 * activities for a specific task (gathering them if disjoint) into a single group at the
6673 * bottom of the stack.
6674 *
6675 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6676 * to premeptively cancel the move.
6677 *
6678 * @param task The taskId to collect and move to the bottom.
6679 * @return Returns true if the move completed, false if not.
6680 */
6681 private final boolean moveTaskToBackLocked(int task) {
6682 Log.i(TAG, "moveTaskToBack: " + task);
6683
6684 // If we have a watcher, preflight the move before committing to it. First check
6685 // for *other* available tasks, but if none are available, then try again allowing the
6686 // current task to be selected.
6687 if (mWatcher != null) {
6688 HistoryRecord next = topRunningActivityLocked(null, task);
6689 if (next == null) {
6690 next = topRunningActivityLocked(null, 0);
6691 }
6692 if (next != null) {
6693 // ask watcher if this is allowed
6694 boolean moveOK = true;
6695 try {
6696 moveOK = mWatcher.activityResuming(next.packageName);
6697 } catch (RemoteException e) {
6698 mWatcher = null;
6699 }
6700 if (!moveOK) {
6701 return false;
6702 }
6703 }
6704 }
6705
6706 ArrayList moved = new ArrayList();
6707
6708 if (DEBUG_TRANSITION) Log.v(TAG,
6709 "Prepare to back transition: task=" + task);
6710 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6711
6712 final int N = mHistory.size();
6713 int bottom = 0;
6714 int pos = 0;
6715
6716 // Shift all activities with this task down to the bottom
6717 // of the stack, keeping them in the same internal order.
6718 while (pos < N) {
6719 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6720 if (localLOGV) Log.v(
6721 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6722 if (r.task.taskId == task) {
6723 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6724 mHistory.remove(pos);
6725 mHistory.add(bottom, r);
6726 moved.add(r);
6727 bottom++;
6728 }
6729 pos++;
6730 }
6731
6732 mWindowManager.moveAppTokensToBottom(moved);
6733 if (VALIDATE_TOKENS) {
6734 mWindowManager.validateAppTokens(mHistory);
6735 }
6736
6737 finishTaskMove(task);
6738 return true;
6739 }
6740
6741 public void moveTaskBackwards(int task) {
6742 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6743 "moveTaskBackwards()");
6744
6745 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006746 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6747 Binder.getCallingUid(), "Task backwards")) {
6748 return;
6749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006750 final long origId = Binder.clearCallingIdentity();
6751 moveTaskBackwardsLocked(task);
6752 Binder.restoreCallingIdentity(origId);
6753 }
6754 }
6755
6756 private final void moveTaskBackwardsLocked(int task) {
6757 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6758 }
6759
6760 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6761 synchronized(this) {
6762 return getTaskForActivityLocked(token, onlyRoot);
6763 }
6764 }
6765
6766 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6767 final int N = mHistory.size();
6768 TaskRecord lastTask = null;
6769 for (int i=0; i<N; i++) {
6770 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6771 if (r == token) {
6772 if (!onlyRoot || lastTask != r.task) {
6773 return r.task.taskId;
6774 }
6775 return -1;
6776 }
6777 lastTask = r.task;
6778 }
6779
6780 return -1;
6781 }
6782
6783 /**
6784 * Returns the top activity in any existing task matching the given
6785 * Intent. Returns null if no such task is found.
6786 */
6787 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6788 ComponentName cls = intent.getComponent();
6789 if (info.targetActivity != null) {
6790 cls = new ComponentName(info.packageName, info.targetActivity);
6791 }
6792
6793 TaskRecord cp = null;
6794
6795 final int N = mHistory.size();
6796 for (int i=(N-1); i>=0; i--) {
6797 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6798 if (!r.finishing && r.task != cp
6799 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6800 cp = r.task;
6801 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6802 // + "/aff=" + r.task.affinity + " to new cls="
6803 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6804 if (r.task.affinity != null) {
6805 if (r.task.affinity.equals(info.taskAffinity)) {
6806 //Log.i(TAG, "Found matching affinity!");
6807 return r;
6808 }
6809 } else if (r.task.intent != null
6810 && r.task.intent.getComponent().equals(cls)) {
6811 //Log.i(TAG, "Found matching class!");
6812 //dump();
6813 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6814 return r;
6815 } else if (r.task.affinityIntent != null
6816 && r.task.affinityIntent.getComponent().equals(cls)) {
6817 //Log.i(TAG, "Found matching class!");
6818 //dump();
6819 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6820 return r;
6821 }
6822 }
6823 }
6824
6825 return null;
6826 }
6827
6828 /**
6829 * Returns the first activity (starting from the top of the stack) that
6830 * is the same as the given activity. Returns null if no such activity
6831 * is found.
6832 */
6833 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6834 ComponentName cls = intent.getComponent();
6835 if (info.targetActivity != null) {
6836 cls = new ComponentName(info.packageName, info.targetActivity);
6837 }
6838
6839 final int N = mHistory.size();
6840 for (int i=(N-1); i>=0; i--) {
6841 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6842 if (!r.finishing) {
6843 if (r.intent.getComponent().equals(cls)) {
6844 //Log.i(TAG, "Found matching class!");
6845 //dump();
6846 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6847 return r;
6848 }
6849 }
6850 }
6851
6852 return null;
6853 }
6854
6855 public void finishOtherInstances(IBinder token, ComponentName className) {
6856 synchronized(this) {
6857 final long origId = Binder.clearCallingIdentity();
6858
6859 int N = mHistory.size();
6860 TaskRecord lastTask = null;
6861 for (int i=0; i<N; i++) {
6862 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6863 if (r.realActivity.equals(className)
6864 && r != token && lastTask != r.task) {
6865 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6866 null, "others")) {
6867 i--;
6868 N--;
6869 }
6870 }
6871 lastTask = r.task;
6872 }
6873
6874 Binder.restoreCallingIdentity(origId);
6875 }
6876 }
6877
6878 // =========================================================
6879 // THUMBNAILS
6880 // =========================================================
6881
6882 public void reportThumbnail(IBinder token,
6883 Bitmap thumbnail, CharSequence description) {
6884 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6885 final long origId = Binder.clearCallingIdentity();
6886 sendPendingThumbnail(null, token, thumbnail, description, true);
6887 Binder.restoreCallingIdentity(origId);
6888 }
6889
6890 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6891 Bitmap thumbnail, CharSequence description, boolean always) {
6892 TaskRecord task = null;
6893 ArrayList receivers = null;
6894
6895 //System.out.println("Send pending thumbnail: " + r);
6896
6897 synchronized(this) {
6898 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006899 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006900 if (index < 0) {
6901 return;
6902 }
6903 r = (HistoryRecord)mHistory.get(index);
6904 }
6905 if (thumbnail == null) {
6906 thumbnail = r.thumbnail;
6907 description = r.description;
6908 }
6909 if (thumbnail == null && !always) {
6910 // If there is no thumbnail, and this entry is not actually
6911 // going away, then abort for now and pick up the next
6912 // thumbnail we get.
6913 return;
6914 }
6915 task = r.task;
6916
6917 int N = mPendingThumbnails.size();
6918 int i=0;
6919 while (i<N) {
6920 PendingThumbnailsRecord pr =
6921 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6922 //System.out.println("Looking in " + pr.pendingRecords);
6923 if (pr.pendingRecords.remove(r)) {
6924 if (receivers == null) {
6925 receivers = new ArrayList();
6926 }
6927 receivers.add(pr);
6928 if (pr.pendingRecords.size() == 0) {
6929 pr.finished = true;
6930 mPendingThumbnails.remove(i);
6931 N--;
6932 continue;
6933 }
6934 }
6935 i++;
6936 }
6937 }
6938
6939 if (receivers != null) {
6940 final int N = receivers.size();
6941 for (int i=0; i<N; i++) {
6942 try {
6943 PendingThumbnailsRecord pr =
6944 (PendingThumbnailsRecord)receivers.get(i);
6945 pr.receiver.newThumbnail(
6946 task != null ? task.taskId : -1, thumbnail, description);
6947 if (pr.finished) {
6948 pr.receiver.finished();
6949 }
6950 } catch (Exception e) {
6951 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6952 }
6953 }
6954 }
6955 }
6956
6957 // =========================================================
6958 // CONTENT PROVIDERS
6959 // =========================================================
6960
6961 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6962 List providers = null;
6963 try {
6964 providers = ActivityThread.getPackageManager().
6965 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006966 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006967 } catch (RemoteException ex) {
6968 }
6969 if (providers != null) {
6970 final int N = providers.size();
6971 for (int i=0; i<N; i++) {
6972 ProviderInfo cpi =
6973 (ProviderInfo)providers.get(i);
6974 ContentProviderRecord cpr =
6975 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6976 if (cpr == null) {
6977 cpr = new ContentProviderRecord(cpi, app.info);
6978 mProvidersByClass.put(cpi.name, cpr);
6979 }
6980 app.pubProviders.put(cpi.name, cpr);
6981 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07006982 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006983 }
6984 }
6985 return providers;
6986 }
6987
6988 private final String checkContentProviderPermissionLocked(
6989 ProviderInfo cpi, ProcessRecord r, int mode) {
6990 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6991 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6992 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6993 cpi.exported ? -1 : cpi.applicationInfo.uid)
6994 == PackageManager.PERMISSION_GRANTED
6995 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6996 return null;
6997 }
6998 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6999 cpi.exported ? -1 : cpi.applicationInfo.uid)
7000 == PackageManager.PERMISSION_GRANTED) {
7001 return null;
7002 }
7003 String msg = "Permission Denial: opening provider " + cpi.name
7004 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7005 + ", uid=" + callingUid + ") requires "
7006 + cpi.readPermission + " or " + cpi.writePermission;
7007 Log.w(TAG, msg);
7008 return msg;
7009 }
7010
7011 private final ContentProviderHolder getContentProviderImpl(
7012 IApplicationThread caller, String name) {
7013 ContentProviderRecord cpr;
7014 ProviderInfo cpi = null;
7015
7016 synchronized(this) {
7017 ProcessRecord r = null;
7018 if (caller != null) {
7019 r = getRecordForAppLocked(caller);
7020 if (r == null) {
7021 throw new SecurityException(
7022 "Unable to find app for caller " + caller
7023 + " (pid=" + Binder.getCallingPid()
7024 + ") when getting content provider " + name);
7025 }
7026 }
7027
7028 // First check if this content provider has been published...
7029 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7030 if (cpr != null) {
7031 cpi = cpr.info;
7032 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7033 return new ContentProviderHolder(cpi,
7034 cpi.readPermission != null
7035 ? cpi.readPermission : cpi.writePermission);
7036 }
7037
7038 if (r != null && cpr.canRunHere(r)) {
7039 // This provider has been published or is in the process
7040 // of being published... but it is also allowed to run
7041 // in the caller's process, so don't make a connection
7042 // and just let the caller instantiate its own instance.
7043 if (cpr.provider != null) {
7044 // don't give caller the provider object, it needs
7045 // to make its own.
7046 cpr = new ContentProviderRecord(cpr);
7047 }
7048 return cpr;
7049 }
7050
7051 final long origId = Binder.clearCallingIdentity();
7052
7053 // In this case the provider is a single instance, so we can
7054 // return it right away.
7055 if (r != null) {
7056 r.conProviders.add(cpr);
7057 cpr.clients.add(r);
7058 } else {
7059 cpr.externals++;
7060 }
7061
7062 if (cpr.app != null) {
7063 updateOomAdjLocked(cpr.app);
7064 }
7065
7066 Binder.restoreCallingIdentity(origId);
7067
7068 } else {
7069 try {
7070 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007071 resolveContentProvider(name,
7072 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007073 } catch (RemoteException ex) {
7074 }
7075 if (cpi == null) {
7076 return null;
7077 }
7078
7079 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7080 return new ContentProviderHolder(cpi,
7081 cpi.readPermission != null
7082 ? cpi.readPermission : cpi.writePermission);
7083 }
7084
7085 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7086 final boolean firstClass = cpr == null;
7087 if (firstClass) {
7088 try {
7089 ApplicationInfo ai =
7090 ActivityThread.getPackageManager().
7091 getApplicationInfo(
7092 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007093 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007094 if (ai == null) {
7095 Log.w(TAG, "No package info for content provider "
7096 + cpi.name);
7097 return null;
7098 }
7099 cpr = new ContentProviderRecord(cpi, ai);
7100 } catch (RemoteException ex) {
7101 // pm is in same process, this will never happen.
7102 }
7103 }
7104
7105 if (r != null && cpr.canRunHere(r)) {
7106 // If this is a multiprocess provider, then just return its
7107 // info and allow the caller to instantiate it. Only do
7108 // this if the provider is the same user as the caller's
7109 // process, or can run as root (so can be in any process).
7110 return cpr;
7111 }
7112
7113 if (false) {
7114 RuntimeException e = new RuntimeException("foo");
7115 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7116 // + " pruid " + ai.uid + "): " + cpi.className, e);
7117 }
7118
7119 // This is single process, and our app is now connecting to it.
7120 // See if we are already in the process of launching this
7121 // provider.
7122 final int N = mLaunchingProviders.size();
7123 int i;
7124 for (i=0; i<N; i++) {
7125 if (mLaunchingProviders.get(i) == cpr) {
7126 break;
7127 }
7128 if (false) {
7129 final ContentProviderRecord rec =
7130 (ContentProviderRecord)mLaunchingProviders.get(i);
7131 if (rec.info.name.equals(cpr.info.name)) {
7132 cpr = rec;
7133 break;
7134 }
7135 }
7136 }
7137
7138 // If the provider is not already being launched, then get it
7139 // started.
7140 if (i >= N) {
7141 final long origId = Binder.clearCallingIdentity();
7142 ProcessRecord proc = startProcessLocked(cpi.processName,
7143 cpr.appInfo, false, 0, "content provider",
7144 new ComponentName(cpi.applicationInfo.packageName,
7145 cpi.name));
7146 if (proc == null) {
7147 Log.w(TAG, "Unable to launch app "
7148 + cpi.applicationInfo.packageName + "/"
7149 + cpi.applicationInfo.uid + " for provider "
7150 + name + ": process is bad");
7151 return null;
7152 }
7153 cpr.launchingApp = proc;
7154 mLaunchingProviders.add(cpr);
7155 Binder.restoreCallingIdentity(origId);
7156 }
7157
7158 // Make sure the provider is published (the same provider class
7159 // may be published under multiple names).
7160 if (firstClass) {
7161 mProvidersByClass.put(cpi.name, cpr);
7162 }
7163 mProvidersByName.put(name, cpr);
7164
7165 if (r != null) {
7166 r.conProviders.add(cpr);
7167 cpr.clients.add(r);
7168 } else {
7169 cpr.externals++;
7170 }
7171 }
7172 }
7173
7174 // Wait for the provider to be published...
7175 synchronized (cpr) {
7176 while (cpr.provider == null) {
7177 if (cpr.launchingApp == null) {
7178 Log.w(TAG, "Unable to launch app "
7179 + cpi.applicationInfo.packageName + "/"
7180 + cpi.applicationInfo.uid + " for provider "
7181 + name + ": launching app became null");
7182 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7183 cpi.applicationInfo.packageName,
7184 cpi.applicationInfo.uid, name);
7185 return null;
7186 }
7187 try {
7188 cpr.wait();
7189 } catch (InterruptedException ex) {
7190 }
7191 }
7192 }
7193 return cpr;
7194 }
7195
7196 public final ContentProviderHolder getContentProvider(
7197 IApplicationThread caller, String name) {
7198 if (caller == null) {
7199 String msg = "null IApplicationThread when getting content provider "
7200 + name;
7201 Log.w(TAG, msg);
7202 throw new SecurityException(msg);
7203 }
7204
7205 return getContentProviderImpl(caller, name);
7206 }
7207
7208 private ContentProviderHolder getContentProviderExternal(String name) {
7209 return getContentProviderImpl(null, name);
7210 }
7211
7212 /**
7213 * Drop a content provider from a ProcessRecord's bookkeeping
7214 * @param cpr
7215 */
7216 public void removeContentProvider(IApplicationThread caller, String name) {
7217 synchronized (this) {
7218 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7219 if(cpr == null) {
7220 //remove from mProvidersByClass
7221 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7222 return;
7223 }
7224 final ProcessRecord r = getRecordForAppLocked(caller);
7225 if (r == null) {
7226 throw new SecurityException(
7227 "Unable to find app for caller " + caller +
7228 " when removing content provider " + name);
7229 }
7230 //update content provider record entry info
7231 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7232 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7233 r.info.processName+" from process "+localCpr.appInfo.processName);
7234 if(localCpr.appInfo.processName == r.info.processName) {
7235 //should not happen. taken care of as a local provider
7236 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7237 return;
7238 } else {
7239 localCpr.clients.remove(r);
7240 r.conProviders.remove(localCpr);
7241 }
7242 updateOomAdjLocked();
7243 }
7244 }
7245
7246 private void removeContentProviderExternal(String name) {
7247 synchronized (this) {
7248 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7249 if(cpr == null) {
7250 //remove from mProvidersByClass
7251 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7252 return;
7253 }
7254
7255 //update content provider record entry info
7256 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7257 localCpr.externals--;
7258 if (localCpr.externals < 0) {
7259 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7260 }
7261 updateOomAdjLocked();
7262 }
7263 }
7264
7265 public final void publishContentProviders(IApplicationThread caller,
7266 List<ContentProviderHolder> providers) {
7267 if (providers == null) {
7268 return;
7269 }
7270
7271 synchronized(this) {
7272 final ProcessRecord r = getRecordForAppLocked(caller);
7273 if (r == null) {
7274 throw new SecurityException(
7275 "Unable to find app for caller " + caller
7276 + " (pid=" + Binder.getCallingPid()
7277 + ") when publishing content providers");
7278 }
7279
7280 final long origId = Binder.clearCallingIdentity();
7281
7282 final int N = providers.size();
7283 for (int i=0; i<N; i++) {
7284 ContentProviderHolder src = providers.get(i);
7285 if (src == null || src.info == null || src.provider == null) {
7286 continue;
7287 }
7288 ContentProviderRecord dst =
7289 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7290 if (dst != null) {
7291 mProvidersByClass.put(dst.info.name, dst);
7292 String names[] = dst.info.authority.split(";");
7293 for (int j = 0; j < names.length; j++) {
7294 mProvidersByName.put(names[j], dst);
7295 }
7296
7297 int NL = mLaunchingProviders.size();
7298 int j;
7299 for (j=0; j<NL; j++) {
7300 if (mLaunchingProviders.get(j) == dst) {
7301 mLaunchingProviders.remove(j);
7302 j--;
7303 NL--;
7304 }
7305 }
7306 synchronized (dst) {
7307 dst.provider = src.provider;
7308 dst.app = r;
7309 dst.notifyAll();
7310 }
7311 updateOomAdjLocked(r);
7312 }
7313 }
7314
7315 Binder.restoreCallingIdentity(origId);
7316 }
7317 }
7318
7319 public static final void installSystemProviders() {
7320 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7321 List providers = mSelf.generateApplicationProvidersLocked(app);
7322 mSystemThread.installSystemProviders(providers);
7323 }
7324
7325 // =========================================================
7326 // GLOBAL MANAGEMENT
7327 // =========================================================
7328
7329 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7330 ApplicationInfo info, String customProcess) {
7331 String proc = customProcess != null ? customProcess : info.processName;
7332 BatteryStatsImpl.Uid.Proc ps = null;
7333 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7334 synchronized (stats) {
7335 ps = stats.getProcessStatsLocked(info.uid, proc);
7336 }
7337 return new ProcessRecord(ps, thread, info, proc);
7338 }
7339
7340 final ProcessRecord addAppLocked(ApplicationInfo info) {
7341 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7342
7343 if (app == null) {
7344 app = newProcessRecordLocked(null, info, null);
7345 mProcessNames.put(info.processName, info.uid, app);
7346 updateLRUListLocked(app, true);
7347 }
7348
7349 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7350 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7351 app.persistent = true;
7352 app.maxAdj = CORE_SERVER_ADJ;
7353 }
7354 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7355 mPersistentStartingProcesses.add(app);
7356 startProcessLocked(app, "added application", app.processName);
7357 }
7358
7359 return app;
7360 }
7361
7362 public void unhandledBack() {
7363 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7364 "unhandledBack()");
7365
7366 synchronized(this) {
7367 int count = mHistory.size();
7368 if (Config.LOGD) Log.d(
7369 TAG, "Performing unhandledBack(): stack size = " + count);
7370 if (count > 1) {
7371 final long origId = Binder.clearCallingIdentity();
7372 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7373 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7374 Binder.restoreCallingIdentity(origId);
7375 }
7376 }
7377 }
7378
7379 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7380 String name = uri.getAuthority();
7381 ContentProviderHolder cph = getContentProviderExternal(name);
7382 ParcelFileDescriptor pfd = null;
7383 if (cph != null) {
7384 // We record the binder invoker's uid in thread-local storage before
7385 // going to the content provider to open the file. Later, in the code
7386 // that handles all permissions checks, we look for this uid and use
7387 // that rather than the Activity Manager's own uid. The effect is that
7388 // we do the check against the caller's permissions even though it looks
7389 // to the content provider like the Activity Manager itself is making
7390 // the request.
7391 sCallerIdentity.set(new Identity(
7392 Binder.getCallingPid(), Binder.getCallingUid()));
7393 try {
7394 pfd = cph.provider.openFile(uri, "r");
7395 } catch (FileNotFoundException e) {
7396 // do nothing; pfd will be returned null
7397 } finally {
7398 // Ensure that whatever happens, we clean up the identity state
7399 sCallerIdentity.remove();
7400 }
7401
7402 // We've got the fd now, so we're done with the provider.
7403 removeContentProviderExternal(name);
7404 } else {
7405 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7406 }
7407 return pfd;
7408 }
7409
7410 public void goingToSleep() {
7411 synchronized(this) {
7412 mSleeping = true;
7413 mWindowManager.setEventDispatching(false);
7414
7415 if (mResumedActivity != null) {
7416 pauseIfSleepingLocked();
7417 } else {
7418 Log.w(TAG, "goingToSleep with no resumed activity!");
7419 }
7420 }
7421 }
7422
Dianne Hackborn55280a92009-05-07 15:53:46 -07007423 public boolean shutdown(int timeout) {
7424 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7425 != PackageManager.PERMISSION_GRANTED) {
7426 throw new SecurityException("Requires permission "
7427 + android.Manifest.permission.SHUTDOWN);
7428 }
7429
7430 boolean timedout = false;
7431
7432 synchronized(this) {
7433 mShuttingDown = true;
7434 mWindowManager.setEventDispatching(false);
7435
7436 if (mResumedActivity != null) {
7437 pauseIfSleepingLocked();
7438 final long endTime = System.currentTimeMillis() + timeout;
7439 while (mResumedActivity != null || mPausingActivity != null) {
7440 long delay = endTime - System.currentTimeMillis();
7441 if (delay <= 0) {
7442 Log.w(TAG, "Activity manager shutdown timed out");
7443 timedout = true;
7444 break;
7445 }
7446 try {
7447 this.wait();
7448 } catch (InterruptedException e) {
7449 }
7450 }
7451 }
7452 }
7453
7454 mUsageStatsService.shutdown();
7455 mBatteryStatsService.shutdown();
7456
7457 return timedout;
7458 }
7459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007460 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007461 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007462 if (!mGoingToSleep.isHeld()) {
7463 mGoingToSleep.acquire();
7464 if (mLaunchingActivity.isHeld()) {
7465 mLaunchingActivity.release();
7466 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7467 }
7468 }
7469
7470 // If we are not currently pausing an activity, get the current
7471 // one to pause. If we are pausing one, we will just let that stuff
7472 // run and release the wake lock when all done.
7473 if (mPausingActivity == null) {
7474 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7475 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7476 startPausingLocked(false, true);
7477 }
7478 }
7479 }
7480
7481 public void wakingUp() {
7482 synchronized(this) {
7483 if (mGoingToSleep.isHeld()) {
7484 mGoingToSleep.release();
7485 }
7486 mWindowManager.setEventDispatching(true);
7487 mSleeping = false;
7488 resumeTopActivityLocked(null);
7489 }
7490 }
7491
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007492 public void stopAppSwitches() {
7493 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7494 != PackageManager.PERMISSION_GRANTED) {
7495 throw new SecurityException("Requires permission "
7496 + android.Manifest.permission.STOP_APP_SWITCHES);
7497 }
7498
7499 synchronized(this) {
7500 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7501 + APP_SWITCH_DELAY_TIME;
7502 mDidAppSwitch = false;
7503 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7504 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7505 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7506 }
7507 }
7508
7509 public void resumeAppSwitches() {
7510 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7511 != PackageManager.PERMISSION_GRANTED) {
7512 throw new SecurityException("Requires permission "
7513 + android.Manifest.permission.STOP_APP_SWITCHES);
7514 }
7515
7516 synchronized(this) {
7517 // Note that we don't execute any pending app switches... we will
7518 // let those wait until either the timeout, or the next start
7519 // activity request.
7520 mAppSwitchesAllowedTime = 0;
7521 }
7522 }
7523
7524 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7525 String name) {
7526 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7527 return true;
7528 }
7529
7530 final int perm = checkComponentPermission(
7531 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7532 callingUid, -1);
7533 if (perm == PackageManager.PERMISSION_GRANTED) {
7534 return true;
7535 }
7536
7537 Log.w(TAG, name + " request from " + callingUid + " stopped");
7538 return false;
7539 }
7540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007541 public void setDebugApp(String packageName, boolean waitForDebugger,
7542 boolean persistent) {
7543 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7544 "setDebugApp()");
7545
7546 // Note that this is not really thread safe if there are multiple
7547 // callers into it at the same time, but that's not a situation we
7548 // care about.
7549 if (persistent) {
7550 final ContentResolver resolver = mContext.getContentResolver();
7551 Settings.System.putString(
7552 resolver, Settings.System.DEBUG_APP,
7553 packageName);
7554 Settings.System.putInt(
7555 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7556 waitForDebugger ? 1 : 0);
7557 }
7558
7559 synchronized (this) {
7560 if (!persistent) {
7561 mOrigDebugApp = mDebugApp;
7562 mOrigWaitForDebugger = mWaitForDebugger;
7563 }
7564 mDebugApp = packageName;
7565 mWaitForDebugger = waitForDebugger;
7566 mDebugTransient = !persistent;
7567 if (packageName != null) {
7568 final long origId = Binder.clearCallingIdentity();
7569 uninstallPackageLocked(packageName, -1, false);
7570 Binder.restoreCallingIdentity(origId);
7571 }
7572 }
7573 }
7574
7575 public void setAlwaysFinish(boolean enabled) {
7576 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7577 "setAlwaysFinish()");
7578
7579 Settings.System.putInt(
7580 mContext.getContentResolver(),
7581 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7582
7583 synchronized (this) {
7584 mAlwaysFinishActivities = enabled;
7585 }
7586 }
7587
7588 public void setActivityWatcher(IActivityWatcher watcher) {
7589 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7590 "setActivityWatcher()");
7591 synchronized (this) {
7592 mWatcher = watcher;
7593 }
7594 }
7595
7596 public final void enterSafeMode() {
7597 synchronized(this) {
7598 // It only makes sense to do this before the system is ready
7599 // and started launching other packages.
7600 if (!mSystemReady) {
7601 try {
7602 ActivityThread.getPackageManager().enterSafeMode();
7603 } catch (RemoteException e) {
7604 }
7605
7606 View v = LayoutInflater.from(mContext).inflate(
7607 com.android.internal.R.layout.safe_mode, null);
7608 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7609 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7610 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7611 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7612 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7613 lp.format = v.getBackground().getOpacity();
7614 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7615 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7616 ((WindowManager)mContext.getSystemService(
7617 Context.WINDOW_SERVICE)).addView(v, lp);
7618 }
7619 }
7620 }
7621
7622 public void noteWakeupAlarm(IIntentSender sender) {
7623 if (!(sender instanceof PendingIntentRecord)) {
7624 return;
7625 }
7626 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7627 synchronized (stats) {
7628 if (mBatteryStatsService.isOnBattery()) {
7629 mBatteryStatsService.enforceCallingPermission();
7630 PendingIntentRecord rec = (PendingIntentRecord)sender;
7631 int MY_UID = Binder.getCallingUid();
7632 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7633 BatteryStatsImpl.Uid.Pkg pkg =
7634 stats.getPackageStatsLocked(uid, rec.key.packageName);
7635 pkg.incWakeupsLocked();
7636 }
7637 }
7638 }
7639
7640 public boolean killPidsForMemory(int[] pids) {
7641 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7642 throw new SecurityException("killPidsForMemory only available to the system");
7643 }
7644
7645 // XXX Note: don't acquire main activity lock here, because the window
7646 // manager calls in with its locks held.
7647
7648 boolean killed = false;
7649 synchronized (mPidsSelfLocked) {
7650 int[] types = new int[pids.length];
7651 int worstType = 0;
7652 for (int i=0; i<pids.length; i++) {
7653 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7654 if (proc != null) {
7655 int type = proc.setAdj;
7656 types[i] = type;
7657 if (type > worstType) {
7658 worstType = type;
7659 }
7660 }
7661 }
7662
7663 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7664 // then constrain it so we will kill all hidden procs.
7665 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7666 worstType = HIDDEN_APP_MIN_ADJ;
7667 }
7668 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7669 for (int i=0; i<pids.length; i++) {
7670 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7671 if (proc == null) {
7672 continue;
7673 }
7674 int adj = proc.setAdj;
7675 if (adj >= worstType) {
7676 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7677 + adj + ")");
7678 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7679 proc.processName, adj);
7680 killed = true;
7681 Process.killProcess(pids[i]);
7682 }
7683 }
7684 }
7685 return killed;
7686 }
7687
7688 public void reportPss(IApplicationThread caller, int pss) {
7689 Watchdog.PssRequestor req;
7690 String name;
7691 ProcessRecord callerApp;
7692 synchronized (this) {
7693 if (caller == null) {
7694 return;
7695 }
7696 callerApp = getRecordForAppLocked(caller);
7697 if (callerApp == null) {
7698 return;
7699 }
7700 callerApp.lastPss = pss;
7701 req = callerApp;
7702 name = callerApp.processName;
7703 }
7704 Watchdog.getInstance().reportPss(req, name, pss);
7705 if (!callerApp.persistent) {
7706 removeRequestedPss(callerApp);
7707 }
7708 }
7709
7710 public void requestPss(Runnable completeCallback) {
7711 ArrayList<ProcessRecord> procs;
7712 synchronized (this) {
7713 mRequestPssCallback = completeCallback;
7714 mRequestPssList.clear();
7715 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7716 ProcessRecord proc = mLRUProcesses.get(i);
7717 if (!proc.persistent) {
7718 mRequestPssList.add(proc);
7719 }
7720 }
7721 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7722 }
7723
7724 int oldPri = Process.getThreadPriority(Process.myTid());
7725 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7726 for (int i=procs.size()-1; i>=0; i--) {
7727 ProcessRecord proc = procs.get(i);
7728 proc.lastPss = 0;
7729 proc.requestPss();
7730 }
7731 Process.setThreadPriority(oldPri);
7732 }
7733
7734 void removeRequestedPss(ProcessRecord proc) {
7735 Runnable callback = null;
7736 synchronized (this) {
7737 if (mRequestPssList.remove(proc)) {
7738 if (mRequestPssList.size() == 0) {
7739 callback = mRequestPssCallback;
7740 mRequestPssCallback = null;
7741 }
7742 }
7743 }
7744
7745 if (callback != null) {
7746 callback.run();
7747 }
7748 }
7749
7750 public void collectPss(Watchdog.PssStats stats) {
7751 stats.mEmptyPss = 0;
7752 stats.mEmptyCount = 0;
7753 stats.mBackgroundPss = 0;
7754 stats.mBackgroundCount = 0;
7755 stats.mServicePss = 0;
7756 stats.mServiceCount = 0;
7757 stats.mVisiblePss = 0;
7758 stats.mVisibleCount = 0;
7759 stats.mForegroundPss = 0;
7760 stats.mForegroundCount = 0;
7761 stats.mNoPssCount = 0;
7762 synchronized (this) {
7763 int i;
7764 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7765 ? mProcDeaths.length : stats.mProcDeaths.length;
7766 int aggr = 0;
7767 for (i=0; i<NPD; i++) {
7768 aggr += mProcDeaths[i];
7769 stats.mProcDeaths[i] = aggr;
7770 }
7771 while (i<stats.mProcDeaths.length) {
7772 stats.mProcDeaths[i] = 0;
7773 i++;
7774 }
7775
7776 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7777 ProcessRecord proc = mLRUProcesses.get(i);
7778 if (proc.persistent) {
7779 continue;
7780 }
7781 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7782 if (proc.lastPss == 0) {
7783 stats.mNoPssCount++;
7784 continue;
7785 }
7786 if (proc.setAdj == EMPTY_APP_ADJ) {
7787 stats.mEmptyPss += proc.lastPss;
7788 stats.mEmptyCount++;
7789 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7790 stats.mEmptyPss += proc.lastPss;
7791 stats.mEmptyCount++;
7792 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7793 stats.mBackgroundPss += proc.lastPss;
7794 stats.mBackgroundCount++;
7795 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7796 stats.mVisiblePss += proc.lastPss;
7797 stats.mVisibleCount++;
7798 } else {
7799 stats.mForegroundPss += proc.lastPss;
7800 stats.mForegroundCount++;
7801 }
7802 }
7803 }
7804 }
7805
7806 public final void startRunning(String pkg, String cls, String action,
7807 String data) {
7808 synchronized(this) {
7809 if (mStartRunning) {
7810 return;
7811 }
7812 mStartRunning = true;
7813 mTopComponent = pkg != null && cls != null
7814 ? new ComponentName(pkg, cls) : null;
7815 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7816 mTopData = data;
7817 if (!mSystemReady) {
7818 return;
7819 }
7820 }
7821
7822 systemReady();
7823 }
7824
7825 private void retrieveSettings() {
7826 final ContentResolver resolver = mContext.getContentResolver();
7827 String debugApp = Settings.System.getString(
7828 resolver, Settings.System.DEBUG_APP);
7829 boolean waitForDebugger = Settings.System.getInt(
7830 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7831 boolean alwaysFinishActivities = Settings.System.getInt(
7832 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7833
7834 Configuration configuration = new Configuration();
7835 Settings.System.getConfiguration(resolver, configuration);
7836
7837 synchronized (this) {
7838 mDebugApp = mOrigDebugApp = debugApp;
7839 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7840 mAlwaysFinishActivities = alwaysFinishActivities;
7841 // This happens before any activities are started, so we can
7842 // change mConfiguration in-place.
7843 mConfiguration.updateFrom(configuration);
7844 }
7845 }
7846
7847 public boolean testIsSystemReady() {
7848 // no need to synchronize(this) just to read & return the value
7849 return mSystemReady;
7850 }
7851
7852 public void systemReady() {
7853 // In the simulator, startRunning will never have been called, which
7854 // normally sets a few crucial variables. Do it here instead.
7855 if (!Process.supportsProcesses()) {
7856 mStartRunning = true;
7857 mTopAction = Intent.ACTION_MAIN;
7858 }
7859
7860 synchronized(this) {
7861 if (mSystemReady) {
7862 return;
7863 }
7864 mSystemReady = true;
7865 if (!mStartRunning) {
7866 return;
7867 }
7868 }
7869
7870 if (Config.LOGD) Log.d(TAG, "Start running!");
7871 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7872 SystemClock.uptimeMillis());
7873
7874 synchronized(this) {
7875 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7876 ResolveInfo ri = mContext.getPackageManager()
7877 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007878 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007879 CharSequence errorMsg = null;
7880 if (ri != null) {
7881 ActivityInfo ai = ri.activityInfo;
7882 ApplicationInfo app = ai.applicationInfo;
7883 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7884 mTopAction = Intent.ACTION_FACTORY_TEST;
7885 mTopData = null;
7886 mTopComponent = new ComponentName(app.packageName,
7887 ai.name);
7888 } else {
7889 errorMsg = mContext.getResources().getText(
7890 com.android.internal.R.string.factorytest_not_system);
7891 }
7892 } else {
7893 errorMsg = mContext.getResources().getText(
7894 com.android.internal.R.string.factorytest_no_action);
7895 }
7896 if (errorMsg != null) {
7897 mTopAction = null;
7898 mTopData = null;
7899 mTopComponent = null;
7900 Message msg = Message.obtain();
7901 msg.what = SHOW_FACTORY_ERROR_MSG;
7902 msg.getData().putCharSequence("msg", errorMsg);
7903 mHandler.sendMessage(msg);
7904 }
7905 }
7906 }
7907
7908 retrieveSettings();
7909
7910 synchronized (this) {
7911 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7912 try {
7913 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007914 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007915 if (apps != null) {
7916 int N = apps.size();
7917 int i;
7918 for (i=0; i<N; i++) {
7919 ApplicationInfo info
7920 = (ApplicationInfo)apps.get(i);
7921 if (info != null &&
7922 !info.packageName.equals("android")) {
7923 addAppLocked(info);
7924 }
7925 }
7926 }
7927 } catch (RemoteException ex) {
7928 // pm is in same process, this will never happen.
7929 }
7930 }
7931
7932 try {
7933 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7934 Message msg = Message.obtain();
7935 msg.what = SHOW_UID_ERROR_MSG;
7936 mHandler.sendMessage(msg);
7937 }
7938 } catch (RemoteException e) {
7939 }
7940
7941 // Start up initial activity.
7942 mBooting = true;
7943 resumeTopActivityLocked(null);
7944 }
7945 }
7946
7947 boolean makeAppCrashingLocked(ProcessRecord app,
7948 String tag, String shortMsg, String longMsg, byte[] crashData) {
7949 app.crashing = true;
7950 app.crashingReport = generateProcessError(app,
7951 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7952 startAppProblemLocked(app);
7953 app.stopFreezingAllLocked();
7954 return handleAppCrashLocked(app);
7955 }
7956
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007957 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7958 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02007959
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007960 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02007961 // look for receiver in the installer package
7962 String candidate = pm.getInstallerPackageName(app.info.packageName);
7963 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
7964 if (result != null) {
7965 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007966 }
7967
Jacek Surazski82a73df2009-06-17 14:33:18 +02007968 // if the error app is on the system image, look for system apps
7969 // error receiver
7970 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7971 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
7972 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
7973 if (result != null) {
7974 return result;
7975 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007976 }
7977
Jacek Surazski82a73df2009-06-17 14:33:18 +02007978 // if there is a default receiver, try that
7979 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
7980 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007981 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02007982 // should not happen
7983 Log.e(TAG, "error talking to PackageManager", e);
7984 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007985 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02007986 }
7987
7988 /**
7989 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
7990 *
7991 * @param pm PackageManager isntance
7992 * @param errorPackage package which caused the error
7993 * @param receiverPackage candidate package to receive the error
7994 * @return activity component within receiverPackage which handles
7995 * ACTION_APP_ERROR, or null if not found
7996 */
7997 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
7998 String receiverPackage) throws RemoteException {
7999 if (receiverPackage == null || receiverPackage.length() == 0) {
8000 return null;
8001 }
8002
8003 // break the loop if it's the error report receiver package that crashed
8004 if (receiverPackage.equals(errorPackage)) {
8005 return null;
8006 }
8007
8008 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8009 intent.setPackage(receiverPackage);
8010 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8011 if (info == null || info.activityInfo == null) {
8012 return null;
8013 }
8014 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008015 }
8016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008017 void makeAppNotRespondingLocked(ProcessRecord app,
8018 String tag, String shortMsg, String longMsg, byte[] crashData) {
8019 app.notResponding = true;
8020 app.notRespondingReport = generateProcessError(app,
8021 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8022 crashData);
8023 startAppProblemLocked(app);
8024 app.stopFreezingAllLocked();
8025 }
8026
8027 /**
8028 * Generate a process error record, suitable for attachment to a ProcessRecord.
8029 *
8030 * @param app The ProcessRecord in which the error occurred.
8031 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8032 * ActivityManager.AppErrorStateInfo
8033 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8034 * @param shortMsg Short message describing the crash.
8035 * @param longMsg Long message describing the crash.
8036 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8037 *
8038 * @return Returns a fully-formed AppErrorStateInfo record.
8039 */
8040 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8041 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8042 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8043
8044 report.condition = condition;
8045 report.processName = app.processName;
8046 report.pid = app.pid;
8047 report.uid = app.info.uid;
8048 report.tag = tag;
8049 report.shortMsg = shortMsg;
8050 report.longMsg = longMsg;
8051 report.crashData = crashData;
8052
8053 return report;
8054 }
8055
8056 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8057 boolean crashed) {
8058 synchronized (this) {
8059 app.crashing = false;
8060 app.crashingReport = null;
8061 app.notResponding = false;
8062 app.notRespondingReport = null;
8063 if (app.anrDialog == fromDialog) {
8064 app.anrDialog = null;
8065 }
8066 if (app.waitDialog == fromDialog) {
8067 app.waitDialog = null;
8068 }
8069 if (app.pid > 0 && app.pid != MY_PID) {
8070 if (crashed) {
8071 handleAppCrashLocked(app);
8072 }
8073 Log.i(ActivityManagerService.TAG, "Killing process "
8074 + app.processName
8075 + " (pid=" + app.pid + ") at user's request");
8076 Process.killProcess(app.pid);
8077 }
8078
8079 }
8080 }
8081
8082 boolean handleAppCrashLocked(ProcessRecord app) {
8083 long now = SystemClock.uptimeMillis();
8084
8085 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8086 app.info.uid);
8087 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8088 // This process loses!
8089 Log.w(TAG, "Process " + app.info.processName
8090 + " has crashed too many times: killing!");
8091 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8092 app.info.processName, app.info.uid);
8093 killServicesLocked(app, false);
8094 for (int i=mHistory.size()-1; i>=0; i--) {
8095 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8096 if (r.app == app) {
8097 if (Config.LOGD) Log.d(
8098 TAG, " Force finishing activity "
8099 + r.intent.getComponent().flattenToShortString());
8100 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8101 }
8102 }
8103 if (!app.persistent) {
8104 // We don't want to start this process again until the user
8105 // explicitly does so... but for persistent process, we really
8106 // need to keep it running. If a persistent process is actually
8107 // repeatedly crashing, then badness for everyone.
8108 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8109 app.info.processName);
8110 mBadProcesses.put(app.info.processName, app.info.uid, now);
8111 app.bad = true;
8112 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8113 app.removed = true;
8114 removeProcessLocked(app, false);
8115 return false;
8116 }
8117 }
8118
8119 // Bump up the crash count of any services currently running in the proc.
8120 if (app.services.size() != 0) {
8121 // Any services running in the application need to be placed
8122 // back in the pending list.
8123 Iterator it = app.services.iterator();
8124 while (it.hasNext()) {
8125 ServiceRecord sr = (ServiceRecord)it.next();
8126 sr.crashCount++;
8127 }
8128 }
8129
8130 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8131 return true;
8132 }
8133
8134 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008135 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008136 skipCurrentReceiverLocked(app);
8137 }
8138
8139 void skipCurrentReceiverLocked(ProcessRecord app) {
8140 boolean reschedule = false;
8141 BroadcastRecord r = app.curReceiver;
8142 if (r != null) {
8143 // The current broadcast is waiting for this app's receiver
8144 // to be finished. Looks like that's not going to happen, so
8145 // let the broadcast continue.
8146 logBroadcastReceiverDiscard(r);
8147 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8148 r.resultExtras, r.resultAbort, true);
8149 reschedule = true;
8150 }
8151 r = mPendingBroadcast;
8152 if (r != null && r.curApp == app) {
8153 if (DEBUG_BROADCAST) Log.v(TAG,
8154 "skip & discard pending app " + r);
8155 logBroadcastReceiverDiscard(r);
8156 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8157 r.resultExtras, r.resultAbort, true);
8158 reschedule = true;
8159 }
8160 if (reschedule) {
8161 scheduleBroadcastsLocked();
8162 }
8163 }
8164
8165 public int handleApplicationError(IBinder app, int flags,
8166 String tag, String shortMsg, String longMsg, byte[] crashData) {
8167 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008168 ProcessRecord r = null;
8169 synchronized (this) {
8170 if (app != null) {
8171 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8172 final int NA = apps.size();
8173 for (int ia=0; ia<NA; ia++) {
8174 ProcessRecord p = apps.valueAt(ia);
8175 if (p.thread != null && p.thread.asBinder() == app) {
8176 r = p;
8177 break;
8178 }
8179 }
8180 }
8181 }
8182
8183 if (r != null) {
8184 // The application has crashed. Send the SIGQUIT to the process so
8185 // that it can dump its state.
8186 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8187 //Log.i(TAG, "Current system threads:");
8188 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8189 }
8190
8191 if (mWatcher != null) {
8192 try {
8193 String name = r != null ? r.processName : null;
8194 int pid = r != null ? r.pid : Binder.getCallingPid();
8195 if (!mWatcher.appCrashed(name, pid,
8196 shortMsg, longMsg, crashData)) {
8197 Log.w(TAG, "Force-killing crashed app " + name
8198 + " at watcher's request");
8199 Process.killProcess(pid);
8200 return 0;
8201 }
8202 } catch (RemoteException e) {
8203 mWatcher = null;
8204 }
8205 }
8206
8207 final long origId = Binder.clearCallingIdentity();
8208
8209 // If this process is running instrumentation, finish it.
8210 if (r != null && r.instrumentationClass != null) {
8211 Log.w(TAG, "Error in app " + r.processName
8212 + " running instrumentation " + r.instrumentationClass + ":");
8213 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8214 if (longMsg != null) Log.w(TAG, " " + longMsg);
8215 Bundle info = new Bundle();
8216 info.putString("shortMsg", shortMsg);
8217 info.putString("longMsg", longMsg);
8218 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8219 Binder.restoreCallingIdentity(origId);
8220 return 0;
8221 }
8222
8223 if (r != null) {
8224 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8225 return 0;
8226 }
8227 } else {
8228 Log.w(TAG, "Some application object " + app + " tag " + tag
8229 + " has crashed, but I don't know who it is.");
8230 Log.w(TAG, "ShortMsg:" + shortMsg);
8231 Log.w(TAG, "LongMsg:" + longMsg);
8232 Binder.restoreCallingIdentity(origId);
8233 return 0;
8234 }
8235
8236 Message msg = Message.obtain();
8237 msg.what = SHOW_ERROR_MSG;
8238 HashMap data = new HashMap();
8239 data.put("result", result);
8240 data.put("app", r);
8241 data.put("flags", flags);
8242 data.put("shortMsg", shortMsg);
8243 data.put("longMsg", longMsg);
8244 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8245 // For system processes, submit crash data to the server.
8246 data.put("crashData", crashData);
8247 }
8248 msg.obj = data;
8249 mHandler.sendMessage(msg);
8250
8251 Binder.restoreCallingIdentity(origId);
8252 }
8253
8254 int res = result.get();
8255
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008256 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008257 synchronized (this) {
8258 if (r != null) {
8259 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8260 SystemClock.uptimeMillis());
8261 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008262 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8263 appErrorIntent = createAppErrorIntentLocked(r);
8264 res = AppErrorDialog.FORCE_QUIT;
8265 }
8266 }
8267
8268 if (appErrorIntent != null) {
8269 try {
8270 mContext.startActivity(appErrorIntent);
8271 } catch (ActivityNotFoundException e) {
8272 Log.w(TAG, "bug report receiver dissappeared", e);
8273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008274 }
8275
8276 return res;
8277 }
8278
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008279 Intent createAppErrorIntentLocked(ProcessRecord r) {
8280 ApplicationErrorReport report = createAppErrorReportLocked(r);
8281 if (report == null) {
8282 return null;
8283 }
8284 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8285 result.setComponent(r.errorReportReceiver);
8286 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8287 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8288 return result;
8289 }
8290
8291 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8292 if (r.errorReportReceiver == null) {
8293 return null;
8294 }
8295
8296 if (!r.crashing && !r.notResponding) {
8297 return null;
8298 }
8299
8300 try {
8301 ApplicationErrorReport report = new ApplicationErrorReport();
8302 report.packageName = r.info.packageName;
8303 report.installerPackageName = r.errorReportReceiver.getPackageName();
8304 report.processName = r.processName;
8305
8306 if (r.crashing) {
8307 report.type = ApplicationErrorReport.TYPE_CRASH;
8308 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8309
8310 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8311 r.crashingReport.crashData);
8312 DataInputStream dataStream = new DataInputStream(byteStream);
8313 CrashData crashData = new CrashData(dataStream);
8314 ThrowableData throwData = crashData.getThrowableData();
8315
8316 report.time = crashData.getTime();
8317 report.crashInfo.stackTrace = throwData.toString();
8318
Jacek Surazskif829a782009-06-11 22:47:02 +02008319 // Extract the source of the exception, useful for report
8320 // clustering. Also extract the "deepest" non-null exception
8321 // message.
8322 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008323 while (throwData.getCause() != null) {
8324 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008325 String msg = throwData.getMessage();
8326 if (msg != null && msg.length() > 0) {
8327 exceptionMessage = msg;
8328 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008329 }
8330 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008331 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008332 report.crashInfo.exceptionClassName = throwData.getType();
8333 report.crashInfo.throwFileName = trace.getFileName();
8334 report.crashInfo.throwClassName = trace.getClassName();
8335 report.crashInfo.throwMethodName = trace.getMethodName();
8336 } else if (r.notResponding) {
8337 report.type = ApplicationErrorReport.TYPE_ANR;
8338 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8339
8340 report.anrInfo.activity = r.notRespondingReport.tag;
8341 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8342 report.anrInfo.info = r.notRespondingReport.longMsg;
8343 }
8344
8345 return report;
8346 } catch (IOException e) {
8347 // we don't send it
8348 }
8349
8350 return null;
8351 }
8352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008353 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8354 // assume our apps are happy - lazy create the list
8355 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8356
8357 synchronized (this) {
8358
8359 // iterate across all processes
8360 final int N = mLRUProcesses.size();
8361 for (int i = 0; i < N; i++) {
8362 ProcessRecord app = mLRUProcesses.get(i);
8363 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8364 // This one's in trouble, so we'll generate a report for it
8365 // crashes are higher priority (in case there's a crash *and* an anr)
8366 ActivityManager.ProcessErrorStateInfo report = null;
8367 if (app.crashing) {
8368 report = app.crashingReport;
8369 } else if (app.notResponding) {
8370 report = app.notRespondingReport;
8371 }
8372
8373 if (report != null) {
8374 if (errList == null) {
8375 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8376 }
8377 errList.add(report);
8378 } else {
8379 Log.w(TAG, "Missing app error report, app = " + app.processName +
8380 " crashing = " + app.crashing +
8381 " notResponding = " + app.notResponding);
8382 }
8383 }
8384 }
8385 }
8386
8387 return errList;
8388 }
8389
8390 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8391 // Lazy instantiation of list
8392 List<ActivityManager.RunningAppProcessInfo> runList = null;
8393 synchronized (this) {
8394 // Iterate across all processes
8395 final int N = mLRUProcesses.size();
8396 for (int i = 0; i < N; i++) {
8397 ProcessRecord app = mLRUProcesses.get(i);
8398 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8399 // Generate process state info for running application
8400 ActivityManager.RunningAppProcessInfo currApp =
8401 new ActivityManager.RunningAppProcessInfo(app.processName,
8402 app.pid, app.getPackageList());
8403 int adj = app.curAdj;
8404 if (adj >= CONTENT_PROVIDER_ADJ) {
8405 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8406 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8407 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008408 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8409 } else if (adj >= HOME_APP_ADJ) {
8410 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8411 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008412 } else if (adj >= SECONDARY_SERVER_ADJ) {
8413 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8414 } else if (adj >= VISIBLE_APP_ADJ) {
8415 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8416 } else {
8417 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8418 }
8419 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8420 // + " lru=" + currApp.lru);
8421 if (runList == null) {
8422 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8423 }
8424 runList.add(currApp);
8425 }
8426 }
8427 }
8428 return runList;
8429 }
8430
8431 @Override
8432 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8433 synchronized (this) {
8434 if (checkCallingPermission(android.Manifest.permission.DUMP)
8435 != PackageManager.PERMISSION_GRANTED) {
8436 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8437 + Binder.getCallingPid()
8438 + ", uid=" + Binder.getCallingUid()
8439 + " without permission "
8440 + android.Manifest.permission.DUMP);
8441 return;
8442 }
8443 if (args.length != 0 && "service".equals(args[0])) {
8444 dumpService(fd, pw, args);
8445 return;
8446 }
8447 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008448 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008449 pw.println(" ");
8450 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008451 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008452 if (mWaitingVisibleActivities.size() > 0) {
8453 pw.println(" ");
8454 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008455 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008456 }
8457 if (mStoppingActivities.size() > 0) {
8458 pw.println(" ");
8459 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008460 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008461 }
8462 if (mFinishingActivities.size() > 0) {
8463 pw.println(" ");
8464 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008465 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008466 }
8467
8468 pw.println(" ");
8469 pw.println(" mPausingActivity: " + mPausingActivity);
8470 pw.println(" mResumedActivity: " + mResumedActivity);
8471 pw.println(" mFocusedActivity: " + mFocusedActivity);
8472 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8473
8474 if (mRecentTasks.size() > 0) {
8475 pw.println(" ");
8476 pw.println("Recent tasks in Current Activity Manager State:");
8477
8478 final int N = mRecentTasks.size();
8479 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008480 TaskRecord tr = mRecentTasks.get(i);
8481 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8482 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008483 mRecentTasks.get(i).dump(pw, " ");
8484 }
8485 }
8486
8487 pw.println(" ");
8488 pw.println(" mCurTask: " + mCurTask);
8489
8490 pw.println(" ");
8491 pw.println("Processes in Current Activity Manager State:");
8492
8493 boolean needSep = false;
8494 int numPers = 0;
8495
8496 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8497 final int NA = procs.size();
8498 for (int ia=0; ia<NA; ia++) {
8499 if (!needSep) {
8500 pw.println(" All known processes:");
8501 needSep = true;
8502 }
8503 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008504 pw.print(r.persistent ? " *PERS*" : " *APP*");
8505 pw.print(" UID "); pw.print(procs.keyAt(ia));
8506 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008507 r.dump(pw, " ");
8508 if (r.persistent) {
8509 numPers++;
8510 }
8511 }
8512 }
8513
8514 if (mLRUProcesses.size() > 0) {
8515 if (needSep) pw.println(" ");
8516 needSep = true;
8517 pw.println(" Running processes (most recent first):");
8518 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008519 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 needSep = true;
8521 }
8522
8523 synchronized (mPidsSelfLocked) {
8524 if (mPidsSelfLocked.size() > 0) {
8525 if (needSep) pw.println(" ");
8526 needSep = true;
8527 pw.println(" PID mappings:");
8528 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008529 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8530 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008531 }
8532 }
8533 }
8534
8535 if (mForegroundProcesses.size() > 0) {
8536 if (needSep) pw.println(" ");
8537 needSep = true;
8538 pw.println(" Foreground Processes:");
8539 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008540 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8541 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008542 }
8543 }
8544
8545 if (mPersistentStartingProcesses.size() > 0) {
8546 if (needSep) pw.println(" ");
8547 needSep = true;
8548 pw.println(" Persisent processes that are starting:");
8549 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008550 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008551 }
8552
8553 if (mStartingProcesses.size() > 0) {
8554 if (needSep) pw.println(" ");
8555 needSep = true;
8556 pw.println(" Processes that are starting:");
8557 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008558 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008559 }
8560
8561 if (mRemovedProcesses.size() > 0) {
8562 if (needSep) pw.println(" ");
8563 needSep = true;
8564 pw.println(" Processes that are being removed:");
8565 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008566 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008567 }
8568
8569 if (mProcessesOnHold.size() > 0) {
8570 if (needSep) pw.println(" ");
8571 needSep = true;
8572 pw.println(" Processes that are on old until the system is ready:");
8573 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008574 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008575 }
8576
8577 if (mProcessCrashTimes.getMap().size() > 0) {
8578 if (needSep) pw.println(" ");
8579 needSep = true;
8580 pw.println(" Time since processes crashed:");
8581 long now = SystemClock.uptimeMillis();
8582 for (Map.Entry<String, SparseArray<Long>> procs
8583 : mProcessCrashTimes.getMap().entrySet()) {
8584 SparseArray<Long> uids = procs.getValue();
8585 final int N = uids.size();
8586 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008587 pw.print(" Process "); pw.print(procs.getKey());
8588 pw.print(" uid "); pw.print(uids.keyAt(i));
8589 pw.print(": last crashed ");
8590 pw.print((now-uids.valueAt(i)));
8591 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008592 }
8593 }
8594 }
8595
8596 if (mBadProcesses.getMap().size() > 0) {
8597 if (needSep) pw.println(" ");
8598 needSep = true;
8599 pw.println(" Bad processes:");
8600 for (Map.Entry<String, SparseArray<Long>> procs
8601 : mBadProcesses.getMap().entrySet()) {
8602 SparseArray<Long> uids = procs.getValue();
8603 final int N = uids.size();
8604 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008605 pw.print(" Bad process "); pw.print(procs.getKey());
8606 pw.print(" uid "); pw.print(uids.keyAt(i));
8607 pw.print(": crashed at time ");
8608 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008609 }
8610 }
8611 }
8612
8613 pw.println(" ");
8614 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008615 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008616 pw.println(" mConfiguration: " + mConfiguration);
8617 pw.println(" mStartRunning=" + mStartRunning
8618 + " mSystemReady=" + mSystemReady
8619 + " mBooting=" + mBooting
8620 + " mBooted=" + mBooted
8621 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008622 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008623 pw.println(" mGoingToSleep=" + mGoingToSleep);
8624 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8625 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8626 + " mDebugTransient=" + mDebugTransient
8627 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8628 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8629 + " mWatcher=" + mWatcher);
8630 }
8631 }
8632
8633 /**
8634 * There are three ways to call this:
8635 * - no service specified: dump all the services
8636 * - a flattened component name that matched an existing service was specified as the
8637 * first arg: dump that one service
8638 * - the first arg isn't the flattened component name of an existing service:
8639 * dump all services whose component contains the first arg as a substring
8640 */
8641 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8642 String[] newArgs;
8643 String componentNameString;
8644 ServiceRecord r;
8645 if (args.length == 1) {
8646 componentNameString = null;
8647 newArgs = EMPTY_STRING_ARRAY;
8648 r = null;
8649 } else {
8650 componentNameString = args[1];
8651 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8652 r = componentName != null ? mServices.get(componentName) : null;
8653 newArgs = new String[args.length - 2];
8654 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8655 }
8656
8657 if (r != null) {
8658 dumpService(fd, pw, r, newArgs);
8659 } else {
8660 for (ServiceRecord r1 : mServices.values()) {
8661 if (componentNameString == null
8662 || r1.name.flattenToString().contains(componentNameString)) {
8663 dumpService(fd, pw, r1, newArgs);
8664 }
8665 }
8666 }
8667 }
8668
8669 /**
8670 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8671 * there is a thread associated with the service.
8672 */
8673 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8674 pw.println(" Service " + r.name.flattenToString());
8675 if (r.app != null && r.app.thread != null) {
8676 try {
8677 // flush anything that is already in the PrintWriter since the thread is going
8678 // to write to the file descriptor directly
8679 pw.flush();
8680 r.app.thread.dumpService(fd, r, args);
8681 pw.print("\n");
8682 } catch (RemoteException e) {
8683 pw.println("got a RemoteException while dumping the service");
8684 }
8685 }
8686 }
8687
8688 void dumpBroadcasts(PrintWriter pw) {
8689 synchronized (this) {
8690 if (checkCallingPermission(android.Manifest.permission.DUMP)
8691 != PackageManager.PERMISSION_GRANTED) {
8692 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8693 + Binder.getCallingPid()
8694 + ", uid=" + Binder.getCallingUid()
8695 + " without permission "
8696 + android.Manifest.permission.DUMP);
8697 return;
8698 }
8699 pw.println("Broadcasts in Current Activity Manager State:");
8700
8701 if (mRegisteredReceivers.size() > 0) {
8702 pw.println(" ");
8703 pw.println(" Registered Receivers:");
8704 Iterator it = mRegisteredReceivers.values().iterator();
8705 while (it.hasNext()) {
8706 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008707 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008708 r.dump(pw, " ");
8709 }
8710 }
8711
8712 pw.println(" ");
8713 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008714 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008715
8716 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8717 || mPendingBroadcast != null) {
8718 if (mParallelBroadcasts.size() > 0) {
8719 pw.println(" ");
8720 pw.println(" Active broadcasts:");
8721 }
8722 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8723 pw.println(" Broadcast #" + i + ":");
8724 mParallelBroadcasts.get(i).dump(pw, " ");
8725 }
8726 if (mOrderedBroadcasts.size() > 0) {
8727 pw.println(" ");
8728 pw.println(" Active serialized broadcasts:");
8729 }
8730 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8731 pw.println(" Serialized Broadcast #" + i + ":");
8732 mOrderedBroadcasts.get(i).dump(pw, " ");
8733 }
8734 pw.println(" ");
8735 pw.println(" Pending broadcast:");
8736 if (mPendingBroadcast != null) {
8737 mPendingBroadcast.dump(pw, " ");
8738 } else {
8739 pw.println(" (null)");
8740 }
8741 }
8742
8743 pw.println(" ");
8744 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8745 if (mStickyBroadcasts != null) {
8746 pw.println(" ");
8747 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008748 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008749 for (Map.Entry<String, ArrayList<Intent>> ent
8750 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008751 pw.print(" * Sticky action "); pw.print(ent.getKey());
8752 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008753 ArrayList<Intent> intents = ent.getValue();
8754 final int N = intents.size();
8755 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008756 sb.setLength(0);
8757 sb.append(" Intent: ");
8758 intents.get(i).toShortString(sb, true, false);
8759 pw.println(sb.toString());
8760 Bundle bundle = intents.get(i).getExtras();
8761 if (bundle != null) {
8762 pw.print(" ");
8763 pw.println(bundle.toString());
8764 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008765 }
8766 }
8767 }
8768
8769 pw.println(" ");
8770 pw.println(" mHandler:");
8771 mHandler.dump(new PrintWriterPrinter(pw), " ");
8772 }
8773 }
8774
8775 void dumpServices(PrintWriter pw) {
8776 synchronized (this) {
8777 if (checkCallingPermission(android.Manifest.permission.DUMP)
8778 != PackageManager.PERMISSION_GRANTED) {
8779 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8780 + Binder.getCallingPid()
8781 + ", uid=" + Binder.getCallingUid()
8782 + " without permission "
8783 + android.Manifest.permission.DUMP);
8784 return;
8785 }
8786 pw.println("Services in Current Activity Manager State:");
8787
8788 boolean needSep = false;
8789
8790 if (mServices.size() > 0) {
8791 pw.println(" Active services:");
8792 Iterator<ServiceRecord> it = mServices.values().iterator();
8793 while (it.hasNext()) {
8794 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008795 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 r.dump(pw, " ");
8797 }
8798 needSep = true;
8799 }
8800
8801 if (mPendingServices.size() > 0) {
8802 if (needSep) pw.println(" ");
8803 pw.println(" Pending services:");
8804 for (int i=0; i<mPendingServices.size(); i++) {
8805 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008806 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008807 r.dump(pw, " ");
8808 }
8809 needSep = true;
8810 }
8811
8812 if (mRestartingServices.size() > 0) {
8813 if (needSep) pw.println(" ");
8814 pw.println(" Restarting services:");
8815 for (int i=0; i<mRestartingServices.size(); i++) {
8816 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008817 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008818 r.dump(pw, " ");
8819 }
8820 needSep = true;
8821 }
8822
8823 if (mStoppingServices.size() > 0) {
8824 if (needSep) pw.println(" ");
8825 pw.println(" Stopping services:");
8826 for (int i=0; i<mStoppingServices.size(); i++) {
8827 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008828 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008829 r.dump(pw, " ");
8830 }
8831 needSep = true;
8832 }
8833
8834 if (mServiceConnections.size() > 0) {
8835 if (needSep) pw.println(" ");
8836 pw.println(" Connection bindings to services:");
8837 Iterator<ConnectionRecord> it
8838 = mServiceConnections.values().iterator();
8839 while (it.hasNext()) {
8840 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008841 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008842 r.dump(pw, " ");
8843 }
8844 }
8845 }
8846 }
8847
8848 void dumpProviders(PrintWriter pw) {
8849 synchronized (this) {
8850 if (checkCallingPermission(android.Manifest.permission.DUMP)
8851 != PackageManager.PERMISSION_GRANTED) {
8852 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8853 + Binder.getCallingPid()
8854 + ", uid=" + Binder.getCallingUid()
8855 + " without permission "
8856 + android.Manifest.permission.DUMP);
8857 return;
8858 }
8859
8860 pw.println("Content Providers in Current Activity Manager State:");
8861
8862 boolean needSep = false;
8863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008864 if (mProvidersByClass.size() > 0) {
8865 if (needSep) pw.println(" ");
8866 pw.println(" Published content providers (by class):");
8867 Iterator it = mProvidersByClass.entrySet().iterator();
8868 while (it.hasNext()) {
8869 Map.Entry e = (Map.Entry)it.next();
8870 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008871 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008872 r.dump(pw, " ");
8873 }
8874 needSep = true;
8875 }
8876
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008877 if (mProvidersByName.size() > 0) {
8878 pw.println(" ");
8879 pw.println(" Authority to provider mappings:");
8880 Iterator it = mProvidersByName.entrySet().iterator();
8881 while (it.hasNext()) {
8882 Map.Entry e = (Map.Entry)it.next();
8883 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8884 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8885 pw.println(r);
8886 }
8887 needSep = true;
8888 }
8889
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008890 if (mLaunchingProviders.size() > 0) {
8891 if (needSep) pw.println(" ");
8892 pw.println(" Launching content providers:");
8893 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008894 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8895 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008896 }
8897 needSep = true;
8898 }
8899
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008900 if (mGrantedUriPermissions.size() > 0) {
8901 pw.println();
8902 pw.println("Granted Uri Permissions:");
8903 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8904 int uid = mGrantedUriPermissions.keyAt(i);
8905 HashMap<Uri, UriPermission> perms
8906 = mGrantedUriPermissions.valueAt(i);
8907 pw.print(" * UID "); pw.print(uid);
8908 pw.println(" holds:");
8909 for (UriPermission perm : perms.values()) {
8910 pw.print(" "); pw.println(perm);
8911 perm.dump(pw, " ");
8912 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008913 }
8914 }
8915 }
8916 }
8917
8918 void dumpSenders(PrintWriter pw) {
8919 synchronized (this) {
8920 if (checkCallingPermission(android.Manifest.permission.DUMP)
8921 != PackageManager.PERMISSION_GRANTED) {
8922 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8923 + Binder.getCallingPid()
8924 + ", uid=" + Binder.getCallingUid()
8925 + " without permission "
8926 + android.Manifest.permission.DUMP);
8927 return;
8928 }
8929
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008930 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931
8932 if (this.mIntentSenderRecords.size() > 0) {
8933 Iterator<WeakReference<PendingIntentRecord>> it
8934 = mIntentSenderRecords.values().iterator();
8935 while (it.hasNext()) {
8936 WeakReference<PendingIntentRecord> ref = it.next();
8937 PendingIntentRecord rec = ref != null ? ref.get(): null;
8938 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008939 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 rec.dump(pw, " ");
8941 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008942 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008943 }
8944 }
8945 }
8946 }
8947 }
8948
8949 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008950 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 TaskRecord lastTask = null;
8952 for (int i=list.size()-1; i>=0; i--) {
8953 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008954 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008955 if (lastTask != r.task) {
8956 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008957 pw.print(prefix);
8958 pw.print(full ? "* " : " ");
8959 pw.println(lastTask);
8960 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008961 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008963 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008964 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8965 pw.print(" #"); pw.print(i); pw.print(": ");
8966 pw.println(r);
8967 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008968 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 }
8971 }
8972
8973 private static final int dumpProcessList(PrintWriter pw, List list,
8974 String prefix, String normalLabel, String persistentLabel,
8975 boolean inclOomAdj) {
8976 int numPers = 0;
8977 for (int i=list.size()-1; i>=0; i--) {
8978 ProcessRecord r = (ProcessRecord)list.get(i);
8979 if (false) {
8980 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8981 + " #" + i + ":");
8982 r.dump(pw, prefix + " ");
8983 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008984 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008985 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008986 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008987 } else {
8988 pw.println(String.format("%s%s #%2d: %s",
8989 prefix, (r.persistent ? persistentLabel : normalLabel),
8990 i, r.toString()));
8991 }
8992 if (r.persistent) {
8993 numPers++;
8994 }
8995 }
8996 return numPers;
8997 }
8998
8999 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9000 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009001 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009002 long uptime = SystemClock.uptimeMillis();
9003 long realtime = SystemClock.elapsedRealtime();
9004
9005 if (isCheckinRequest) {
9006 // short checkin version
9007 pw.println(uptime + "," + realtime);
9008 pw.flush();
9009 } else {
9010 pw.println("Applications Memory Usage (kB):");
9011 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9012 }
9013 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9014 ProcessRecord r = (ProcessRecord)list.get(i);
9015 if (r.thread != null) {
9016 if (!isCheckinRequest) {
9017 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9018 pw.flush();
9019 }
9020 try {
9021 r.thread.asBinder().dump(fd, args);
9022 } catch (RemoteException e) {
9023 if (!isCheckinRequest) {
9024 pw.println("Got RemoteException!");
9025 pw.flush();
9026 }
9027 }
9028 }
9029 }
9030 }
9031
9032 /**
9033 * Searches array of arguments for the specified string
9034 * @param args array of argument strings
9035 * @param value value to search for
9036 * @return true if the value is contained in the array
9037 */
9038 private static boolean scanArgs(String[] args, String value) {
9039 if (args != null) {
9040 for (String arg : args) {
9041 if (value.equals(arg)) {
9042 return true;
9043 }
9044 }
9045 }
9046 return false;
9047 }
9048
Dianne Hackborn75b03852009-06-12 15:43:26 -07009049 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009050 int count = mHistory.size();
9051
9052 // convert the token to an entry in the history.
9053 HistoryRecord r = null;
9054 int index = -1;
9055 for (int i=count-1; i>=0; i--) {
9056 Object o = mHistory.get(i);
9057 if (o == token) {
9058 r = (HistoryRecord)o;
9059 index = i;
9060 break;
9061 }
9062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063
9064 return index;
9065 }
9066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009067 private final void killServicesLocked(ProcessRecord app,
9068 boolean allowRestart) {
9069 // Report disconnected services.
9070 if (false) {
9071 // XXX we are letting the client link to the service for
9072 // death notifications.
9073 if (app.services.size() > 0) {
9074 Iterator it = app.services.iterator();
9075 while (it.hasNext()) {
9076 ServiceRecord r = (ServiceRecord)it.next();
9077 if (r.connections.size() > 0) {
9078 Iterator<ConnectionRecord> jt
9079 = r.connections.values().iterator();
9080 while (jt.hasNext()) {
9081 ConnectionRecord c = jt.next();
9082 if (c.binding.client != app) {
9083 try {
9084 //c.conn.connected(r.className, null);
9085 } catch (Exception e) {
9086 // todo: this should be asynchronous!
9087 Log.w(TAG, "Exception thrown disconnected servce "
9088 + r.shortName
9089 + " from app " + app.processName, e);
9090 }
9091 }
9092 }
9093 }
9094 }
9095 }
9096 }
9097
9098 // Clean up any connections this application has to other services.
9099 if (app.connections.size() > 0) {
9100 Iterator<ConnectionRecord> it = app.connections.iterator();
9101 while (it.hasNext()) {
9102 ConnectionRecord r = it.next();
9103 removeConnectionLocked(r, app, null);
9104 }
9105 }
9106 app.connections.clear();
9107
9108 if (app.services.size() != 0) {
9109 // Any services running in the application need to be placed
9110 // back in the pending list.
9111 Iterator it = app.services.iterator();
9112 while (it.hasNext()) {
9113 ServiceRecord sr = (ServiceRecord)it.next();
9114 synchronized (sr.stats.getBatteryStats()) {
9115 sr.stats.stopLaunchedLocked();
9116 }
9117 sr.app = null;
9118 sr.executeNesting = 0;
9119 mStoppingServices.remove(sr);
9120 if (sr.bindings.size() > 0) {
9121 Iterator<IntentBindRecord> bindings
9122 = sr.bindings.values().iterator();
9123 while (bindings.hasNext()) {
9124 IntentBindRecord b = bindings.next();
9125 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9126 + ": shouldUnbind=" + b.hasBound);
9127 b.binder = null;
9128 b.requested = b.received = b.hasBound = false;
9129 }
9130 }
9131
9132 if (sr.crashCount >= 2) {
9133 Log.w(TAG, "Service crashed " + sr.crashCount
9134 + " times, stopping: " + sr);
9135 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9136 sr.crashCount, sr.shortName, app.pid);
9137 bringDownServiceLocked(sr, true);
9138 } else if (!allowRestart) {
9139 bringDownServiceLocked(sr, true);
9140 } else {
9141 scheduleServiceRestartLocked(sr);
9142 }
9143 }
9144
9145 if (!allowRestart) {
9146 app.services.clear();
9147 }
9148 }
9149
9150 app.executingServices.clear();
9151 }
9152
9153 private final void removeDyingProviderLocked(ProcessRecord proc,
9154 ContentProviderRecord cpr) {
9155 synchronized (cpr) {
9156 cpr.launchingApp = null;
9157 cpr.notifyAll();
9158 }
9159
9160 mProvidersByClass.remove(cpr.info.name);
9161 String names[] = cpr.info.authority.split(";");
9162 for (int j = 0; j < names.length; j++) {
9163 mProvidersByName.remove(names[j]);
9164 }
9165
9166 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9167 while (cit.hasNext()) {
9168 ProcessRecord capp = cit.next();
9169 if (!capp.persistent && capp.thread != null
9170 && capp.pid != 0
9171 && capp.pid != MY_PID) {
9172 Log.i(TAG, "Killing app " + capp.processName
9173 + " (pid " + capp.pid
9174 + ") because provider " + cpr.info.name
9175 + " is in dying process " + proc.processName);
9176 Process.killProcess(capp.pid);
9177 }
9178 }
9179
9180 mLaunchingProviders.remove(cpr);
9181 }
9182
9183 /**
9184 * Main code for cleaning up a process when it has gone away. This is
9185 * called both as a result of the process dying, or directly when stopping
9186 * a process when running in single process mode.
9187 */
9188 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9189 boolean restarting, int index) {
9190 if (index >= 0) {
9191 mLRUProcesses.remove(index);
9192 }
9193
9194 // Dismiss any open dialogs.
9195 if (app.crashDialog != null) {
9196 app.crashDialog.dismiss();
9197 app.crashDialog = null;
9198 }
9199 if (app.anrDialog != null) {
9200 app.anrDialog.dismiss();
9201 app.anrDialog = null;
9202 }
9203 if (app.waitDialog != null) {
9204 app.waitDialog.dismiss();
9205 app.waitDialog = null;
9206 }
9207
9208 app.crashing = false;
9209 app.notResponding = false;
9210
9211 app.resetPackageList();
9212 app.thread = null;
9213 app.forcingToForeground = null;
9214 app.foregroundServices = false;
9215
9216 killServicesLocked(app, true);
9217
9218 boolean restart = false;
9219
9220 int NL = mLaunchingProviders.size();
9221
9222 // Remove published content providers.
9223 if (!app.pubProviders.isEmpty()) {
9224 Iterator it = app.pubProviders.values().iterator();
9225 while (it.hasNext()) {
9226 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9227 cpr.provider = null;
9228 cpr.app = null;
9229
9230 // See if someone is waiting for this provider... in which
9231 // case we don't remove it, but just let it restart.
9232 int i = 0;
9233 if (!app.bad) {
9234 for (; i<NL; i++) {
9235 if (mLaunchingProviders.get(i) == cpr) {
9236 restart = true;
9237 break;
9238 }
9239 }
9240 } else {
9241 i = NL;
9242 }
9243
9244 if (i >= NL) {
9245 removeDyingProviderLocked(app, cpr);
9246 NL = mLaunchingProviders.size();
9247 }
9248 }
9249 app.pubProviders.clear();
9250 }
9251
9252 // Look through the content providers we are waiting to have launched,
9253 // and if any run in this process then either schedule a restart of
9254 // the process or kill the client waiting for it if this process has
9255 // gone bad.
9256 for (int i=0; i<NL; i++) {
9257 ContentProviderRecord cpr = (ContentProviderRecord)
9258 mLaunchingProviders.get(i);
9259 if (cpr.launchingApp == app) {
9260 if (!app.bad) {
9261 restart = true;
9262 } else {
9263 removeDyingProviderLocked(app, cpr);
9264 NL = mLaunchingProviders.size();
9265 }
9266 }
9267 }
9268
9269 // Unregister from connected content providers.
9270 if (!app.conProviders.isEmpty()) {
9271 Iterator it = app.conProviders.iterator();
9272 while (it.hasNext()) {
9273 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9274 cpr.clients.remove(app);
9275 }
9276 app.conProviders.clear();
9277 }
9278
9279 skipCurrentReceiverLocked(app);
9280
9281 // Unregister any receivers.
9282 if (app.receivers.size() > 0) {
9283 Iterator<ReceiverList> it = app.receivers.iterator();
9284 while (it.hasNext()) {
9285 removeReceiverLocked(it.next());
9286 }
9287 app.receivers.clear();
9288 }
9289
Christopher Tate181fafa2009-05-14 11:12:14 -07009290 // If the app is undergoing backup, tell the backup manager about it
9291 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9292 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9293 try {
9294 IBackupManager bm = IBackupManager.Stub.asInterface(
9295 ServiceManager.getService(Context.BACKUP_SERVICE));
9296 bm.agentDisconnected(app.info.packageName);
9297 } catch (RemoteException e) {
9298 // can't happen; backup manager is local
9299 }
9300 }
9301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009302 // If the caller is restarting this app, then leave it in its
9303 // current lists and let the caller take care of it.
9304 if (restarting) {
9305 return;
9306 }
9307
9308 if (!app.persistent) {
9309 if (DEBUG_PROCESSES) Log.v(TAG,
9310 "Removing non-persistent process during cleanup: " + app);
9311 mProcessNames.remove(app.processName, app.info.uid);
9312 } else if (!app.removed) {
9313 // This app is persistent, so we need to keep its record around.
9314 // If it is not already on the pending app list, add it there
9315 // and start a new process for it.
9316 app.thread = null;
9317 app.forcingToForeground = null;
9318 app.foregroundServices = false;
9319 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9320 mPersistentStartingProcesses.add(app);
9321 restart = true;
9322 }
9323 }
9324 mProcessesOnHold.remove(app);
9325
The Android Open Source Project4df24232009-03-05 14:34:35 -08009326 if (app == mHomeProcess) {
9327 mHomeProcess = null;
9328 }
9329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009330 if (restart) {
9331 // We have components that still need to be running in the
9332 // process, so re-launch it.
9333 mProcessNames.put(app.processName, app.info.uid, app);
9334 startProcessLocked(app, "restart", app.processName);
9335 } else if (app.pid > 0 && app.pid != MY_PID) {
9336 // Goodbye!
9337 synchronized (mPidsSelfLocked) {
9338 mPidsSelfLocked.remove(app.pid);
9339 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9340 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009341 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009342 }
9343 }
9344
9345 // =========================================================
9346 // SERVICES
9347 // =========================================================
9348
9349 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9350 ActivityManager.RunningServiceInfo info =
9351 new ActivityManager.RunningServiceInfo();
9352 info.service = r.name;
9353 if (r.app != null) {
9354 info.pid = r.app.pid;
9355 }
9356 info.process = r.processName;
9357 info.foreground = r.isForeground;
9358 info.activeSince = r.createTime;
9359 info.started = r.startRequested;
9360 info.clientCount = r.connections.size();
9361 info.crashCount = r.crashCount;
9362 info.lastActivityTime = r.lastActivity;
9363 return info;
9364 }
9365
9366 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9367 int flags) {
9368 synchronized (this) {
9369 ArrayList<ActivityManager.RunningServiceInfo> res
9370 = new ArrayList<ActivityManager.RunningServiceInfo>();
9371
9372 if (mServices.size() > 0) {
9373 Iterator<ServiceRecord> it = mServices.values().iterator();
9374 while (it.hasNext() && res.size() < maxNum) {
9375 res.add(makeRunningServiceInfoLocked(it.next()));
9376 }
9377 }
9378
9379 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9380 ServiceRecord r = mRestartingServices.get(i);
9381 ActivityManager.RunningServiceInfo info =
9382 makeRunningServiceInfoLocked(r);
9383 info.restarting = r.nextRestartTime;
9384 res.add(info);
9385 }
9386
9387 return res;
9388 }
9389 }
9390
9391 private final ServiceRecord findServiceLocked(ComponentName name,
9392 IBinder token) {
9393 ServiceRecord r = mServices.get(name);
9394 return r == token ? r : null;
9395 }
9396
9397 private final class ServiceLookupResult {
9398 final ServiceRecord record;
9399 final String permission;
9400
9401 ServiceLookupResult(ServiceRecord _record, String _permission) {
9402 record = _record;
9403 permission = _permission;
9404 }
9405 };
9406
9407 private ServiceLookupResult findServiceLocked(Intent service,
9408 String resolvedType) {
9409 ServiceRecord r = null;
9410 if (service.getComponent() != null) {
9411 r = mServices.get(service.getComponent());
9412 }
9413 if (r == null) {
9414 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9415 r = mServicesByIntent.get(filter);
9416 }
9417
9418 if (r == null) {
9419 try {
9420 ResolveInfo rInfo =
9421 ActivityThread.getPackageManager().resolveService(
9422 service, resolvedType, 0);
9423 ServiceInfo sInfo =
9424 rInfo != null ? rInfo.serviceInfo : null;
9425 if (sInfo == null) {
9426 return null;
9427 }
9428
9429 ComponentName name = new ComponentName(
9430 sInfo.applicationInfo.packageName, sInfo.name);
9431 r = mServices.get(name);
9432 } catch (RemoteException ex) {
9433 // pm is in same process, this will never happen.
9434 }
9435 }
9436 if (r != null) {
9437 int callingPid = Binder.getCallingPid();
9438 int callingUid = Binder.getCallingUid();
9439 if (checkComponentPermission(r.permission,
9440 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9441 != PackageManager.PERMISSION_GRANTED) {
9442 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9443 + " from pid=" + callingPid
9444 + ", uid=" + callingUid
9445 + " requires " + r.permission);
9446 return new ServiceLookupResult(null, r.permission);
9447 }
9448 return new ServiceLookupResult(r, null);
9449 }
9450 return null;
9451 }
9452
9453 private class ServiceRestarter implements Runnable {
9454 private ServiceRecord mService;
9455
9456 void setService(ServiceRecord service) {
9457 mService = service;
9458 }
9459
9460 public void run() {
9461 synchronized(ActivityManagerService.this) {
9462 performServiceRestartLocked(mService);
9463 }
9464 }
9465 }
9466
9467 private ServiceLookupResult retrieveServiceLocked(Intent service,
9468 String resolvedType, int callingPid, int callingUid) {
9469 ServiceRecord r = null;
9470 if (service.getComponent() != null) {
9471 r = mServices.get(service.getComponent());
9472 }
9473 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9474 r = mServicesByIntent.get(filter);
9475 if (r == null) {
9476 try {
9477 ResolveInfo rInfo =
9478 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009479 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009480 ServiceInfo sInfo =
9481 rInfo != null ? rInfo.serviceInfo : null;
9482 if (sInfo == null) {
9483 Log.w(TAG, "Unable to start service " + service +
9484 ": not found");
9485 return null;
9486 }
9487
9488 ComponentName name = new ComponentName(
9489 sInfo.applicationInfo.packageName, sInfo.name);
9490 r = mServices.get(name);
9491 if (r == null) {
9492 filter = new Intent.FilterComparison(service.cloneFilter());
9493 ServiceRestarter res = new ServiceRestarter();
9494 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9495 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9496 synchronized (stats) {
9497 ss = stats.getServiceStatsLocked(
9498 sInfo.applicationInfo.uid, sInfo.packageName,
9499 sInfo.name);
9500 }
9501 r = new ServiceRecord(ss, name, filter, sInfo, res);
9502 res.setService(r);
9503 mServices.put(name, r);
9504 mServicesByIntent.put(filter, r);
9505
9506 // Make sure this component isn't in the pending list.
9507 int N = mPendingServices.size();
9508 for (int i=0; i<N; i++) {
9509 ServiceRecord pr = mPendingServices.get(i);
9510 if (pr.name.equals(name)) {
9511 mPendingServices.remove(i);
9512 i--;
9513 N--;
9514 }
9515 }
9516 }
9517 } catch (RemoteException ex) {
9518 // pm is in same process, this will never happen.
9519 }
9520 }
9521 if (r != null) {
9522 if (checkComponentPermission(r.permission,
9523 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9524 != PackageManager.PERMISSION_GRANTED) {
9525 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9526 + " from pid=" + Binder.getCallingPid()
9527 + ", uid=" + Binder.getCallingUid()
9528 + " requires " + r.permission);
9529 return new ServiceLookupResult(null, r.permission);
9530 }
9531 return new ServiceLookupResult(r, null);
9532 }
9533 return null;
9534 }
9535
9536 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9537 long now = SystemClock.uptimeMillis();
9538 if (r.executeNesting == 0 && r.app != null) {
9539 if (r.app.executingServices.size() == 0) {
9540 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9541 msg.obj = r.app;
9542 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9543 }
9544 r.app.executingServices.add(r);
9545 }
9546 r.executeNesting++;
9547 r.executingStart = now;
9548 }
9549
9550 private final void sendServiceArgsLocked(ServiceRecord r,
9551 boolean oomAdjusted) {
9552 final int N = r.startArgs.size();
9553 if (N == 0) {
9554 return;
9555 }
9556
9557 final int BASEID = r.lastStartId - N + 1;
9558 int i = 0;
9559 while (i < N) {
9560 try {
9561 Intent args = r.startArgs.get(i);
9562 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9563 + r.name + " " + r.intent + " args=" + args);
9564 bumpServiceExecutingLocked(r);
9565 if (!oomAdjusted) {
9566 oomAdjusted = true;
9567 updateOomAdjLocked(r.app);
9568 }
9569 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9570 i++;
9571 } catch (Exception e) {
9572 break;
9573 }
9574 }
9575 if (i == N) {
9576 r.startArgs.clear();
9577 } else {
9578 while (i > 0) {
9579 r.startArgs.remove(0);
9580 i--;
9581 }
9582 }
9583 }
9584
9585 private final boolean requestServiceBindingLocked(ServiceRecord r,
9586 IntentBindRecord i, boolean rebind) {
9587 if (r.app == null || r.app.thread == null) {
9588 // If service is not currently running, can't yet bind.
9589 return false;
9590 }
9591 if ((!i.requested || rebind) && i.apps.size() > 0) {
9592 try {
9593 bumpServiceExecutingLocked(r);
9594 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9595 + ": shouldUnbind=" + i.hasBound);
9596 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9597 if (!rebind) {
9598 i.requested = true;
9599 }
9600 i.hasBound = true;
9601 i.doRebind = false;
9602 } catch (RemoteException e) {
9603 return false;
9604 }
9605 }
9606 return true;
9607 }
9608
9609 private final void requestServiceBindingsLocked(ServiceRecord r) {
9610 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9611 while (bindings.hasNext()) {
9612 IntentBindRecord i = bindings.next();
9613 if (!requestServiceBindingLocked(r, i, false)) {
9614 break;
9615 }
9616 }
9617 }
9618
9619 private final void realStartServiceLocked(ServiceRecord r,
9620 ProcessRecord app) throws RemoteException {
9621 if (app.thread == null) {
9622 throw new RemoteException();
9623 }
9624
9625 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009626 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009627
9628 app.services.add(r);
9629 bumpServiceExecutingLocked(r);
9630 updateLRUListLocked(app, true);
9631
9632 boolean created = false;
9633 try {
9634 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9635 + r.name + " " + r.intent);
9636 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9637 System.identityHashCode(r), r.shortName,
9638 r.intent.getIntent().toString(), r.app.pid);
9639 synchronized (r.stats.getBatteryStats()) {
9640 r.stats.startLaunchedLocked();
9641 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009642 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009643 app.thread.scheduleCreateService(r, r.serviceInfo);
9644 created = true;
9645 } finally {
9646 if (!created) {
9647 app.services.remove(r);
9648 scheduleServiceRestartLocked(r);
9649 }
9650 }
9651
9652 requestServiceBindingsLocked(r);
9653 sendServiceArgsLocked(r, true);
9654 }
9655
9656 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9657 r.totalRestartCount++;
9658 if (r.restartDelay == 0) {
9659 r.restartCount++;
9660 r.restartDelay = SERVICE_RESTART_DURATION;
9661 } else {
9662 // If it has been a "reasonably long time" since the service
9663 // was started, then reset our restart duration back to
9664 // the beginning, so we don't infinitely increase the duration
9665 // on a service that just occasionally gets killed (which is
9666 // a normal case, due to process being killed to reclaim memory).
9667 long now = SystemClock.uptimeMillis();
9668 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9669 r.restartCount = 1;
9670 r.restartDelay = SERVICE_RESTART_DURATION;
9671 } else {
9672 r.restartDelay *= 2;
9673 }
9674 }
9675 if (!mRestartingServices.contains(r)) {
9676 mRestartingServices.add(r);
9677 }
9678 mHandler.removeCallbacks(r.restarter);
9679 mHandler.postDelayed(r.restarter, r.restartDelay);
9680 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9681 Log.w(TAG, "Scheduling restart of crashed service "
9682 + r.shortName + " in " + r.restartDelay + "ms");
9683 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9684 r.shortName, r.restartDelay);
9685
9686 Message msg = Message.obtain();
9687 msg.what = SERVICE_ERROR_MSG;
9688 msg.obj = r;
9689 mHandler.sendMessage(msg);
9690 }
9691
9692 final void performServiceRestartLocked(ServiceRecord r) {
9693 if (!mRestartingServices.contains(r)) {
9694 return;
9695 }
9696 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9697 }
9698
9699 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9700 if (r.restartDelay == 0) {
9701 return false;
9702 }
9703 r.resetRestartCounter();
9704 mRestartingServices.remove(r);
9705 mHandler.removeCallbacks(r.restarter);
9706 return true;
9707 }
9708
9709 private final boolean bringUpServiceLocked(ServiceRecord r,
9710 int intentFlags, boolean whileRestarting) {
9711 //Log.i(TAG, "Bring up service:");
9712 //r.dump(" ");
9713
9714 if (r.app != null) {
9715 sendServiceArgsLocked(r, false);
9716 return true;
9717 }
9718
9719 if (!whileRestarting && r.restartDelay > 0) {
9720 // If waiting for a restart, then do nothing.
9721 return true;
9722 }
9723
9724 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9725 + " " + r.intent);
9726
9727 final String appName = r.processName;
9728 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9729 if (app != null && app.thread != null) {
9730 try {
9731 realStartServiceLocked(r, app);
9732 return true;
9733 } catch (RemoteException e) {
9734 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9735 }
9736
9737 // If a dead object exception was thrown -- fall through to
9738 // restart the application.
9739 }
9740
9741 if (!mPendingServices.contains(r)) {
9742 // Not running -- get it started, and enqueue this service record
9743 // to be executed when the app comes up.
9744 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9745 "service", r.name) == null) {
9746 Log.w(TAG, "Unable to launch app "
9747 + r.appInfo.packageName + "/"
9748 + r.appInfo.uid + " for service "
9749 + r.intent.getIntent() + ": process is bad");
9750 bringDownServiceLocked(r, true);
9751 return false;
9752 }
9753 mPendingServices.add(r);
9754 }
9755 return true;
9756 }
9757
9758 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9759 //Log.i(TAG, "Bring down service:");
9760 //r.dump(" ");
9761
9762 // Does it still need to run?
9763 if (!force && r.startRequested) {
9764 return;
9765 }
9766 if (r.connections.size() > 0) {
9767 if (!force) {
9768 // XXX should probably keep a count of the number of auto-create
9769 // connections directly in the service.
9770 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9771 while (it.hasNext()) {
9772 ConnectionRecord cr = it.next();
9773 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9774 return;
9775 }
9776 }
9777 }
9778
9779 // Report to all of the connections that the service is no longer
9780 // available.
9781 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9782 while (it.hasNext()) {
9783 ConnectionRecord c = it.next();
9784 try {
9785 // todo: shouldn't be a synchronous call!
9786 c.conn.connected(r.name, null);
9787 } catch (Exception e) {
9788 Log.w(TAG, "Failure disconnecting service " + r.name +
9789 " to connection " + c.conn.asBinder() +
9790 " (in " + c.binding.client.processName + ")", e);
9791 }
9792 }
9793 }
9794
9795 // Tell the service that it has been unbound.
9796 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9797 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9798 while (it.hasNext()) {
9799 IntentBindRecord ibr = it.next();
9800 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9801 + ": hasBound=" + ibr.hasBound);
9802 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9803 try {
9804 bumpServiceExecutingLocked(r);
9805 updateOomAdjLocked(r.app);
9806 ibr.hasBound = false;
9807 r.app.thread.scheduleUnbindService(r,
9808 ibr.intent.getIntent());
9809 } catch (Exception e) {
9810 Log.w(TAG, "Exception when unbinding service "
9811 + r.shortName, e);
9812 serviceDoneExecutingLocked(r, true);
9813 }
9814 }
9815 }
9816 }
9817
9818 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9819 + " " + r.intent);
9820 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9821 System.identityHashCode(r), r.shortName,
9822 (r.app != null) ? r.app.pid : -1);
9823
9824 mServices.remove(r.name);
9825 mServicesByIntent.remove(r.intent);
9826 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9827 r.totalRestartCount = 0;
9828 unscheduleServiceRestartLocked(r);
9829
9830 // Also make sure it is not on the pending list.
9831 int N = mPendingServices.size();
9832 for (int i=0; i<N; i++) {
9833 if (mPendingServices.get(i) == r) {
9834 mPendingServices.remove(i);
9835 if (DEBUG_SERVICE) Log.v(
9836 TAG, "Removed pending service: " + r.shortName);
9837 i--;
9838 N--;
9839 }
9840 }
9841
9842 if (r.app != null) {
9843 synchronized (r.stats.getBatteryStats()) {
9844 r.stats.stopLaunchedLocked();
9845 }
9846 r.app.services.remove(r);
9847 if (r.app.thread != null) {
9848 updateServiceForegroundLocked(r.app, false);
9849 try {
9850 Log.i(TAG, "Stopping service: " + r.shortName);
9851 bumpServiceExecutingLocked(r);
9852 mStoppingServices.add(r);
9853 updateOomAdjLocked(r.app);
9854 r.app.thread.scheduleStopService(r);
9855 } catch (Exception e) {
9856 Log.w(TAG, "Exception when stopping service "
9857 + r.shortName, e);
9858 serviceDoneExecutingLocked(r, true);
9859 }
9860 } else {
9861 if (DEBUG_SERVICE) Log.v(
9862 TAG, "Removed service that has no process: " + r.shortName);
9863 }
9864 } else {
9865 if (DEBUG_SERVICE) Log.v(
9866 TAG, "Removed service that is not running: " + r.shortName);
9867 }
9868 }
9869
9870 ComponentName startServiceLocked(IApplicationThread caller,
9871 Intent service, String resolvedType,
9872 int callingPid, int callingUid) {
9873 synchronized(this) {
9874 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9875 + " type=" + resolvedType + " args=" + service.getExtras());
9876
9877 if (caller != null) {
9878 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9879 if (callerApp == null) {
9880 throw new SecurityException(
9881 "Unable to find app for caller " + caller
9882 + " (pid=" + Binder.getCallingPid()
9883 + ") when starting service " + service);
9884 }
9885 }
9886
9887 ServiceLookupResult res =
9888 retrieveServiceLocked(service, resolvedType,
9889 callingPid, callingUid);
9890 if (res == null) {
9891 return null;
9892 }
9893 if (res.record == null) {
9894 return new ComponentName("!", res.permission != null
9895 ? res.permission : "private to package");
9896 }
9897 ServiceRecord r = res.record;
9898 if (unscheduleServiceRestartLocked(r)) {
9899 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9900 + r.shortName);
9901 }
9902 r.startRequested = true;
9903 r.startArgs.add(service);
9904 r.lastStartId++;
9905 if (r.lastStartId < 1) {
9906 r.lastStartId = 1;
9907 }
9908 r.lastActivity = SystemClock.uptimeMillis();
9909 synchronized (r.stats.getBatteryStats()) {
9910 r.stats.startRunningLocked();
9911 }
9912 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9913 return new ComponentName("!", "Service process is bad");
9914 }
9915 return r.name;
9916 }
9917 }
9918
9919 public ComponentName startService(IApplicationThread caller, Intent service,
9920 String resolvedType) {
9921 // Refuse possible leaked file descriptors
9922 if (service != null && service.hasFileDescriptors() == true) {
9923 throw new IllegalArgumentException("File descriptors passed in Intent");
9924 }
9925
9926 synchronized(this) {
9927 final int callingPid = Binder.getCallingPid();
9928 final int callingUid = Binder.getCallingUid();
9929 final long origId = Binder.clearCallingIdentity();
9930 ComponentName res = startServiceLocked(caller, service,
9931 resolvedType, callingPid, callingUid);
9932 Binder.restoreCallingIdentity(origId);
9933 return res;
9934 }
9935 }
9936
9937 ComponentName startServiceInPackage(int uid,
9938 Intent service, String resolvedType) {
9939 synchronized(this) {
9940 final long origId = Binder.clearCallingIdentity();
9941 ComponentName res = startServiceLocked(null, service,
9942 resolvedType, -1, uid);
9943 Binder.restoreCallingIdentity(origId);
9944 return res;
9945 }
9946 }
9947
9948 public int stopService(IApplicationThread caller, Intent service,
9949 String resolvedType) {
9950 // Refuse possible leaked file descriptors
9951 if (service != null && service.hasFileDescriptors() == true) {
9952 throw new IllegalArgumentException("File descriptors passed in Intent");
9953 }
9954
9955 synchronized(this) {
9956 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9957 + " type=" + resolvedType);
9958
9959 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9960 if (caller != null && callerApp == null) {
9961 throw new SecurityException(
9962 "Unable to find app for caller " + caller
9963 + " (pid=" + Binder.getCallingPid()
9964 + ") when stopping service " + service);
9965 }
9966
9967 // If this service is active, make sure it is stopped.
9968 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9969 if (r != null) {
9970 if (r.record != null) {
9971 synchronized (r.record.stats.getBatteryStats()) {
9972 r.record.stats.stopRunningLocked();
9973 }
9974 r.record.startRequested = false;
9975 final long origId = Binder.clearCallingIdentity();
9976 bringDownServiceLocked(r.record, false);
9977 Binder.restoreCallingIdentity(origId);
9978 return 1;
9979 }
9980 return -1;
9981 }
9982 }
9983
9984 return 0;
9985 }
9986
9987 public IBinder peekService(Intent service, String resolvedType) {
9988 // Refuse possible leaked file descriptors
9989 if (service != null && service.hasFileDescriptors() == true) {
9990 throw new IllegalArgumentException("File descriptors passed in Intent");
9991 }
9992
9993 IBinder ret = null;
9994
9995 synchronized(this) {
9996 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9997
9998 if (r != null) {
9999 // r.record is null if findServiceLocked() failed the caller permission check
10000 if (r.record == null) {
10001 throw new SecurityException(
10002 "Permission Denial: Accessing service " + r.record.name
10003 + " from pid=" + Binder.getCallingPid()
10004 + ", uid=" + Binder.getCallingUid()
10005 + " requires " + r.permission);
10006 }
10007 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10008 if (ib != null) {
10009 ret = ib.binder;
10010 }
10011 }
10012 }
10013
10014 return ret;
10015 }
10016
10017 public boolean stopServiceToken(ComponentName className, IBinder token,
10018 int startId) {
10019 synchronized(this) {
10020 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10021 + " " + token + " startId=" + startId);
10022 ServiceRecord r = findServiceLocked(className, token);
10023 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10024 synchronized (r.stats.getBatteryStats()) {
10025 r.stats.stopRunningLocked();
10026 r.startRequested = false;
10027 }
10028 final long origId = Binder.clearCallingIdentity();
10029 bringDownServiceLocked(r, false);
10030 Binder.restoreCallingIdentity(origId);
10031 return true;
10032 }
10033 }
10034 return false;
10035 }
10036
10037 public void setServiceForeground(ComponentName className, IBinder token,
10038 boolean isForeground) {
10039 synchronized(this) {
10040 ServiceRecord r = findServiceLocked(className, token);
10041 if (r != null) {
10042 if (r.isForeground != isForeground) {
10043 final long origId = Binder.clearCallingIdentity();
10044 r.isForeground = isForeground;
10045 if (r.app != null) {
10046 updateServiceForegroundLocked(r.app, true);
10047 }
10048 Binder.restoreCallingIdentity(origId);
10049 }
10050 }
10051 }
10052 }
10053
10054 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10055 boolean anyForeground = false;
10056 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10057 if (sr.isForeground) {
10058 anyForeground = true;
10059 break;
10060 }
10061 }
10062 if (anyForeground != proc.foregroundServices) {
10063 proc.foregroundServices = anyForeground;
10064 if (oomAdj) {
10065 updateOomAdjLocked();
10066 }
10067 }
10068 }
10069
10070 public int bindService(IApplicationThread caller, IBinder token,
10071 Intent service, String resolvedType,
10072 IServiceConnection connection, int flags) {
10073 // Refuse possible leaked file descriptors
10074 if (service != null && service.hasFileDescriptors() == true) {
10075 throw new IllegalArgumentException("File descriptors passed in Intent");
10076 }
10077
10078 synchronized(this) {
10079 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10080 + " type=" + resolvedType + " conn=" + connection.asBinder()
10081 + " flags=0x" + Integer.toHexString(flags));
10082 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10083 if (callerApp == null) {
10084 throw new SecurityException(
10085 "Unable to find app for caller " + caller
10086 + " (pid=" + Binder.getCallingPid()
10087 + ") when binding service " + service);
10088 }
10089
10090 HistoryRecord activity = null;
10091 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010092 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010093 if (aindex < 0) {
10094 Log.w(TAG, "Binding with unknown activity: " + token);
10095 return 0;
10096 }
10097 activity = (HistoryRecord)mHistory.get(aindex);
10098 }
10099
10100 ServiceLookupResult res =
10101 retrieveServiceLocked(service, resolvedType,
10102 Binder.getCallingPid(), Binder.getCallingUid());
10103 if (res == null) {
10104 return 0;
10105 }
10106 if (res.record == null) {
10107 return -1;
10108 }
10109 ServiceRecord s = res.record;
10110
10111 final long origId = Binder.clearCallingIdentity();
10112
10113 if (unscheduleServiceRestartLocked(s)) {
10114 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10115 + s.shortName);
10116 }
10117
10118 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10119 ConnectionRecord c = new ConnectionRecord(b, activity,
10120 connection, flags);
10121
10122 IBinder binder = connection.asBinder();
10123 s.connections.put(binder, c);
10124 b.connections.add(c);
10125 if (activity != null) {
10126 if (activity.connections == null) {
10127 activity.connections = new HashSet<ConnectionRecord>();
10128 }
10129 activity.connections.add(c);
10130 }
10131 b.client.connections.add(c);
10132 mServiceConnections.put(binder, c);
10133
10134 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10135 s.lastActivity = SystemClock.uptimeMillis();
10136 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10137 return 0;
10138 }
10139 }
10140
10141 if (s.app != null) {
10142 // This could have made the service more important.
10143 updateOomAdjLocked(s.app);
10144 }
10145
10146 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10147 + ": received=" + b.intent.received
10148 + " apps=" + b.intent.apps.size()
10149 + " doRebind=" + b.intent.doRebind);
10150
10151 if (s.app != null && b.intent.received) {
10152 // Service is already running, so we can immediately
10153 // publish the connection.
10154 try {
10155 c.conn.connected(s.name, b.intent.binder);
10156 } catch (Exception e) {
10157 Log.w(TAG, "Failure sending service " + s.shortName
10158 + " to connection " + c.conn.asBinder()
10159 + " (in " + c.binding.client.processName + ")", e);
10160 }
10161
10162 // If this is the first app connected back to this binding,
10163 // and the service had previously asked to be told when
10164 // rebound, then do so.
10165 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10166 requestServiceBindingLocked(s, b.intent, true);
10167 }
10168 } else if (!b.intent.requested) {
10169 requestServiceBindingLocked(s, b.intent, false);
10170 }
10171
10172 Binder.restoreCallingIdentity(origId);
10173 }
10174
10175 return 1;
10176 }
10177
10178 private void removeConnectionLocked(
10179 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10180 IBinder binder = c.conn.asBinder();
10181 AppBindRecord b = c.binding;
10182 ServiceRecord s = b.service;
10183 s.connections.remove(binder);
10184 b.connections.remove(c);
10185 if (c.activity != null && c.activity != skipAct) {
10186 if (c.activity.connections != null) {
10187 c.activity.connections.remove(c);
10188 }
10189 }
10190 if (b.client != skipApp) {
10191 b.client.connections.remove(c);
10192 }
10193 mServiceConnections.remove(binder);
10194
10195 if (b.connections.size() == 0) {
10196 b.intent.apps.remove(b.client);
10197 }
10198
10199 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10200 + ": shouldUnbind=" + b.intent.hasBound);
10201 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10202 && b.intent.hasBound) {
10203 try {
10204 bumpServiceExecutingLocked(s);
10205 updateOomAdjLocked(s.app);
10206 b.intent.hasBound = false;
10207 // Assume the client doesn't want to know about a rebind;
10208 // we will deal with that later if it asks for one.
10209 b.intent.doRebind = false;
10210 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10211 } catch (Exception e) {
10212 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10213 serviceDoneExecutingLocked(s, true);
10214 }
10215 }
10216
10217 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10218 bringDownServiceLocked(s, false);
10219 }
10220 }
10221
10222 public boolean unbindService(IServiceConnection connection) {
10223 synchronized (this) {
10224 IBinder binder = connection.asBinder();
10225 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10226 ConnectionRecord r = mServiceConnections.get(binder);
10227 if (r == null) {
10228 Log.w(TAG, "Unbind failed: could not find connection for "
10229 + connection.asBinder());
10230 return false;
10231 }
10232
10233 final long origId = Binder.clearCallingIdentity();
10234
10235 removeConnectionLocked(r, null, null);
10236
10237 if (r.binding.service.app != null) {
10238 // This could have made the service less important.
10239 updateOomAdjLocked(r.binding.service.app);
10240 }
10241
10242 Binder.restoreCallingIdentity(origId);
10243 }
10244
10245 return true;
10246 }
10247
10248 public void publishService(IBinder token, Intent intent, IBinder service) {
10249 // Refuse possible leaked file descriptors
10250 if (intent != null && intent.hasFileDescriptors() == true) {
10251 throw new IllegalArgumentException("File descriptors passed in Intent");
10252 }
10253
10254 synchronized(this) {
10255 if (!(token instanceof ServiceRecord)) {
10256 throw new IllegalArgumentException("Invalid service token");
10257 }
10258 ServiceRecord r = (ServiceRecord)token;
10259
10260 final long origId = Binder.clearCallingIdentity();
10261
10262 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10263 + " " + intent + ": " + service);
10264 if (r != null) {
10265 Intent.FilterComparison filter
10266 = new Intent.FilterComparison(intent);
10267 IntentBindRecord b = r.bindings.get(filter);
10268 if (b != null && !b.received) {
10269 b.binder = service;
10270 b.requested = true;
10271 b.received = true;
10272 if (r.connections.size() > 0) {
10273 Iterator<ConnectionRecord> it
10274 = r.connections.values().iterator();
10275 while (it.hasNext()) {
10276 ConnectionRecord c = it.next();
10277 if (!filter.equals(c.binding.intent.intent)) {
10278 if (DEBUG_SERVICE) Log.v(
10279 TAG, "Not publishing to: " + c);
10280 if (DEBUG_SERVICE) Log.v(
10281 TAG, "Bound intent: " + c.binding.intent.intent);
10282 if (DEBUG_SERVICE) Log.v(
10283 TAG, "Published intent: " + intent);
10284 continue;
10285 }
10286 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10287 try {
10288 c.conn.connected(r.name, service);
10289 } catch (Exception e) {
10290 Log.w(TAG, "Failure sending service " + r.name +
10291 " to connection " + c.conn.asBinder() +
10292 " (in " + c.binding.client.processName + ")", e);
10293 }
10294 }
10295 }
10296 }
10297
10298 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10299
10300 Binder.restoreCallingIdentity(origId);
10301 }
10302 }
10303 }
10304
10305 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10306 // Refuse possible leaked file descriptors
10307 if (intent != null && intent.hasFileDescriptors() == true) {
10308 throw new IllegalArgumentException("File descriptors passed in Intent");
10309 }
10310
10311 synchronized(this) {
10312 if (!(token instanceof ServiceRecord)) {
10313 throw new IllegalArgumentException("Invalid service token");
10314 }
10315 ServiceRecord r = (ServiceRecord)token;
10316
10317 final long origId = Binder.clearCallingIdentity();
10318
10319 if (r != null) {
10320 Intent.FilterComparison filter
10321 = new Intent.FilterComparison(intent);
10322 IntentBindRecord b = r.bindings.get(filter);
10323 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10324 + " at " + b + ": apps="
10325 + (b != null ? b.apps.size() : 0));
10326 if (b != null) {
10327 if (b.apps.size() > 0) {
10328 // Applications have already bound since the last
10329 // unbind, so just rebind right here.
10330 requestServiceBindingLocked(r, b, true);
10331 } else {
10332 // Note to tell the service the next time there is
10333 // a new client.
10334 b.doRebind = true;
10335 }
10336 }
10337
10338 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10339
10340 Binder.restoreCallingIdentity(origId);
10341 }
10342 }
10343 }
10344
10345 public void serviceDoneExecuting(IBinder token) {
10346 synchronized(this) {
10347 if (!(token instanceof ServiceRecord)) {
10348 throw new IllegalArgumentException("Invalid service token");
10349 }
10350 ServiceRecord r = (ServiceRecord)token;
10351 boolean inStopping = mStoppingServices.contains(token);
10352 if (r != null) {
10353 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10354 + ": nesting=" + r.executeNesting
10355 + ", inStopping=" + inStopping);
10356 if (r != token) {
10357 Log.w(TAG, "Done executing service " + r.name
10358 + " with incorrect token: given " + token
10359 + ", expected " + r);
10360 return;
10361 }
10362
10363 final long origId = Binder.clearCallingIdentity();
10364 serviceDoneExecutingLocked(r, inStopping);
10365 Binder.restoreCallingIdentity(origId);
10366 } else {
10367 Log.w(TAG, "Done executing unknown service " + r.name
10368 + " with token " + token);
10369 }
10370 }
10371 }
10372
10373 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10374 r.executeNesting--;
10375 if (r.executeNesting <= 0 && r.app != null) {
10376 r.app.executingServices.remove(r);
10377 if (r.app.executingServices.size() == 0) {
10378 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10379 }
10380 if (inStopping) {
10381 mStoppingServices.remove(r);
10382 }
10383 updateOomAdjLocked(r.app);
10384 }
10385 }
10386
10387 void serviceTimeout(ProcessRecord proc) {
10388 synchronized(this) {
10389 if (proc.executingServices.size() == 0 || proc.thread == null) {
10390 return;
10391 }
10392 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10393 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10394 ServiceRecord timeout = null;
10395 long nextTime = 0;
10396 while (it.hasNext()) {
10397 ServiceRecord sr = it.next();
10398 if (sr.executingStart < maxTime) {
10399 timeout = sr;
10400 break;
10401 }
10402 if (sr.executingStart > nextTime) {
10403 nextTime = sr.executingStart;
10404 }
10405 }
10406 if (timeout != null && mLRUProcesses.contains(proc)) {
10407 Log.w(TAG, "Timeout executing service: " + timeout);
10408 appNotRespondingLocked(proc, null, "Executing service "
10409 + timeout.name);
10410 } else {
10411 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10412 msg.obj = proc;
10413 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10414 }
10415 }
10416 }
10417
10418 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010419 // BACKUP AND RESTORE
10420 // =========================================================
10421
10422 // Cause the target app to be launched if necessary and its backup agent
10423 // instantiated. The backup agent will invoke backupAgentCreated() on the
10424 // activity manager to announce its creation.
10425 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10426 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10427 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10428
10429 synchronized(this) {
10430 // !!! TODO: currently no check here that we're already bound
10431 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10432 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10433 synchronized (stats) {
10434 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10435 }
10436
10437 BackupRecord r = new BackupRecord(ss, app, backupMode);
10438 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10439 // startProcessLocked() returns existing proc's record if it's already running
10440 ProcessRecord proc = startProcessLocked(app.processName, app,
10441 false, 0, "backup", hostingName);
10442 if (proc == null) {
10443 Log.e(TAG, "Unable to start backup agent process " + r);
10444 return false;
10445 }
10446
10447 r.app = proc;
10448 mBackupTarget = r;
10449 mBackupAppName = app.packageName;
10450
Christopher Tate6fa95972009-06-05 18:43:55 -070010451 // Try not to kill the process during backup
10452 updateOomAdjLocked(proc);
10453
Christopher Tate181fafa2009-05-14 11:12:14 -070010454 // If the process is already attached, schedule the creation of the backup agent now.
10455 // If it is not yet live, this will be done when it attaches to the framework.
10456 if (proc.thread != null) {
10457 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10458 try {
10459 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10460 } catch (RemoteException e) {
10461 // !!! TODO: notify the backup manager that we crashed, or rely on
10462 // death notices, or...?
10463 }
10464 } else {
10465 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10466 }
10467 // Invariants: at this point, the target app process exists and the application
10468 // is either already running or in the process of coming up. mBackupTarget and
10469 // mBackupAppName describe the app, so that when it binds back to the AM we
10470 // know that it's scheduled for a backup-agent operation.
10471 }
10472
10473 return true;
10474 }
10475
10476 // A backup agent has just come up
10477 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10478 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10479 + " = " + agent);
10480
10481 synchronized(this) {
10482 if (!agentPackageName.equals(mBackupAppName)) {
10483 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10484 return;
10485 }
10486
Christopher Tate043dadc2009-06-02 16:11:00 -070010487 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010488 try {
10489 IBackupManager bm = IBackupManager.Stub.asInterface(
10490 ServiceManager.getService(Context.BACKUP_SERVICE));
10491 bm.agentConnected(agentPackageName, agent);
10492 } catch (RemoteException e) {
10493 // can't happen; the backup manager service is local
10494 } catch (Exception e) {
10495 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10496 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010497 } finally {
10498 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010499 }
10500 }
10501 }
10502
10503 // done with this agent
10504 public void unbindBackupAgent(ApplicationInfo appInfo) {
10505 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10506
10507 synchronized(this) {
10508 if (!mBackupAppName.equals(appInfo.packageName)) {
10509 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10510 return;
10511 }
10512
Christopher Tate6fa95972009-06-05 18:43:55 -070010513 ProcessRecord proc = mBackupTarget.app;
10514 mBackupTarget = null;
10515 mBackupAppName = null;
10516
10517 // Not backing this app up any more; reset its OOM adjustment
10518 updateOomAdjLocked(proc);
10519
Christopher Tatec7b31e32009-06-10 15:49:30 -070010520 // If the app crashed during backup, 'thread' will be null here
10521 if (proc.thread != null) {
10522 try {
10523 proc.thread.scheduleDestroyBackupAgent(appInfo);
10524 } catch (Exception e) {
10525 Log.e(TAG, "Exception when unbinding backup agent:");
10526 e.printStackTrace();
10527 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010528 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010529 }
10530 }
10531 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010532 // BROADCASTS
10533 // =========================================================
10534
10535 private final List getStickies(String action, IntentFilter filter,
10536 List cur) {
10537 final ContentResolver resolver = mContext.getContentResolver();
10538 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10539 if (list == null) {
10540 return cur;
10541 }
10542 int N = list.size();
10543 for (int i=0; i<N; i++) {
10544 Intent intent = list.get(i);
10545 if (filter.match(resolver, intent, true, TAG) >= 0) {
10546 if (cur == null) {
10547 cur = new ArrayList<Intent>();
10548 }
10549 cur.add(intent);
10550 }
10551 }
10552 return cur;
10553 }
10554
10555 private final void scheduleBroadcastsLocked() {
10556 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10557 + mBroadcastsScheduled);
10558
10559 if (mBroadcastsScheduled) {
10560 return;
10561 }
10562 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10563 mBroadcastsScheduled = true;
10564 }
10565
10566 public Intent registerReceiver(IApplicationThread caller,
10567 IIntentReceiver receiver, IntentFilter filter, String permission) {
10568 synchronized(this) {
10569 ProcessRecord callerApp = null;
10570 if (caller != null) {
10571 callerApp = getRecordForAppLocked(caller);
10572 if (callerApp == null) {
10573 throw new SecurityException(
10574 "Unable to find app for caller " + caller
10575 + " (pid=" + Binder.getCallingPid()
10576 + ") when registering receiver " + receiver);
10577 }
10578 }
10579
10580 List allSticky = null;
10581
10582 // Look for any matching sticky broadcasts...
10583 Iterator actions = filter.actionsIterator();
10584 if (actions != null) {
10585 while (actions.hasNext()) {
10586 String action = (String)actions.next();
10587 allSticky = getStickies(action, filter, allSticky);
10588 }
10589 } else {
10590 allSticky = getStickies(null, filter, allSticky);
10591 }
10592
10593 // The first sticky in the list is returned directly back to
10594 // the client.
10595 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10596
10597 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10598 + ": " + sticky);
10599
10600 if (receiver == null) {
10601 return sticky;
10602 }
10603
10604 ReceiverList rl
10605 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10606 if (rl == null) {
10607 rl = new ReceiverList(this, callerApp,
10608 Binder.getCallingPid(),
10609 Binder.getCallingUid(), receiver);
10610 if (rl.app != null) {
10611 rl.app.receivers.add(rl);
10612 } else {
10613 try {
10614 receiver.asBinder().linkToDeath(rl, 0);
10615 } catch (RemoteException e) {
10616 return sticky;
10617 }
10618 rl.linkedToDeath = true;
10619 }
10620 mRegisteredReceivers.put(receiver.asBinder(), rl);
10621 }
10622 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10623 rl.add(bf);
10624 if (!bf.debugCheck()) {
10625 Log.w(TAG, "==> For Dynamic broadast");
10626 }
10627 mReceiverResolver.addFilter(bf);
10628
10629 // Enqueue broadcasts for all existing stickies that match
10630 // this filter.
10631 if (allSticky != null) {
10632 ArrayList receivers = new ArrayList();
10633 receivers.add(bf);
10634
10635 int N = allSticky.size();
10636 for (int i=0; i<N; i++) {
10637 Intent intent = (Intent)allSticky.get(i);
10638 BroadcastRecord r = new BroadcastRecord(intent, null,
10639 null, -1, -1, null, receivers, null, 0, null, null,
10640 false);
10641 if (mParallelBroadcasts.size() == 0) {
10642 scheduleBroadcastsLocked();
10643 }
10644 mParallelBroadcasts.add(r);
10645 }
10646 }
10647
10648 return sticky;
10649 }
10650 }
10651
10652 public void unregisterReceiver(IIntentReceiver receiver) {
10653 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10654
10655 boolean doNext = false;
10656
10657 synchronized(this) {
10658 ReceiverList rl
10659 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10660 if (rl != null) {
10661 if (rl.curBroadcast != null) {
10662 BroadcastRecord r = rl.curBroadcast;
10663 doNext = finishReceiverLocked(
10664 receiver.asBinder(), r.resultCode, r.resultData,
10665 r.resultExtras, r.resultAbort, true);
10666 }
10667
10668 if (rl.app != null) {
10669 rl.app.receivers.remove(rl);
10670 }
10671 removeReceiverLocked(rl);
10672 if (rl.linkedToDeath) {
10673 rl.linkedToDeath = false;
10674 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10675 }
10676 }
10677 }
10678
10679 if (!doNext) {
10680 return;
10681 }
10682
10683 final long origId = Binder.clearCallingIdentity();
10684 processNextBroadcast(false);
10685 trimApplications();
10686 Binder.restoreCallingIdentity(origId);
10687 }
10688
10689 void removeReceiverLocked(ReceiverList rl) {
10690 mRegisteredReceivers.remove(rl.receiver.asBinder());
10691 int N = rl.size();
10692 for (int i=0; i<N; i++) {
10693 mReceiverResolver.removeFilter(rl.get(i));
10694 }
10695 }
10696
10697 private final int broadcastIntentLocked(ProcessRecord callerApp,
10698 String callerPackage, Intent intent, String resolvedType,
10699 IIntentReceiver resultTo, int resultCode, String resultData,
10700 Bundle map, String requiredPermission,
10701 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10702 intent = new Intent(intent);
10703
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010704 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010705 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10706 + " ordered=" + ordered);
10707 if ((resultTo != null) && !ordered) {
10708 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10709 }
10710
10711 // Handle special intents: if this broadcast is from the package
10712 // manager about a package being removed, we need to remove all of
10713 // its activities from the history stack.
10714 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10715 intent.getAction());
10716 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10717 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10718 || uidRemoved) {
10719 if (checkComponentPermission(
10720 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10721 callingPid, callingUid, -1)
10722 == PackageManager.PERMISSION_GRANTED) {
10723 if (uidRemoved) {
10724 final Bundle intentExtras = intent.getExtras();
10725 final int uid = intentExtras != null
10726 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10727 if (uid >= 0) {
10728 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10729 synchronized (bs) {
10730 bs.removeUidStatsLocked(uid);
10731 }
10732 }
10733 } else {
10734 Uri data = intent.getData();
10735 String ssp;
10736 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10737 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10738 uninstallPackageLocked(ssp,
10739 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10740 }
10741 }
10742 }
10743 } else {
10744 String msg = "Permission Denial: " + intent.getAction()
10745 + " broadcast from " + callerPackage + " (pid=" + callingPid
10746 + ", uid=" + callingUid + ")"
10747 + " requires "
10748 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10749 Log.w(TAG, msg);
10750 throw new SecurityException(msg);
10751 }
10752 }
10753
10754 /*
10755 * If this is the time zone changed action, queue up a message that will reset the timezone
10756 * of all currently running processes. This message will get queued up before the broadcast
10757 * happens.
10758 */
10759 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10760 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10761 }
10762
10763 // Add to the sticky list if requested.
10764 if (sticky) {
10765 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10766 callingPid, callingUid)
10767 != PackageManager.PERMISSION_GRANTED) {
10768 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10769 + callingPid + ", uid=" + callingUid
10770 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10771 Log.w(TAG, msg);
10772 throw new SecurityException(msg);
10773 }
10774 if (requiredPermission != null) {
10775 Log.w(TAG, "Can't broadcast sticky intent " + intent
10776 + " and enforce permission " + requiredPermission);
10777 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10778 }
10779 if (intent.getComponent() != null) {
10780 throw new SecurityException(
10781 "Sticky broadcasts can't target a specific component");
10782 }
10783 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10784 if (list == null) {
10785 list = new ArrayList<Intent>();
10786 mStickyBroadcasts.put(intent.getAction(), list);
10787 }
10788 int N = list.size();
10789 int i;
10790 for (i=0; i<N; i++) {
10791 if (intent.filterEquals(list.get(i))) {
10792 // This sticky already exists, replace it.
10793 list.set(i, new Intent(intent));
10794 break;
10795 }
10796 }
10797 if (i >= N) {
10798 list.add(new Intent(intent));
10799 }
10800 }
10801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010802 // Figure out who all will receive this broadcast.
10803 List receivers = null;
10804 List<BroadcastFilter> registeredReceivers = null;
10805 try {
10806 if (intent.getComponent() != null) {
10807 // Broadcast is going to one specific receiver class...
10808 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010809 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010810 if (ai != null) {
10811 receivers = new ArrayList();
10812 ResolveInfo ri = new ResolveInfo();
10813 ri.activityInfo = ai;
10814 receivers.add(ri);
10815 }
10816 } else {
10817 // Need to resolve the intent to interested receivers...
10818 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10819 == 0) {
10820 receivers =
10821 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010822 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010823 }
Mihai Preda074edef2009-05-18 17:13:31 +020010824 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010825 }
10826 } catch (RemoteException ex) {
10827 // pm is in same process, this will never happen.
10828 }
10829
10830 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10831 if (!ordered && NR > 0) {
10832 // If we are not serializing this broadcast, then send the
10833 // registered receivers separately so they don't wait for the
10834 // components to be launched.
10835 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10836 callerPackage, callingPid, callingUid, requiredPermission,
10837 registeredReceivers, resultTo, resultCode, resultData, map,
10838 ordered);
10839 if (DEBUG_BROADCAST) Log.v(
10840 TAG, "Enqueueing parallel broadcast " + r
10841 + ": prev had " + mParallelBroadcasts.size());
10842 mParallelBroadcasts.add(r);
10843 scheduleBroadcastsLocked();
10844 registeredReceivers = null;
10845 NR = 0;
10846 }
10847
10848 // Merge into one list.
10849 int ir = 0;
10850 if (receivers != null) {
10851 // A special case for PACKAGE_ADDED: do not allow the package
10852 // being added to see this broadcast. This prevents them from
10853 // using this as a back door to get run as soon as they are
10854 // installed. Maybe in the future we want to have a special install
10855 // broadcast or such for apps, but we'd like to deliberately make
10856 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010857 boolean skip = false;
10858 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010859 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010860 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10861 skip = true;
10862 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10863 skip = true;
10864 }
10865 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010866 ? intent.getData().getSchemeSpecificPart()
10867 : null;
10868 if (skipPackage != null && receivers != null) {
10869 int NT = receivers.size();
10870 for (int it=0; it<NT; it++) {
10871 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10872 if (curt.activityInfo.packageName.equals(skipPackage)) {
10873 receivers.remove(it);
10874 it--;
10875 NT--;
10876 }
10877 }
10878 }
10879
10880 int NT = receivers != null ? receivers.size() : 0;
10881 int it = 0;
10882 ResolveInfo curt = null;
10883 BroadcastFilter curr = null;
10884 while (it < NT && ir < NR) {
10885 if (curt == null) {
10886 curt = (ResolveInfo)receivers.get(it);
10887 }
10888 if (curr == null) {
10889 curr = registeredReceivers.get(ir);
10890 }
10891 if (curr.getPriority() >= curt.priority) {
10892 // Insert this broadcast record into the final list.
10893 receivers.add(it, curr);
10894 ir++;
10895 curr = null;
10896 it++;
10897 NT++;
10898 } else {
10899 // Skip to the next ResolveInfo in the final list.
10900 it++;
10901 curt = null;
10902 }
10903 }
10904 }
10905 while (ir < NR) {
10906 if (receivers == null) {
10907 receivers = new ArrayList();
10908 }
10909 receivers.add(registeredReceivers.get(ir));
10910 ir++;
10911 }
10912
10913 if ((receivers != null && receivers.size() > 0)
10914 || resultTo != null) {
10915 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10916 callerPackage, callingPid, callingUid, requiredPermission,
10917 receivers, resultTo, resultCode, resultData, map, ordered);
10918 if (DEBUG_BROADCAST) Log.v(
10919 TAG, "Enqueueing ordered broadcast " + r
10920 + ": prev had " + mOrderedBroadcasts.size());
10921 if (DEBUG_BROADCAST) {
10922 int seq = r.intent.getIntExtra("seq", -1);
10923 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10924 }
10925 mOrderedBroadcasts.add(r);
10926 scheduleBroadcastsLocked();
10927 }
10928
10929 return BROADCAST_SUCCESS;
10930 }
10931
10932 public final int broadcastIntent(IApplicationThread caller,
10933 Intent intent, String resolvedType, IIntentReceiver resultTo,
10934 int resultCode, String resultData, Bundle map,
10935 String requiredPermission, boolean serialized, boolean sticky) {
10936 // Refuse possible leaked file descriptors
10937 if (intent != null && intent.hasFileDescriptors() == true) {
10938 throw new IllegalArgumentException("File descriptors passed in Intent");
10939 }
10940
10941 synchronized(this) {
10942 if (!mSystemReady) {
10943 // if the caller really truly claims to know what they're doing, go
10944 // ahead and allow the broadcast without launching any receivers
10945 int flags = intent.getFlags();
10946 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10947 intent = new Intent(intent);
10948 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10949 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10950 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10951 + " before boot completion");
10952 throw new IllegalStateException("Cannot broadcast before boot completed");
10953 }
10954 }
10955
10956 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10957 final int callingPid = Binder.getCallingPid();
10958 final int callingUid = Binder.getCallingUid();
10959 final long origId = Binder.clearCallingIdentity();
10960 int res = broadcastIntentLocked(callerApp,
10961 callerApp != null ? callerApp.info.packageName : null,
10962 intent, resolvedType, resultTo,
10963 resultCode, resultData, map, requiredPermission, serialized,
10964 sticky, callingPid, callingUid);
10965 Binder.restoreCallingIdentity(origId);
10966 return res;
10967 }
10968 }
10969
10970 int broadcastIntentInPackage(String packageName, int uid,
10971 Intent intent, String resolvedType, IIntentReceiver resultTo,
10972 int resultCode, String resultData, Bundle map,
10973 String requiredPermission, boolean serialized, boolean sticky) {
10974 synchronized(this) {
10975 final long origId = Binder.clearCallingIdentity();
10976 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10977 resultTo, resultCode, resultData, map, requiredPermission,
10978 serialized, sticky, -1, uid);
10979 Binder.restoreCallingIdentity(origId);
10980 return res;
10981 }
10982 }
10983
10984 public final void unbroadcastIntent(IApplicationThread caller,
10985 Intent intent) {
10986 // Refuse possible leaked file descriptors
10987 if (intent != null && intent.hasFileDescriptors() == true) {
10988 throw new IllegalArgumentException("File descriptors passed in Intent");
10989 }
10990
10991 synchronized(this) {
10992 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10993 != PackageManager.PERMISSION_GRANTED) {
10994 String msg = "Permission Denial: unbroadcastIntent() from pid="
10995 + Binder.getCallingPid()
10996 + ", uid=" + Binder.getCallingUid()
10997 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10998 Log.w(TAG, msg);
10999 throw new SecurityException(msg);
11000 }
11001 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11002 if (list != null) {
11003 int N = list.size();
11004 int i;
11005 for (i=0; i<N; i++) {
11006 if (intent.filterEquals(list.get(i))) {
11007 list.remove(i);
11008 break;
11009 }
11010 }
11011 }
11012 }
11013 }
11014
11015 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11016 String resultData, Bundle resultExtras, boolean resultAbort,
11017 boolean explicit) {
11018 if (mOrderedBroadcasts.size() == 0) {
11019 if (explicit) {
11020 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11021 }
11022 return false;
11023 }
11024 BroadcastRecord r = mOrderedBroadcasts.get(0);
11025 if (r.receiver == null) {
11026 if (explicit) {
11027 Log.w(TAG, "finishReceiver called but none active");
11028 }
11029 return false;
11030 }
11031 if (r.receiver != receiver) {
11032 Log.w(TAG, "finishReceiver called but active receiver is different");
11033 return false;
11034 }
11035 int state = r.state;
11036 r.state = r.IDLE;
11037 if (state == r.IDLE) {
11038 if (explicit) {
11039 Log.w(TAG, "finishReceiver called but state is IDLE");
11040 }
11041 }
11042 r.receiver = null;
11043 r.intent.setComponent(null);
11044 if (r.curApp != null) {
11045 r.curApp.curReceiver = null;
11046 }
11047 if (r.curFilter != null) {
11048 r.curFilter.receiverList.curBroadcast = null;
11049 }
11050 r.curFilter = null;
11051 r.curApp = null;
11052 r.curComponent = null;
11053 r.curReceiver = null;
11054 mPendingBroadcast = null;
11055
11056 r.resultCode = resultCode;
11057 r.resultData = resultData;
11058 r.resultExtras = resultExtras;
11059 r.resultAbort = resultAbort;
11060
11061 // We will process the next receiver right now if this is finishing
11062 // an app receiver (which is always asynchronous) or after we have
11063 // come back from calling a receiver.
11064 return state == BroadcastRecord.APP_RECEIVE
11065 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11066 }
11067
11068 public void finishReceiver(IBinder who, int resultCode, String resultData,
11069 Bundle resultExtras, boolean resultAbort) {
11070 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11071
11072 // Refuse possible leaked file descriptors
11073 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11074 throw new IllegalArgumentException("File descriptors passed in Bundle");
11075 }
11076
11077 boolean doNext;
11078
11079 final long origId = Binder.clearCallingIdentity();
11080
11081 synchronized(this) {
11082 doNext = finishReceiverLocked(
11083 who, resultCode, resultData, resultExtras, resultAbort, true);
11084 }
11085
11086 if (doNext) {
11087 processNextBroadcast(false);
11088 }
11089 trimApplications();
11090
11091 Binder.restoreCallingIdentity(origId);
11092 }
11093
11094 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11095 if (r.nextReceiver > 0) {
11096 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11097 if (curReceiver instanceof BroadcastFilter) {
11098 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11099 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11100 System.identityHashCode(r),
11101 r.intent.getAction(),
11102 r.nextReceiver - 1,
11103 System.identityHashCode(bf));
11104 } else {
11105 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11106 System.identityHashCode(r),
11107 r.intent.getAction(),
11108 r.nextReceiver - 1,
11109 ((ResolveInfo)curReceiver).toString());
11110 }
11111 } else {
11112 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11113 + r);
11114 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11115 System.identityHashCode(r),
11116 r.intent.getAction(),
11117 r.nextReceiver,
11118 "NONE");
11119 }
11120 }
11121
11122 private final void broadcastTimeout() {
11123 synchronized (this) {
11124 if (mOrderedBroadcasts.size() == 0) {
11125 return;
11126 }
11127 long now = SystemClock.uptimeMillis();
11128 BroadcastRecord r = mOrderedBroadcasts.get(0);
11129 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11130 if (DEBUG_BROADCAST) Log.v(TAG,
11131 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11132 + (r.startTime + BROADCAST_TIMEOUT));
11133 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11134 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11135 return;
11136 }
11137
11138 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11139 r.startTime = now;
11140 r.anrCount++;
11141
11142 // Current receiver has passed its expiration date.
11143 if (r.nextReceiver <= 0) {
11144 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11145 return;
11146 }
11147
11148 ProcessRecord app = null;
11149
11150 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11151 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11152 logBroadcastReceiverDiscard(r);
11153 if (curReceiver instanceof BroadcastFilter) {
11154 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11155 if (bf.receiverList.pid != 0
11156 && bf.receiverList.pid != MY_PID) {
11157 synchronized (this.mPidsSelfLocked) {
11158 app = this.mPidsSelfLocked.get(
11159 bf.receiverList.pid);
11160 }
11161 }
11162 } else {
11163 app = r.curApp;
11164 }
11165
11166 if (app != null) {
11167 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11168 }
11169
11170 if (mPendingBroadcast == r) {
11171 mPendingBroadcast = null;
11172 }
11173
11174 // Move on to the next receiver.
11175 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11176 r.resultExtras, r.resultAbort, true);
11177 scheduleBroadcastsLocked();
11178 }
11179 }
11180
11181 private final void processCurBroadcastLocked(BroadcastRecord r,
11182 ProcessRecord app) throws RemoteException {
11183 if (app.thread == null) {
11184 throw new RemoteException();
11185 }
11186 r.receiver = app.thread.asBinder();
11187 r.curApp = app;
11188 app.curReceiver = r;
11189 updateLRUListLocked(app, true);
11190
11191 // Tell the application to launch this receiver.
11192 r.intent.setComponent(r.curComponent);
11193
11194 boolean started = false;
11195 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011196 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011197 "Delivering to component " + r.curComponent
11198 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011199 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011200 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11201 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11202 started = true;
11203 } finally {
11204 if (!started) {
11205 r.receiver = null;
11206 r.curApp = null;
11207 app.curReceiver = null;
11208 }
11209 }
11210
11211 }
11212
11213 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11214 Intent intent, int resultCode, String data,
11215 Bundle extras, boolean ordered) throws RemoteException {
11216 if (app != null && app.thread != null) {
11217 // If we have an app thread, do the call through that so it is
11218 // correctly ordered with other one-way calls.
11219 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11220 data, extras, ordered);
11221 } else {
11222 receiver.performReceive(intent, resultCode, data, extras, ordered);
11223 }
11224 }
11225
11226 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11227 BroadcastFilter filter, boolean ordered) {
11228 boolean skip = false;
11229 if (filter.requiredPermission != null) {
11230 int perm = checkComponentPermission(filter.requiredPermission,
11231 r.callingPid, r.callingUid, -1);
11232 if (perm != PackageManager.PERMISSION_GRANTED) {
11233 Log.w(TAG, "Permission Denial: broadcasting "
11234 + r.intent.toString()
11235 + " from " + r.callerPackage + " (pid="
11236 + r.callingPid + ", uid=" + r.callingUid + ")"
11237 + " requires " + filter.requiredPermission
11238 + " due to registered receiver " + filter);
11239 skip = true;
11240 }
11241 }
11242 if (r.requiredPermission != null) {
11243 int perm = checkComponentPermission(r.requiredPermission,
11244 filter.receiverList.pid, filter.receiverList.uid, -1);
11245 if (perm != PackageManager.PERMISSION_GRANTED) {
11246 Log.w(TAG, "Permission Denial: receiving "
11247 + r.intent.toString()
11248 + " to " + filter.receiverList.app
11249 + " (pid=" + filter.receiverList.pid
11250 + ", uid=" + filter.receiverList.uid + ")"
11251 + " requires " + r.requiredPermission
11252 + " due to sender " + r.callerPackage
11253 + " (uid " + r.callingUid + ")");
11254 skip = true;
11255 }
11256 }
11257
11258 if (!skip) {
11259 // If this is not being sent as an ordered broadcast, then we
11260 // don't want to touch the fields that keep track of the current
11261 // state of ordered broadcasts.
11262 if (ordered) {
11263 r.receiver = filter.receiverList.receiver.asBinder();
11264 r.curFilter = filter;
11265 filter.receiverList.curBroadcast = r;
11266 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011267 if (filter.receiverList.app != null) {
11268 // Bump hosting application to no longer be in background
11269 // scheduling class. Note that we can't do that if there
11270 // isn't an app... but we can only be in that case for
11271 // things that directly call the IActivityManager API, which
11272 // are already core system stuff so don't matter for this.
11273 r.curApp = filter.receiverList.app;
11274 filter.receiverList.app.curReceiver = r;
11275 updateOomAdjLocked();
11276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011277 }
11278 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011279 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011280 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011281 Log.i(TAG, "Delivering to " + filter.receiverList.app
11282 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011283 }
11284 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11285 new Intent(r.intent), r.resultCode,
11286 r.resultData, r.resultExtras, r.ordered);
11287 if (ordered) {
11288 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11289 }
11290 } catch (RemoteException e) {
11291 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11292 if (ordered) {
11293 r.receiver = null;
11294 r.curFilter = null;
11295 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011296 if (filter.receiverList.app != null) {
11297 filter.receiverList.app.curReceiver = null;
11298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011299 }
11300 }
11301 }
11302 }
11303
11304 private final void processNextBroadcast(boolean fromMsg) {
11305 synchronized(this) {
11306 BroadcastRecord r;
11307
11308 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11309 + mParallelBroadcasts.size() + " broadcasts, "
11310 + mOrderedBroadcasts.size() + " serialized broadcasts");
11311
11312 updateCpuStats();
11313
11314 if (fromMsg) {
11315 mBroadcastsScheduled = false;
11316 }
11317
11318 // First, deliver any non-serialized broadcasts right away.
11319 while (mParallelBroadcasts.size() > 0) {
11320 r = mParallelBroadcasts.remove(0);
11321 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011322 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11323 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011324 for (int i=0; i<N; i++) {
11325 Object target = r.receivers.get(i);
11326 if (DEBUG_BROADCAST) Log.v(TAG,
11327 "Delivering non-serialized to registered "
11328 + target + ": " + r);
11329 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11330 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011331 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11332 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011333 }
11334
11335 // Now take care of the next serialized one...
11336
11337 // If we are waiting for a process to come up to handle the next
11338 // broadcast, then do nothing at this point. Just in case, we
11339 // check that the process we're waiting for still exists.
11340 if (mPendingBroadcast != null) {
11341 Log.i(TAG, "processNextBroadcast: waiting for "
11342 + mPendingBroadcast.curApp);
11343
11344 boolean isDead;
11345 synchronized (mPidsSelfLocked) {
11346 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11347 }
11348 if (!isDead) {
11349 // It's still alive, so keep waiting
11350 return;
11351 } else {
11352 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11353 + " died before responding to broadcast");
11354 mPendingBroadcast = null;
11355 }
11356 }
11357
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011358 boolean looped = false;
11359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011360 do {
11361 if (mOrderedBroadcasts.size() == 0) {
11362 // No more broadcasts pending, so all done!
11363 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011364 if (looped) {
11365 // If we had finished the last ordered broadcast, then
11366 // make sure all processes have correct oom and sched
11367 // adjustments.
11368 updateOomAdjLocked();
11369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011370 return;
11371 }
11372 r = mOrderedBroadcasts.get(0);
11373 boolean forceReceive = false;
11374
11375 // Ensure that even if something goes awry with the timeout
11376 // detection, we catch "hung" broadcasts here, discard them,
11377 // and continue to make progress.
11378 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11379 long now = SystemClock.uptimeMillis();
11380 if (r.dispatchTime > 0) {
11381 if ((numReceivers > 0) &&
11382 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11383 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11384 + " now=" + now
11385 + " dispatchTime=" + r.dispatchTime
11386 + " startTime=" + r.startTime
11387 + " intent=" + r.intent
11388 + " numReceivers=" + numReceivers
11389 + " nextReceiver=" + r.nextReceiver
11390 + " state=" + r.state);
11391 broadcastTimeout(); // forcibly finish this broadcast
11392 forceReceive = true;
11393 r.state = BroadcastRecord.IDLE;
11394 }
11395 }
11396
11397 if (r.state != BroadcastRecord.IDLE) {
11398 if (DEBUG_BROADCAST) Log.d(TAG,
11399 "processNextBroadcast() called when not idle (state="
11400 + r.state + ")");
11401 return;
11402 }
11403
11404 if (r.receivers == null || r.nextReceiver >= numReceivers
11405 || r.resultAbort || forceReceive) {
11406 // No more receivers for this broadcast! Send the final
11407 // result if requested...
11408 if (r.resultTo != null) {
11409 try {
11410 if (DEBUG_BROADCAST) {
11411 int seq = r.intent.getIntExtra("seq", -1);
11412 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11413 + " seq=" + seq + " app=" + r.callerApp);
11414 }
11415 performReceive(r.callerApp, r.resultTo,
11416 new Intent(r.intent), r.resultCode,
11417 r.resultData, r.resultExtras, false);
11418 } catch (RemoteException e) {
11419 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11420 }
11421 }
11422
11423 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11424 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11425
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011426 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11427 + r);
11428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011429 // ... and on to the next...
11430 mOrderedBroadcasts.remove(0);
11431 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011432 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011433 continue;
11434 }
11435 } while (r == null);
11436
11437 // Get the next receiver...
11438 int recIdx = r.nextReceiver++;
11439
11440 // Keep track of when this receiver started, and make sure there
11441 // is a timeout message pending to kill it if need be.
11442 r.startTime = SystemClock.uptimeMillis();
11443 if (recIdx == 0) {
11444 r.dispatchTime = r.startTime;
11445
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011446 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11447 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011448 if (DEBUG_BROADCAST) Log.v(TAG,
11449 "Submitting BROADCAST_TIMEOUT_MSG for "
11450 + (r.startTime + BROADCAST_TIMEOUT));
11451 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11452 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11453 }
11454
11455 Object nextReceiver = r.receivers.get(recIdx);
11456 if (nextReceiver instanceof BroadcastFilter) {
11457 // Simple case: this is a registered receiver who gets
11458 // a direct call.
11459 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11460 if (DEBUG_BROADCAST) Log.v(TAG,
11461 "Delivering serialized to registered "
11462 + filter + ": " + r);
11463 deliverToRegisteredReceiver(r, filter, r.ordered);
11464 if (r.receiver == null || !r.ordered) {
11465 // The receiver has already finished, so schedule to
11466 // process the next one.
11467 r.state = BroadcastRecord.IDLE;
11468 scheduleBroadcastsLocked();
11469 }
11470 return;
11471 }
11472
11473 // Hard case: need to instantiate the receiver, possibly
11474 // starting its application process to host it.
11475
11476 ResolveInfo info =
11477 (ResolveInfo)nextReceiver;
11478
11479 boolean skip = false;
11480 int perm = checkComponentPermission(info.activityInfo.permission,
11481 r.callingPid, r.callingUid,
11482 info.activityInfo.exported
11483 ? -1 : info.activityInfo.applicationInfo.uid);
11484 if (perm != PackageManager.PERMISSION_GRANTED) {
11485 Log.w(TAG, "Permission Denial: broadcasting "
11486 + r.intent.toString()
11487 + " from " + r.callerPackage + " (pid=" + r.callingPid
11488 + ", uid=" + r.callingUid + ")"
11489 + " requires " + info.activityInfo.permission
11490 + " due to receiver " + info.activityInfo.packageName
11491 + "/" + info.activityInfo.name);
11492 skip = true;
11493 }
11494 if (r.callingUid != Process.SYSTEM_UID &&
11495 r.requiredPermission != null) {
11496 try {
11497 perm = ActivityThread.getPackageManager().
11498 checkPermission(r.requiredPermission,
11499 info.activityInfo.applicationInfo.packageName);
11500 } catch (RemoteException e) {
11501 perm = PackageManager.PERMISSION_DENIED;
11502 }
11503 if (perm != PackageManager.PERMISSION_GRANTED) {
11504 Log.w(TAG, "Permission Denial: receiving "
11505 + r.intent + " to "
11506 + info.activityInfo.applicationInfo.packageName
11507 + " requires " + r.requiredPermission
11508 + " due to sender " + r.callerPackage
11509 + " (uid " + r.callingUid + ")");
11510 skip = true;
11511 }
11512 }
11513 if (r.curApp != null && r.curApp.crashing) {
11514 // If the target process is crashing, just skip it.
11515 skip = true;
11516 }
11517
11518 if (skip) {
11519 r.receiver = null;
11520 r.curFilter = null;
11521 r.state = BroadcastRecord.IDLE;
11522 scheduleBroadcastsLocked();
11523 return;
11524 }
11525
11526 r.state = BroadcastRecord.APP_RECEIVE;
11527 String targetProcess = info.activityInfo.processName;
11528 r.curComponent = new ComponentName(
11529 info.activityInfo.applicationInfo.packageName,
11530 info.activityInfo.name);
11531 r.curReceiver = info.activityInfo;
11532
11533 // Is this receiver's application already running?
11534 ProcessRecord app = getProcessRecordLocked(targetProcess,
11535 info.activityInfo.applicationInfo.uid);
11536 if (app != null && app.thread != null) {
11537 try {
11538 processCurBroadcastLocked(r, app);
11539 return;
11540 } catch (RemoteException e) {
11541 Log.w(TAG, "Exception when sending broadcast to "
11542 + r.curComponent, e);
11543 }
11544
11545 // If a dead object exception was thrown -- fall through to
11546 // restart the application.
11547 }
11548
11549 // Not running -- get it started, and enqueue this history record
11550 // to be executed when the app comes up.
11551 if ((r.curApp=startProcessLocked(targetProcess,
11552 info.activityInfo.applicationInfo, true,
11553 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11554 "broadcast", r.curComponent)) == null) {
11555 // Ah, this recipient is unavailable. Finish it if necessary,
11556 // and mark the broadcast record as ready for the next.
11557 Log.w(TAG, "Unable to launch app "
11558 + info.activityInfo.applicationInfo.packageName + "/"
11559 + info.activityInfo.applicationInfo.uid + " for broadcast "
11560 + r.intent + ": process is bad");
11561 logBroadcastReceiverDiscard(r);
11562 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11563 r.resultExtras, r.resultAbort, true);
11564 scheduleBroadcastsLocked();
11565 r.state = BroadcastRecord.IDLE;
11566 return;
11567 }
11568
11569 mPendingBroadcast = r;
11570 }
11571 }
11572
11573 // =========================================================
11574 // INSTRUMENTATION
11575 // =========================================================
11576
11577 public boolean startInstrumentation(ComponentName className,
11578 String profileFile, int flags, Bundle arguments,
11579 IInstrumentationWatcher watcher) {
11580 // Refuse possible leaked file descriptors
11581 if (arguments != null && arguments.hasFileDescriptors()) {
11582 throw new IllegalArgumentException("File descriptors passed in Bundle");
11583 }
11584
11585 synchronized(this) {
11586 InstrumentationInfo ii = null;
11587 ApplicationInfo ai = null;
11588 try {
11589 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011590 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011591 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011592 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011593 } catch (PackageManager.NameNotFoundException e) {
11594 }
11595 if (ii == null) {
11596 reportStartInstrumentationFailure(watcher, className,
11597 "Unable to find instrumentation info for: " + className);
11598 return false;
11599 }
11600 if (ai == null) {
11601 reportStartInstrumentationFailure(watcher, className,
11602 "Unable to find instrumentation target package: " + ii.targetPackage);
11603 return false;
11604 }
11605
11606 int match = mContext.getPackageManager().checkSignatures(
11607 ii.targetPackage, ii.packageName);
11608 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11609 String msg = "Permission Denial: starting instrumentation "
11610 + className + " from pid="
11611 + Binder.getCallingPid()
11612 + ", uid=" + Binder.getCallingPid()
11613 + " not allowed because package " + ii.packageName
11614 + " does not have a signature matching the target "
11615 + ii.targetPackage;
11616 reportStartInstrumentationFailure(watcher, className, msg);
11617 throw new SecurityException(msg);
11618 }
11619
11620 final long origId = Binder.clearCallingIdentity();
11621 uninstallPackageLocked(ii.targetPackage, -1, true);
11622 ProcessRecord app = addAppLocked(ai);
11623 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011624 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011625 app.instrumentationProfileFile = profileFile;
11626 app.instrumentationArguments = arguments;
11627 app.instrumentationWatcher = watcher;
11628 app.instrumentationResultClass = className;
11629 Binder.restoreCallingIdentity(origId);
11630 }
11631
11632 return true;
11633 }
11634
11635 /**
11636 * Report errors that occur while attempting to start Instrumentation. Always writes the
11637 * error to the logs, but if somebody is watching, send the report there too. This enables
11638 * the "am" command to report errors with more information.
11639 *
11640 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11641 * @param cn The component name of the instrumentation.
11642 * @param report The error report.
11643 */
11644 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11645 ComponentName cn, String report) {
11646 Log.w(TAG, report);
11647 try {
11648 if (watcher != null) {
11649 Bundle results = new Bundle();
11650 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11651 results.putString("Error", report);
11652 watcher.instrumentationStatus(cn, -1, results);
11653 }
11654 } catch (RemoteException e) {
11655 Log.w(TAG, e);
11656 }
11657 }
11658
11659 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11660 if (app.instrumentationWatcher != null) {
11661 try {
11662 // NOTE: IInstrumentationWatcher *must* be oneway here
11663 app.instrumentationWatcher.instrumentationFinished(
11664 app.instrumentationClass,
11665 resultCode,
11666 results);
11667 } catch (RemoteException e) {
11668 }
11669 }
11670 app.instrumentationWatcher = null;
11671 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011672 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011673 app.instrumentationProfileFile = null;
11674 app.instrumentationArguments = null;
11675
11676 uninstallPackageLocked(app.processName, -1, false);
11677 }
11678
11679 public void finishInstrumentation(IApplicationThread target,
11680 int resultCode, Bundle results) {
11681 // Refuse possible leaked file descriptors
11682 if (results != null && results.hasFileDescriptors()) {
11683 throw new IllegalArgumentException("File descriptors passed in Intent");
11684 }
11685
11686 synchronized(this) {
11687 ProcessRecord app = getRecordForAppLocked(target);
11688 if (app == null) {
11689 Log.w(TAG, "finishInstrumentation: no app for " + target);
11690 return;
11691 }
11692 final long origId = Binder.clearCallingIdentity();
11693 finishInstrumentationLocked(app, resultCode, results);
11694 Binder.restoreCallingIdentity(origId);
11695 }
11696 }
11697
11698 // =========================================================
11699 // CONFIGURATION
11700 // =========================================================
11701
11702 public ConfigurationInfo getDeviceConfigurationInfo() {
11703 ConfigurationInfo config = new ConfigurationInfo();
11704 synchronized (this) {
11705 config.reqTouchScreen = mConfiguration.touchscreen;
11706 config.reqKeyboardType = mConfiguration.keyboard;
11707 config.reqNavigation = mConfiguration.navigation;
11708 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11709 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11710 }
11711 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11712 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11713 }
11714 }
11715 return config;
11716 }
11717
11718 public Configuration getConfiguration() {
11719 Configuration ci;
11720 synchronized(this) {
11721 ci = new Configuration(mConfiguration);
11722 }
11723 return ci;
11724 }
11725
11726 public void updateConfiguration(Configuration values) {
11727 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11728 "updateConfiguration()");
11729
11730 synchronized(this) {
11731 if (values == null && mWindowManager != null) {
11732 // sentinel: fetch the current configuration from the window manager
11733 values = mWindowManager.computeNewConfiguration();
11734 }
11735
11736 final long origId = Binder.clearCallingIdentity();
11737 updateConfigurationLocked(values, null);
11738 Binder.restoreCallingIdentity(origId);
11739 }
11740 }
11741
11742 /**
11743 * Do either or both things: (1) change the current configuration, and (2)
11744 * make sure the given activity is running with the (now) current
11745 * configuration. Returns true if the activity has been left running, or
11746 * false if <var>starting</var> is being destroyed to match the new
11747 * configuration.
11748 */
11749 public boolean updateConfigurationLocked(Configuration values,
11750 HistoryRecord starting) {
11751 int changes = 0;
11752
11753 boolean kept = true;
11754
11755 if (values != null) {
11756 Configuration newConfig = new Configuration(mConfiguration);
11757 changes = newConfig.updateFrom(values);
11758 if (changes != 0) {
11759 if (DEBUG_SWITCH) {
11760 Log.i(TAG, "Updating configuration to: " + values);
11761 }
11762
11763 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11764
11765 if (values.locale != null) {
11766 saveLocaleLocked(values.locale,
11767 !values.locale.equals(mConfiguration.locale),
11768 values.userSetLocale);
11769 }
11770
11771 mConfiguration = newConfig;
11772
11773 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11774 msg.obj = new Configuration(mConfiguration);
11775 mHandler.sendMessage(msg);
11776
11777 final int N = mLRUProcesses.size();
11778 for (int i=0; i<N; i++) {
11779 ProcessRecord app = mLRUProcesses.get(i);
11780 try {
11781 if (app.thread != null) {
11782 app.thread.scheduleConfigurationChanged(mConfiguration);
11783 }
11784 } catch (Exception e) {
11785 }
11786 }
11787 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11788 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11789 null, false, false, MY_PID, Process.SYSTEM_UID);
11790 }
11791 }
11792
11793 if (changes != 0 && starting == null) {
11794 // If the configuration changed, and the caller is not already
11795 // in the process of starting an activity, then find the top
11796 // activity to check if its configuration needs to change.
11797 starting = topRunningActivityLocked(null);
11798 }
11799
11800 if (starting != null) {
11801 kept = ensureActivityConfigurationLocked(starting, changes);
11802 if (kept) {
11803 // If this didn't result in the starting activity being
11804 // destroyed, then we need to make sure at this point that all
11805 // other activities are made visible.
11806 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11807 + ", ensuring others are correct.");
11808 ensureActivitiesVisibleLocked(starting, changes);
11809 }
11810 }
11811
11812 return kept;
11813 }
11814
11815 private final boolean relaunchActivityLocked(HistoryRecord r,
11816 int changes, boolean andResume) {
11817 List<ResultInfo> results = null;
11818 List<Intent> newIntents = null;
11819 if (andResume) {
11820 results = r.results;
11821 newIntents = r.newIntents;
11822 }
11823 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11824 + " with results=" + results + " newIntents=" + newIntents
11825 + " andResume=" + andResume);
11826 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11827 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11828 r.task.taskId, r.shortComponentName);
11829
11830 r.startFreezingScreenLocked(r.app, 0);
11831
11832 try {
11833 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11834 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11835 changes, !andResume);
11836 // Note: don't need to call pauseIfSleepingLocked() here, because
11837 // the caller will only pass in 'andResume' if this activity is
11838 // currently resumed, which implies we aren't sleeping.
11839 } catch (RemoteException e) {
11840 return false;
11841 }
11842
11843 if (andResume) {
11844 r.results = null;
11845 r.newIntents = null;
11846 }
11847
11848 return true;
11849 }
11850
11851 /**
11852 * Make sure the given activity matches the current configuration. Returns
11853 * false if the activity had to be destroyed. Returns true if the
11854 * configuration is the same, or the activity will remain running as-is
11855 * for whatever reason. Ensures the HistoryRecord is updated with the
11856 * correct configuration and all other bookkeeping is handled.
11857 */
11858 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11859 int globalChanges) {
11860 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11861
11862 // Short circuit: if the two configurations are the exact same
11863 // object (the common case), then there is nothing to do.
11864 Configuration newConfig = mConfiguration;
11865 if (r.configuration == newConfig) {
11866 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11867 return true;
11868 }
11869
11870 // We don't worry about activities that are finishing.
11871 if (r.finishing) {
11872 if (DEBUG_SWITCH) Log.i(TAG,
11873 "Configuration doesn't matter in finishing " + r);
11874 r.stopFreezingScreenLocked(false);
11875 return true;
11876 }
11877
11878 // Okay we now are going to make this activity have the new config.
11879 // But then we need to figure out how it needs to deal with that.
11880 Configuration oldConfig = r.configuration;
11881 r.configuration = newConfig;
11882
11883 // If the activity isn't currently running, just leave the new
11884 // configuration and it will pick that up next time it starts.
11885 if (r.app == null || r.app.thread == null) {
11886 if (DEBUG_SWITCH) Log.i(TAG,
11887 "Configuration doesn't matter not running " + r);
11888 r.stopFreezingScreenLocked(false);
11889 return true;
11890 }
11891
11892 // If the activity isn't persistent, there is a chance we will
11893 // need to restart it.
11894 if (!r.persistent) {
11895
11896 // Figure out what has changed between the two configurations.
11897 int changes = oldConfig.diff(newConfig);
11898 if (DEBUG_SWITCH) {
11899 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11900 + Integer.toHexString(changes) + ", handles=0x"
11901 + Integer.toHexString(r.info.configChanges));
11902 }
11903 if ((changes&(~r.info.configChanges)) != 0) {
11904 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11905 r.configChangeFlags |= changes;
11906 r.startFreezingScreenLocked(r.app, globalChanges);
11907 if (r.app == null || r.app.thread == null) {
11908 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11909 destroyActivityLocked(r, true);
11910 } else if (r.state == ActivityState.PAUSING) {
11911 // A little annoying: we are waiting for this activity to
11912 // finish pausing. Let's not do anything now, but just
11913 // flag that it needs to be restarted when done pausing.
11914 r.configDestroy = true;
11915 return true;
11916 } else if (r.state == ActivityState.RESUMED) {
11917 // Try to optimize this case: the configuration is changing
11918 // and we need to restart the top, resumed activity.
11919 // Instead of doing the normal handshaking, just say
11920 // "restart!".
11921 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11922 relaunchActivityLocked(r, r.configChangeFlags, true);
11923 r.configChangeFlags = 0;
11924 } else {
11925 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11926 relaunchActivityLocked(r, r.configChangeFlags, false);
11927 r.configChangeFlags = 0;
11928 }
11929
11930 // All done... tell the caller we weren't able to keep this
11931 // activity around.
11932 return false;
11933 }
11934 }
11935
11936 // Default case: the activity can handle this new configuration, so
11937 // hand it over. Note that we don't need to give it the new
11938 // configuration, since we always send configuration changes to all
11939 // process when they happen so it can just use whatever configuration
11940 // it last got.
11941 if (r.app != null && r.app.thread != null) {
11942 try {
11943 r.app.thread.scheduleActivityConfigurationChanged(r);
11944 } catch (RemoteException e) {
11945 // If process died, whatever.
11946 }
11947 }
11948 r.stopFreezingScreenLocked(false);
11949
11950 return true;
11951 }
11952
11953 /**
11954 * Save the locale. You must be inside a synchronized (this) block.
11955 */
11956 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11957 if(isDiff) {
11958 SystemProperties.set("user.language", l.getLanguage());
11959 SystemProperties.set("user.region", l.getCountry());
11960 }
11961
11962 if(isPersist) {
11963 SystemProperties.set("persist.sys.language", l.getLanguage());
11964 SystemProperties.set("persist.sys.country", l.getCountry());
11965 SystemProperties.set("persist.sys.localevar", l.getVariant());
11966 }
11967 }
11968
11969 // =========================================================
11970 // LIFETIME MANAGEMENT
11971 // =========================================================
11972
11973 private final int computeOomAdjLocked(
11974 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11975 if (mAdjSeq == app.adjSeq) {
11976 // This adjustment has already been computed.
11977 return app.curAdj;
11978 }
11979
11980 if (app.thread == null) {
11981 app.adjSeq = mAdjSeq;
11982 return (app.curAdj=EMPTY_APP_ADJ);
11983 }
11984
11985 app.isForeground = false;
11986
The Android Open Source Project4df24232009-03-05 14:34:35 -080011987 // Determine the importance of the process, starting with most
11988 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011989 int adj;
11990 int N;
11991 if (app == TOP_APP || app.instrumentationClass != null
11992 || app.persistentActivities > 0) {
11993 // The last app on the list is the foreground app.
11994 adj = FOREGROUND_APP_ADJ;
11995 app.isForeground = true;
11996 } else if (app.curReceiver != null ||
11997 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11998 // An app that is currently receiving a broadcast also
11999 // counts as being in the foreground.
12000 adj = FOREGROUND_APP_ADJ;
12001 } else if (app.executingServices.size() > 0) {
12002 // An app that is currently executing a service callback also
12003 // counts as being in the foreground.
12004 adj = FOREGROUND_APP_ADJ;
12005 } else if (app.foregroundServices || app.forcingToForeground != null) {
12006 // The user is aware of this app, so make it visible.
12007 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012008 } else if (app == mHomeProcess) {
12009 // This process is hosting what we currently consider to be the
12010 // home app, so we don't want to let it go into the background.
12011 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012012 } else if ((N=app.activities.size()) != 0) {
12013 // This app is in the background with paused activities.
12014 adj = hiddenAdj;
12015 for (int j=0; j<N; j++) {
12016 if (((HistoryRecord)app.activities.get(j)).visible) {
12017 // This app has a visible activity!
12018 adj = VISIBLE_APP_ADJ;
12019 break;
12020 }
12021 }
12022 } else {
12023 // A very not-needed process.
12024 adj = EMPTY_APP_ADJ;
12025 }
12026
The Android Open Source Project4df24232009-03-05 14:34:35 -080012027 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012028 // there are applications dependent on our services or providers, but
12029 // this gives us a baseline and makes sure we don't get into an
12030 // infinite recursion.
12031 app.adjSeq = mAdjSeq;
12032 app.curRawAdj = adj;
12033 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12034
Christopher Tate6fa95972009-06-05 18:43:55 -070012035 if (mBackupTarget != null && app == mBackupTarget.app) {
12036 // If possible we want to avoid killing apps while they're being backed up
12037 if (adj > BACKUP_APP_ADJ) {
12038 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12039 adj = BACKUP_APP_ADJ;
12040 }
12041 }
12042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012043 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12044 // If this process has active services running in it, we would
12045 // like to avoid killing it unless it would prevent the current
12046 // application from running.
12047 if (adj > hiddenAdj) {
12048 adj = hiddenAdj;
12049 }
12050 final long now = SystemClock.uptimeMillis();
12051 // This process is more important if the top activity is
12052 // bound to the service.
12053 Iterator jt = app.services.iterator();
12054 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12055 ServiceRecord s = (ServiceRecord)jt.next();
12056 if (s.startRequested) {
12057 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12058 // This service has seen some activity within
12059 // recent memory, so we will keep its process ahead
12060 // of the background processes.
12061 if (adj > SECONDARY_SERVER_ADJ) {
12062 adj = SECONDARY_SERVER_ADJ;
12063 }
12064 } else {
12065 // This service has been inactive for too long, just
12066 // put it with the rest of the background processes.
12067 if (adj > hiddenAdj) {
12068 adj = hiddenAdj;
12069 }
12070 }
12071 }
12072 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12073 Iterator<ConnectionRecord> kt
12074 = s.connections.values().iterator();
12075 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12076 // XXX should compute this based on the max of
12077 // all connected clients.
12078 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012079 if (cr.binding.client == app) {
12080 // Binding to ourself is not interesting.
12081 continue;
12082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012083 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12084 ProcessRecord client = cr.binding.client;
12085 int myHiddenAdj = hiddenAdj;
12086 if (myHiddenAdj > client.hiddenAdj) {
12087 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12088 myHiddenAdj = client.hiddenAdj;
12089 } else {
12090 myHiddenAdj = VISIBLE_APP_ADJ;
12091 }
12092 }
12093 int clientAdj = computeOomAdjLocked(
12094 client, myHiddenAdj, TOP_APP);
12095 if (adj > clientAdj) {
12096 adj = clientAdj > VISIBLE_APP_ADJ
12097 ? clientAdj : VISIBLE_APP_ADJ;
12098 }
12099 }
12100 HistoryRecord a = cr.activity;
12101 //if (a != null) {
12102 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12103 //}
12104 if (a != null && adj > FOREGROUND_APP_ADJ &&
12105 (a.state == ActivityState.RESUMED
12106 || a.state == ActivityState.PAUSING)) {
12107 adj = FOREGROUND_APP_ADJ;
12108 }
12109 }
12110 }
12111 }
12112 }
12113
12114 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12115 // If this process has published any content providers, then
12116 // its adjustment makes it at least as important as any of the
12117 // processes using those providers, and no less important than
12118 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12119 if (adj > CONTENT_PROVIDER_ADJ) {
12120 adj = CONTENT_PROVIDER_ADJ;
12121 }
12122 Iterator jt = app.pubProviders.values().iterator();
12123 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12124 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12125 if (cpr.clients.size() != 0) {
12126 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12127 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12128 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012129 if (client == app) {
12130 // Being our own client is not interesting.
12131 continue;
12132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012133 int myHiddenAdj = hiddenAdj;
12134 if (myHiddenAdj > client.hiddenAdj) {
12135 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12136 myHiddenAdj = client.hiddenAdj;
12137 } else {
12138 myHiddenAdj = FOREGROUND_APP_ADJ;
12139 }
12140 }
12141 int clientAdj = computeOomAdjLocked(
12142 client, myHiddenAdj, TOP_APP);
12143 if (adj > clientAdj) {
12144 adj = clientAdj > FOREGROUND_APP_ADJ
12145 ? clientAdj : FOREGROUND_APP_ADJ;
12146 }
12147 }
12148 }
12149 // If the provider has external (non-framework) process
12150 // dependencies, ensure that its adjustment is at least
12151 // FOREGROUND_APP_ADJ.
12152 if (cpr.externals != 0) {
12153 if (adj > FOREGROUND_APP_ADJ) {
12154 adj = FOREGROUND_APP_ADJ;
12155 }
12156 }
12157 }
12158 }
12159
12160 app.curRawAdj = adj;
12161
12162 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12163 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12164 if (adj > app.maxAdj) {
12165 adj = app.maxAdj;
12166 }
12167
12168 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012169 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12170 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12171 : Process.THREAD_GROUP_DEFAULT;
12172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012173 return adj;
12174 }
12175
12176 /**
12177 * Ask a given process to GC right now.
12178 */
12179 final void performAppGcLocked(ProcessRecord app) {
12180 try {
12181 app.lastRequestedGc = SystemClock.uptimeMillis();
12182 if (app.thread != null) {
12183 app.thread.processInBackground();
12184 }
12185 } catch (Exception e) {
12186 // whatever.
12187 }
12188 }
12189
12190 /**
12191 * Returns true if things are idle enough to perform GCs.
12192 */
12193 private final boolean canGcNow() {
12194 return mParallelBroadcasts.size() == 0
12195 && mOrderedBroadcasts.size() == 0
12196 && (mSleeping || (mResumedActivity != null &&
12197 mResumedActivity.idle));
12198 }
12199
12200 /**
12201 * Perform GCs on all processes that are waiting for it, but only
12202 * if things are idle.
12203 */
12204 final void performAppGcsLocked() {
12205 final int N = mProcessesToGc.size();
12206 if (N <= 0) {
12207 return;
12208 }
12209 if (canGcNow()) {
12210 while (mProcessesToGc.size() > 0) {
12211 ProcessRecord proc = mProcessesToGc.remove(0);
12212 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12213 // To avoid spamming the system, we will GC processes one
12214 // at a time, waiting a few seconds between each.
12215 performAppGcLocked(proc);
12216 scheduleAppGcsLocked();
12217 return;
12218 }
12219 }
12220 }
12221 }
12222
12223 /**
12224 * If all looks good, perform GCs on all processes waiting for them.
12225 */
12226 final void performAppGcsIfAppropriateLocked() {
12227 if (canGcNow()) {
12228 performAppGcsLocked();
12229 return;
12230 }
12231 // Still not idle, wait some more.
12232 scheduleAppGcsLocked();
12233 }
12234
12235 /**
12236 * Schedule the execution of all pending app GCs.
12237 */
12238 final void scheduleAppGcsLocked() {
12239 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12240 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12241 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12242 }
12243
12244 /**
12245 * Set up to ask a process to GC itself. This will either do it
12246 * immediately, or put it on the list of processes to gc the next
12247 * time things are idle.
12248 */
12249 final void scheduleAppGcLocked(ProcessRecord app) {
12250 long now = SystemClock.uptimeMillis();
12251 if ((app.lastRequestedGc+5000) > now) {
12252 return;
12253 }
12254 if (!mProcessesToGc.contains(app)) {
12255 mProcessesToGc.add(app);
12256 scheduleAppGcsLocked();
12257 }
12258 }
12259
12260 private final boolean updateOomAdjLocked(
12261 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12262 app.hiddenAdj = hiddenAdj;
12263
12264 if (app.thread == null) {
12265 return true;
12266 }
12267
12268 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12269
12270 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12271 //Thread priority adjustment is disabled out to see
12272 //how the kernel scheduler performs.
12273 if (false) {
12274 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12275 app.setIsForeground = app.isForeground;
12276 if (app.pid != MY_PID) {
12277 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12278 + " to " + (app.isForeground
12279 ? Process.THREAD_PRIORITY_FOREGROUND
12280 : Process.THREAD_PRIORITY_DEFAULT));
12281 try {
12282 Process.setThreadPriority(app.pid, app.isForeground
12283 ? Process.THREAD_PRIORITY_FOREGROUND
12284 : Process.THREAD_PRIORITY_DEFAULT);
12285 } catch (RuntimeException e) {
12286 Log.w(TAG, "Exception trying to set priority of application thread "
12287 + app.pid, e);
12288 }
12289 }
12290 }
12291 }
12292 if (app.pid != 0 && app.pid != MY_PID) {
12293 if (app.curRawAdj != app.setRawAdj) {
12294 if (app.curRawAdj > FOREGROUND_APP_ADJ
12295 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12296 // If this app is transitioning from foreground to
12297 // non-foreground, have it do a gc.
12298 scheduleAppGcLocked(app);
12299 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12300 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12301 // Likewise do a gc when an app is moving in to the
12302 // background (such as a service stopping).
12303 scheduleAppGcLocked(app);
12304 }
12305 app.setRawAdj = app.curRawAdj;
12306 }
12307 if (adj != app.setAdj) {
12308 if (Process.setOomAdj(app.pid, adj)) {
12309 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12310 TAG, "Set app " + app.processName +
12311 " oom adj to " + adj);
12312 app.setAdj = adj;
12313 } else {
12314 return false;
12315 }
12316 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012317 if (app.setSchedGroup != app.curSchedGroup) {
12318 app.setSchedGroup = app.curSchedGroup;
12319 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12320 "Setting process group of " + app.processName
12321 + " to " + app.curSchedGroup);
12322 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012323 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012324 try {
12325 Process.setProcessGroup(app.pid, app.curSchedGroup);
12326 } catch (Exception e) {
12327 Log.w(TAG, "Failed setting process group of " + app.pid
12328 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012329 e.printStackTrace();
12330 } finally {
12331 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012332 }
12333 }
12334 if (false) {
12335 if (app.thread != null) {
12336 try {
12337 app.thread.setSchedulingGroup(app.curSchedGroup);
12338 } catch (RemoteException e) {
12339 }
12340 }
12341 }
12342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012343 }
12344
12345 return true;
12346 }
12347
12348 private final HistoryRecord resumedAppLocked() {
12349 HistoryRecord resumedActivity = mResumedActivity;
12350 if (resumedActivity == null || resumedActivity.app == null) {
12351 resumedActivity = mPausingActivity;
12352 if (resumedActivity == null || resumedActivity.app == null) {
12353 resumedActivity = topRunningActivityLocked(null);
12354 }
12355 }
12356 return resumedActivity;
12357 }
12358
12359 private final boolean updateOomAdjLocked(ProcessRecord app) {
12360 final HistoryRecord TOP_ACT = resumedAppLocked();
12361 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12362 int curAdj = app.curAdj;
12363 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12364 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12365
12366 mAdjSeq++;
12367
12368 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12369 if (res) {
12370 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12371 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12372 if (nowHidden != wasHidden) {
12373 // Changed to/from hidden state, so apps after it in the LRU
12374 // list may also be changed.
12375 updateOomAdjLocked();
12376 }
12377 }
12378 return res;
12379 }
12380
12381 private final boolean updateOomAdjLocked() {
12382 boolean didOomAdj = true;
12383 final HistoryRecord TOP_ACT = resumedAppLocked();
12384 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12385
12386 if (false) {
12387 RuntimeException e = new RuntimeException();
12388 e.fillInStackTrace();
12389 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12390 }
12391
12392 mAdjSeq++;
12393
12394 // First try updating the OOM adjustment for each of the
12395 // application processes based on their current state.
12396 int i = mLRUProcesses.size();
12397 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12398 while (i > 0) {
12399 i--;
12400 ProcessRecord app = mLRUProcesses.get(i);
12401 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12402 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12403 && app.curAdj == curHiddenAdj) {
12404 curHiddenAdj++;
12405 }
12406 } else {
12407 didOomAdj = false;
12408 }
12409 }
12410
12411 // todo: for now pretend like OOM ADJ didn't work, because things
12412 // aren't behaving as expected on Linux -- it's not killing processes.
12413 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12414 }
12415
12416 private final void trimApplications() {
12417 synchronized (this) {
12418 int i;
12419
12420 // First remove any unused application processes whose package
12421 // has been removed.
12422 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12423 final ProcessRecord app = mRemovedProcesses.get(i);
12424 if (app.activities.size() == 0
12425 && app.curReceiver == null && app.services.size() == 0) {
12426 Log.i(
12427 TAG, "Exiting empty application process "
12428 + app.processName + " ("
12429 + (app.thread != null ? app.thread.asBinder() : null)
12430 + ")\n");
12431 if (app.pid > 0 && app.pid != MY_PID) {
12432 Process.killProcess(app.pid);
12433 } else {
12434 try {
12435 app.thread.scheduleExit();
12436 } catch (Exception e) {
12437 // Ignore exceptions.
12438 }
12439 }
12440 cleanUpApplicationRecordLocked(app, false, -1);
12441 mRemovedProcesses.remove(i);
12442
12443 if (app.persistent) {
12444 if (app.persistent) {
12445 addAppLocked(app.info);
12446 }
12447 }
12448 }
12449 }
12450
12451 // Now try updating the OOM adjustment for each of the
12452 // application processes based on their current state.
12453 // If the setOomAdj() API is not supported, then go with our
12454 // back-up plan...
12455 if (!updateOomAdjLocked()) {
12456
12457 // Count how many processes are running services.
12458 int numServiceProcs = 0;
12459 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12460 final ProcessRecord app = mLRUProcesses.get(i);
12461
12462 if (app.persistent || app.services.size() != 0
12463 || app.curReceiver != null
12464 || app.persistentActivities > 0) {
12465 // Don't count processes holding services against our
12466 // maximum process count.
12467 if (localLOGV) Log.v(
12468 TAG, "Not trimming app " + app + " with services: "
12469 + app.services);
12470 numServiceProcs++;
12471 }
12472 }
12473
12474 int curMaxProcs = mProcessLimit;
12475 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12476 if (mAlwaysFinishActivities) {
12477 curMaxProcs = 1;
12478 }
12479 curMaxProcs += numServiceProcs;
12480
12481 // Quit as many processes as we can to get down to the desired
12482 // process count. First remove any processes that no longer
12483 // have activites running in them.
12484 for ( i=0;
12485 i<mLRUProcesses.size()
12486 && mLRUProcesses.size() > curMaxProcs;
12487 i++) {
12488 final ProcessRecord app = mLRUProcesses.get(i);
12489 // Quit an application only if it is not currently
12490 // running any activities.
12491 if (!app.persistent && app.activities.size() == 0
12492 && app.curReceiver == null && app.services.size() == 0) {
12493 Log.i(
12494 TAG, "Exiting empty application process "
12495 + app.processName + " ("
12496 + (app.thread != null ? app.thread.asBinder() : null)
12497 + ")\n");
12498 if (app.pid > 0 && app.pid != MY_PID) {
12499 Process.killProcess(app.pid);
12500 } else {
12501 try {
12502 app.thread.scheduleExit();
12503 } catch (Exception e) {
12504 // Ignore exceptions.
12505 }
12506 }
12507 // todo: For now we assume the application is not buggy
12508 // or evil, and will quit as a result of our request.
12509 // Eventually we need to drive this off of the death
12510 // notification, and kill the process if it takes too long.
12511 cleanUpApplicationRecordLocked(app, false, i);
12512 i--;
12513 }
12514 }
12515
12516 // If we still have too many processes, now from the least
12517 // recently used process we start finishing activities.
12518 if (Config.LOGV) Log.v(
12519 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12520 " of " + curMaxProcs + " processes");
12521 for ( i=0;
12522 i<mLRUProcesses.size()
12523 && mLRUProcesses.size() > curMaxProcs;
12524 i++) {
12525 final ProcessRecord app = mLRUProcesses.get(i);
12526 // Quit the application only if we have a state saved for
12527 // all of its activities.
12528 boolean canQuit = !app.persistent && app.curReceiver == null
12529 && app.services.size() == 0
12530 && app.persistentActivities == 0;
12531 int NUMA = app.activities.size();
12532 int j;
12533 if (Config.LOGV) Log.v(
12534 TAG, "Looking to quit " + app.processName);
12535 for (j=0; j<NUMA && canQuit; j++) {
12536 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12537 if (Config.LOGV) Log.v(
12538 TAG, " " + r.intent.getComponent().flattenToShortString()
12539 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12540 canQuit = (r.haveState || !r.stateNotNeeded)
12541 && !r.visible && r.stopped;
12542 }
12543 if (canQuit) {
12544 // Finish all of the activities, and then the app itself.
12545 for (j=0; j<NUMA; j++) {
12546 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12547 if (!r.finishing) {
12548 destroyActivityLocked(r, false);
12549 }
12550 r.resultTo = null;
12551 }
12552 Log.i(TAG, "Exiting application process "
12553 + app.processName + " ("
12554 + (app.thread != null ? app.thread.asBinder() : null)
12555 + ")\n");
12556 if (app.pid > 0 && app.pid != MY_PID) {
12557 Process.killProcess(app.pid);
12558 } else {
12559 try {
12560 app.thread.scheduleExit();
12561 } catch (Exception e) {
12562 // Ignore exceptions.
12563 }
12564 }
12565 // todo: For now we assume the application is not buggy
12566 // or evil, and will quit as a result of our request.
12567 // Eventually we need to drive this off of the death
12568 // notification, and kill the process if it takes too long.
12569 cleanUpApplicationRecordLocked(app, false, i);
12570 i--;
12571 //dump();
12572 }
12573 }
12574
12575 }
12576
12577 int curMaxActivities = MAX_ACTIVITIES;
12578 if (mAlwaysFinishActivities) {
12579 curMaxActivities = 1;
12580 }
12581
12582 // Finally, if there are too many activities now running, try to
12583 // finish as many as we can to get back down to the limit.
12584 for ( i=0;
12585 i<mLRUActivities.size()
12586 && mLRUActivities.size() > curMaxActivities;
12587 i++) {
12588 final HistoryRecord r
12589 = (HistoryRecord)mLRUActivities.get(i);
12590
12591 // We can finish this one if we have its icicle saved and
12592 // it is not persistent.
12593 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12594 && r.stopped && !r.persistent && !r.finishing) {
12595 final int origSize = mLRUActivities.size();
12596 destroyActivityLocked(r, true);
12597
12598 // This will remove it from the LRU list, so keep
12599 // our index at the same value. Note that this check to
12600 // see if the size changes is just paranoia -- if
12601 // something unexpected happens, we don't want to end up
12602 // in an infinite loop.
12603 if (origSize > mLRUActivities.size()) {
12604 i--;
12605 }
12606 }
12607 }
12608 }
12609 }
12610
12611 /** This method sends the specified signal to each of the persistent apps */
12612 public void signalPersistentProcesses(int sig) throws RemoteException {
12613 if (sig != Process.SIGNAL_USR1) {
12614 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12615 }
12616
12617 synchronized (this) {
12618 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12619 != PackageManager.PERMISSION_GRANTED) {
12620 throw new SecurityException("Requires permission "
12621 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12622 }
12623
12624 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12625 ProcessRecord r = mLRUProcesses.get(i);
12626 if (r.thread != null && r.persistent) {
12627 Process.sendSignal(r.pid, sig);
12628 }
12629 }
12630 }
12631 }
12632
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012633 public boolean profileControl(String process, boolean start,
12634 String path) throws RemoteException {
12635
12636 synchronized (this) {
12637 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12638 // its own permission.
12639 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12640 != PackageManager.PERMISSION_GRANTED) {
12641 throw new SecurityException("Requires permission "
12642 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12643 }
12644
12645 ProcessRecord proc = null;
12646 try {
12647 int pid = Integer.parseInt(process);
12648 synchronized (mPidsSelfLocked) {
12649 proc = mPidsSelfLocked.get(pid);
12650 }
12651 } catch (NumberFormatException e) {
12652 }
12653
12654 if (proc == null) {
12655 HashMap<String, SparseArray<ProcessRecord>> all
12656 = mProcessNames.getMap();
12657 SparseArray<ProcessRecord> procs = all.get(process);
12658 if (procs != null && procs.size() > 0) {
12659 proc = procs.valueAt(0);
12660 }
12661 }
12662
12663 if (proc == null || proc.thread == null) {
12664 throw new IllegalArgumentException("Unknown process: " + process);
12665 }
12666
12667 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12668 if (isSecure) {
12669 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12670 throw new SecurityException("Process not debuggable: " + proc);
12671 }
12672 }
12673
12674 try {
12675 proc.thread.profilerControl(start, path);
12676 return true;
12677 } catch (RemoteException e) {
12678 throw new IllegalStateException("Process disappeared");
12679 }
12680 }
12681 }
12682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012683 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12684 public void monitor() {
12685 synchronized (this) { }
12686 }
12687}