blob: 16bb29db267e5555894b838c10ae771e7cd979f4 [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
318 // Corresponding memory levels for above adjustments.
319 final int EMPTY_APP_MEM;
320 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800321 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700322 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 final int SECONDARY_SERVER_MEM;
324 final int VISIBLE_APP_MEM;
325 final int FOREGROUND_APP_MEM;
326
327 final int MY_PID;
328
329 static final String[] EMPTY_STRING_ARRAY = new String[0];
330
331 enum ActivityState {
332 INITIALIZING,
333 RESUMED,
334 PAUSING,
335 PAUSED,
336 STOPPING,
337 STOPPED,
338 FINISHING,
339 DESTROYING,
340 DESTROYED
341 }
342
343 /**
344 * The back history of all previous (and possibly still
345 * running) activities. It contains HistoryRecord objects.
346 */
347 final ArrayList mHistory = new ArrayList();
348
349 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700350 * Description of a request to start a new activity, which has been held
351 * due to app switches being disabled.
352 */
353 class PendingActivityLaunch {
354 HistoryRecord r;
355 HistoryRecord sourceRecord;
356 Uri[] grantedUriPermissions;
357 int grantedMode;
358 boolean onlyIfNeeded;
359 }
360
361 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
362 = new ArrayList<PendingActivityLaunch>();
363
364 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 * List of all active broadcasts that are to be executed immediately
366 * (without waiting for another broadcast to finish). Currently this only
367 * contains broadcasts to registered receivers, to avoid spinning up
368 * a bunch of processes to execute IntentReceiver components.
369 */
370 final ArrayList<BroadcastRecord> mParallelBroadcasts
371 = new ArrayList<BroadcastRecord>();
372
373 /**
374 * List of all active broadcasts that are to be executed one at a time.
375 * The object at the top of the list is the currently activity broadcasts;
376 * those after it are waiting for the top to finish..
377 */
378 final ArrayList<BroadcastRecord> mOrderedBroadcasts
379 = new ArrayList<BroadcastRecord>();
380
381 /**
382 * Set when we current have a BROADCAST_INTENT_MSG in flight.
383 */
384 boolean mBroadcastsScheduled = false;
385
386 /**
387 * Set to indicate whether to issue an onUserLeaving callback when a
388 * newly launched activity is being brought in front of us.
389 */
390 boolean mUserLeaving = false;
391
392 /**
393 * When we are in the process of pausing an activity, before starting the
394 * next one, this variable holds the activity that is currently being paused.
395 */
396 HistoryRecord mPausingActivity = null;
397
398 /**
399 * Current activity that is resumed, or null if there is none.
400 */
401 HistoryRecord mResumedActivity = null;
402
403 /**
404 * Activity we have told the window manager to have key focus.
405 */
406 HistoryRecord mFocusedActivity = null;
407
408 /**
409 * This is the last activity that we put into the paused state. This is
410 * used to determine if we need to do an activity transition while sleeping,
411 * when we normally hold the top activity paused.
412 */
413 HistoryRecord mLastPausedActivity = null;
414
415 /**
416 * List of activities that are waiting for a new activity
417 * to become visible before completing whatever operation they are
418 * supposed to do.
419 */
420 final ArrayList mWaitingVisibleActivities = new ArrayList();
421
422 /**
423 * List of activities that are ready to be stopped, but waiting
424 * for the next activity to settle down before doing so. It contains
425 * HistoryRecord objects.
426 */
427 final ArrayList<HistoryRecord> mStoppingActivities
428 = new ArrayList<HistoryRecord>();
429
430 /**
431 * List of intents that were used to start the most recent tasks.
432 */
433 final ArrayList<TaskRecord> mRecentTasks
434 = new ArrayList<TaskRecord>();
435
436 /**
437 * List of activities that are ready to be finished, but waiting
438 * for the previous activity to settle down before doing so. It contains
439 * HistoryRecord objects.
440 */
441 final ArrayList mFinishingActivities = new ArrayList();
442
443 /**
444 * All of the applications we currently have running organized by name.
445 * The keys are strings of the application package name (as
446 * returned by the package manager), and the keys are ApplicationRecord
447 * objects.
448 */
449 final ProcessMap<ProcessRecord> mProcessNames
450 = new ProcessMap<ProcessRecord>();
451
452 /**
453 * The last time that various processes have crashed.
454 */
455 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
456
457 /**
458 * Set of applications that we consider to be bad, and will reject
459 * incoming broadcasts from (which the user has no control over).
460 * Processes are added to this set when they have crashed twice within
461 * a minimum amount of time; they are removed from it when they are
462 * later restarted (hopefully due to some user action). The value is the
463 * time it was added to the list.
464 */
465 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
466
467 /**
468 * All of the processes we currently have running organized by pid.
469 * The keys are the pid running the application.
470 *
471 * <p>NOTE: This object is protected by its own lock, NOT the global
472 * activity manager lock!
473 */
474 final SparseArray<ProcessRecord> mPidsSelfLocked
475 = new SparseArray<ProcessRecord>();
476
477 /**
478 * All of the processes that have been forced to be foreground. The key
479 * is the pid of the caller who requested it (we hold a death
480 * link on it).
481 */
482 abstract class ForegroundToken implements IBinder.DeathRecipient {
483 int pid;
484 IBinder token;
485 }
486 final SparseArray<ForegroundToken> mForegroundProcesses
487 = new SparseArray<ForegroundToken>();
488
489 /**
490 * List of records for processes that someone had tried to start before the
491 * system was ready. We don't start them at that point, but ensure they
492 * are started by the time booting is complete.
493 */
494 final ArrayList<ProcessRecord> mProcessesOnHold
495 = new ArrayList<ProcessRecord>();
496
497 /**
498 * List of records for processes that we have started and are waiting
499 * for them to call back. This is really only needed when running in
500 * single processes mode, in which case we do not have a unique pid for
501 * each process.
502 */
503 final ArrayList<ProcessRecord> mStartingProcesses
504 = new ArrayList<ProcessRecord>();
505
506 /**
507 * List of persistent applications that are in the process
508 * of being started.
509 */
510 final ArrayList<ProcessRecord> mPersistentStartingProcesses
511 = new ArrayList<ProcessRecord>();
512
513 /**
514 * Processes that are being forcibly torn down.
515 */
516 final ArrayList<ProcessRecord> mRemovedProcesses
517 = new ArrayList<ProcessRecord>();
518
519 /**
520 * List of running applications, sorted by recent usage.
521 * The first entry in the list is the least recently used.
522 * It contains ApplicationRecord objects. This list does NOT include
523 * any persistent application records (since we never want to exit them).
524 */
525 final ArrayList<ProcessRecord> mLRUProcesses
526 = new ArrayList<ProcessRecord>();
527
528 /**
529 * List of processes that should gc as soon as things are idle.
530 */
531 final ArrayList<ProcessRecord> mProcessesToGc
532 = new ArrayList<ProcessRecord>();
533
534 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800535 * This is the process holding what we currently consider to be
536 * the "home" activity.
537 */
538 private ProcessRecord mHomeProcess;
539
540 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 * List of running activities, sorted by recent usage.
542 * The first entry in the list is the least recently used.
543 * It contains HistoryRecord objects.
544 */
545 private final ArrayList mLRUActivities = new ArrayList();
546
547 /**
548 * Set of PendingResultRecord objects that are currently active.
549 */
550 final HashSet mPendingResultRecords = new HashSet();
551
552 /**
553 * Set of IntentSenderRecord objects that are currently active.
554 */
555 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
556 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
557
558 /**
559 * Intent broadcast that we have tried to start, but are
560 * waiting for its application's process to be created. We only
561 * need one (instead of a list) because we always process broadcasts
562 * one at a time, so no others can be started while waiting for this
563 * one.
564 */
565 BroadcastRecord mPendingBroadcast = null;
566
567 /**
568 * Keeps track of all IIntentReceivers that have been registered for
569 * broadcasts. Hash keys are the receiver IBinder, hash value is
570 * a ReceiverList.
571 */
572 final HashMap mRegisteredReceivers = new HashMap();
573
574 /**
575 * Resolver for broadcast intents to registered receivers.
576 * Holds BroadcastFilter (subclass of IntentFilter).
577 */
578 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
579 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
580 @Override
581 protected boolean allowFilterResult(
582 BroadcastFilter filter, List<BroadcastFilter> dest) {
583 IBinder target = filter.receiverList.receiver.asBinder();
584 for (int i=dest.size()-1; i>=0; i--) {
585 if (dest.get(i).receiverList.receiver.asBinder() == target) {
586 return false;
587 }
588 }
589 return true;
590 }
591 };
592
593 /**
594 * State of all active sticky broadcasts. Keys are the action of the
595 * sticky Intent, values are an ArrayList of all broadcasted intents with
596 * that action (which should usually be one).
597 */
598 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
599 new HashMap<String, ArrayList<Intent>>();
600
601 /**
602 * All currently running services.
603 */
604 final HashMap<ComponentName, ServiceRecord> mServices =
605 new HashMap<ComponentName, ServiceRecord>();
606
607 /**
608 * All currently running services indexed by the Intent used to start them.
609 */
610 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
611 new HashMap<Intent.FilterComparison, ServiceRecord>();
612
613 /**
614 * All currently bound service connections. Keys are the IBinder of
615 * the client's IServiceConnection.
616 */
617 final HashMap<IBinder, ConnectionRecord> mServiceConnections
618 = new HashMap<IBinder, ConnectionRecord>();
619
620 /**
621 * List of services that we have been asked to start,
622 * but haven't yet been able to. It is used to hold start requests
623 * while waiting for their corresponding application thread to get
624 * going.
625 */
626 final ArrayList<ServiceRecord> mPendingServices
627 = new ArrayList<ServiceRecord>();
628
629 /**
630 * List of services that are scheduled to restart following a crash.
631 */
632 final ArrayList<ServiceRecord> mRestartingServices
633 = new ArrayList<ServiceRecord>();
634
635 /**
636 * List of services that are in the process of being stopped.
637 */
638 final ArrayList<ServiceRecord> mStoppingServices
639 = new ArrayList<ServiceRecord>();
640
641 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700642 * Backup/restore process management
643 */
644 String mBackupAppName = null;
645 BackupRecord mBackupTarget = null;
646
647 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 * List of PendingThumbnailsRecord objects of clients who are still
649 * waiting to receive all of the thumbnails for a task.
650 */
651 final ArrayList mPendingThumbnails = new ArrayList();
652
653 /**
654 * List of HistoryRecord objects that have been finished and must
655 * still report back to a pending thumbnail receiver.
656 */
657 final ArrayList mCancelledThumbnails = new ArrayList();
658
659 /**
660 * All of the currently running global content providers. Keys are a
661 * string containing the provider name and values are a
662 * ContentProviderRecord object containing the data about it. Note
663 * that a single provider may be published under multiple names, so
664 * there may be multiple entries here for a single one in mProvidersByClass.
665 */
666 final HashMap mProvidersByName = new HashMap();
667
668 /**
669 * All of the currently running global content providers. Keys are a
670 * string containing the provider's implementation class and values are a
671 * ContentProviderRecord object containing the data about it.
672 */
673 final HashMap mProvidersByClass = new HashMap();
674
675 /**
676 * List of content providers who have clients waiting for them. The
677 * application is currently being launched and the provider will be
678 * removed from this list once it is published.
679 */
680 final ArrayList mLaunchingProviders = new ArrayList();
681
682 /**
683 * Global set of specific Uri permissions that have been granted.
684 */
685 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
686 = new SparseArray<HashMap<Uri, UriPermission>>();
687
688 /**
689 * Thread-local storage used to carry caller permissions over through
690 * indirect content-provider access.
691 * @see #ActivityManagerService.openContentUri()
692 */
693 private class Identity {
694 public int pid;
695 public int uid;
696
697 Identity(int _pid, int _uid) {
698 pid = _pid;
699 uid = _uid;
700 }
701 }
702 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
703
704 /**
705 * All information we have collected about the runtime performance of
706 * any user id that can impact battery performance.
707 */
708 final BatteryStatsService mBatteryStatsService;
709
710 /**
711 * information about component usage
712 */
713 final UsageStatsService mUsageStatsService;
714
715 /**
716 * Current configuration information. HistoryRecord objects are given
717 * a reference to this object to indicate which configuration they are
718 * currently running in, so this object must be kept immutable.
719 */
720 Configuration mConfiguration = new Configuration();
721
722 /**
723 * List of initialization arguments to pass to all processes when binding applications to them.
724 * For example, references to the commonly used services.
725 */
726 HashMap<String, IBinder> mAppBindArgs;
727
728 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700729 * Temporary to avoid allocations. Protected by main lock.
730 */
731 final StringBuilder mStringBuilder = new StringBuilder(256);
732
733 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 * Used to control how we initialize the service.
735 */
736 boolean mStartRunning = false;
737 ComponentName mTopComponent;
738 String mTopAction;
739 String mTopData;
740 boolean mSystemReady = false;
741 boolean mBooting = false;
742
743 Context mContext;
744
745 int mFactoryTest;
746
747 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700748 * The time at which we will allow normal application switches again,
749 * after a call to {@link #stopAppSwitches()}.
750 */
751 long mAppSwitchesAllowedTime;
752
753 /**
754 * This is set to true after the first switch after mAppSwitchesAllowedTime
755 * is set; any switches after that will clear the time.
756 */
757 boolean mDidAppSwitch;
758
759 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 * Set while we are wanting to sleep, to prevent any
761 * activities from being started/resumed.
762 */
763 boolean mSleeping = false;
764
765 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700766 * Set if we are shutting down the system, similar to sleeping.
767 */
768 boolean mShuttingDown = false;
769
770 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 * Set when the system is going to sleep, until we have
772 * successfully paused the current activity and released our wake lock.
773 * At that point the system is allowed to actually sleep.
774 */
775 PowerManager.WakeLock mGoingToSleep;
776
777 /**
778 * We don't want to allow the device to go to sleep while in the process
779 * of launching an activity. This is primarily to allow alarm intent
780 * receivers to launch an activity and get that to run before the device
781 * goes back to sleep.
782 */
783 PowerManager.WakeLock mLaunchingActivity;
784
785 /**
786 * Task identifier that activities are currently being started
787 * in. Incremented each time a new task is created.
788 * todo: Replace this with a TokenSpace class that generates non-repeating
789 * integers that won't wrap.
790 */
791 int mCurTask = 1;
792
793 /**
794 * Current sequence id for oom_adj computation traversal.
795 */
796 int mAdjSeq = 0;
797
798 /**
799 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
800 * is set, indicating the user wants processes started in such a way
801 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
802 * running in each process (thus no pre-initialized process, etc).
803 */
804 boolean mSimpleProcessManagement = false;
805
806 /**
807 * System monitoring: number of processes that died since the last
808 * N procs were started.
809 */
810 int[] mProcDeaths = new int[20];
811
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700812 /**
813 * This is set if we had to do a delayed dexopt of an app before launching
814 * it, to increasing the ANR timeouts in that case.
815 */
816 boolean mDidDexOpt;
817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 String mDebugApp = null;
819 boolean mWaitForDebugger = false;
820 boolean mDebugTransient = false;
821 String mOrigDebugApp = null;
822 boolean mOrigWaitForDebugger = false;
823 boolean mAlwaysFinishActivities = false;
824 IActivityWatcher mWatcher = null;
825
826 /**
827 * Callback of last caller to {@link #requestPss}.
828 */
829 Runnable mRequestPssCallback;
830
831 /**
832 * Remaining processes for which we are waiting results from the last
833 * call to {@link #requestPss}.
834 */
835 final ArrayList<ProcessRecord> mRequestPssList
836 = new ArrayList<ProcessRecord>();
837
838 /**
839 * Runtime statistics collection thread. This object's lock is used to
840 * protect all related state.
841 */
842 final Thread mProcessStatsThread;
843
844 /**
845 * Used to collect process stats when showing not responding dialog.
846 * Protected by mProcessStatsThread.
847 */
848 final ProcessStats mProcessStats = new ProcessStats(
849 MONITOR_THREAD_CPU_USAGE);
850 long mLastCpuTime = 0;
851 long mLastWriteTime = 0;
852
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700853 long mInitialStartTime = 0;
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 /**
856 * Set to true after the system has finished booting.
857 */
858 boolean mBooted = false;
859
860 int mProcessLimit = 0;
861
862 WindowManagerService mWindowManager;
863
864 static ActivityManagerService mSelf;
865 static ActivityThread mSystemThread;
866
867 private final class AppDeathRecipient implements IBinder.DeathRecipient {
868 final ProcessRecord mApp;
869 final int mPid;
870 final IApplicationThread mAppThread;
871
872 AppDeathRecipient(ProcessRecord app, int pid,
873 IApplicationThread thread) {
874 if (localLOGV) Log.v(
875 TAG, "New death recipient " + this
876 + " for thread " + thread.asBinder());
877 mApp = app;
878 mPid = pid;
879 mAppThread = thread;
880 }
881
882 public void binderDied() {
883 if (localLOGV) Log.v(
884 TAG, "Death received in " + this
885 + " for thread " + mAppThread.asBinder());
886 removeRequestedPss(mApp);
887 synchronized(ActivityManagerService.this) {
888 appDiedLocked(mApp, mPid, mAppThread);
889 }
890 }
891 }
892
893 static final int SHOW_ERROR_MSG = 1;
894 static final int SHOW_NOT_RESPONDING_MSG = 2;
895 static final int SHOW_FACTORY_ERROR_MSG = 3;
896 static final int UPDATE_CONFIGURATION_MSG = 4;
897 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
898 static final int WAIT_FOR_DEBUGGER_MSG = 6;
899 static final int BROADCAST_INTENT_MSG = 7;
900 static final int BROADCAST_TIMEOUT_MSG = 8;
901 static final int PAUSE_TIMEOUT_MSG = 9;
902 static final int IDLE_TIMEOUT_MSG = 10;
903 static final int IDLE_NOW_MSG = 11;
904 static final int SERVICE_TIMEOUT_MSG = 12;
905 static final int UPDATE_TIME_ZONE = 13;
906 static final int SHOW_UID_ERROR_MSG = 14;
907 static final int IM_FEELING_LUCKY_MSG = 15;
908 static final int LAUNCH_TIMEOUT_MSG = 16;
909 static final int DESTROY_TIMEOUT_MSG = 17;
910 static final int SERVICE_ERROR_MSG = 18;
911 static final int RESUME_TOP_ACTIVITY_MSG = 19;
912 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700913 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914
915 AlertDialog mUidAlert;
916
917 final Handler mHandler = new Handler() {
918 //public Handler() {
919 // if (localLOGV) Log.v(TAG, "Handler started!");
920 //}
921
922 public void handleMessage(Message msg) {
923 switch (msg.what) {
924 case SHOW_ERROR_MSG: {
925 HashMap data = (HashMap) msg.obj;
926 byte[] crashData = (byte[])data.get("crashData");
927 if (crashData != null) {
928 // This needs to be *un*synchronized to avoid deadlock.
929 ContentResolver resolver = mContext.getContentResolver();
930 Checkin.reportCrash(resolver, crashData);
931 }
932 synchronized (ActivityManagerService.this) {
933 ProcessRecord proc = (ProcessRecord)data.get("app");
934 if (proc != null && proc.crashDialog != null) {
935 Log.e(TAG, "App already has crash dialog: " + proc);
936 return;
937 }
938 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700939 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 Dialog d = new AppErrorDialog(
941 mContext, res, proc,
942 (Integer)data.get("flags"),
943 (String)data.get("shortMsg"),
944 (String)data.get("longMsg"));
945 d.show();
946 proc.crashDialog = d;
947 } else {
948 // The device is asleep, so just pretend that the user
949 // saw a crash dialog and hit "force quit".
950 res.set(0);
951 }
952 }
953 } break;
954 case SHOW_NOT_RESPONDING_MSG: {
955 synchronized (ActivityManagerService.this) {
956 HashMap data = (HashMap) msg.obj;
957 ProcessRecord proc = (ProcessRecord)data.get("app");
958 if (proc != null && proc.anrDialog != null) {
959 Log.e(TAG, "App already has anr dialog: " + proc);
960 return;
961 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800962
963 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
964 null, null, 0, null, null, null,
965 false, false, MY_PID, Process.SYSTEM_UID);
966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
968 mContext, proc, (HistoryRecord)data.get("activity"));
969 d.show();
970 proc.anrDialog = d;
971 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700972
973 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 } break;
975 case SHOW_FACTORY_ERROR_MSG: {
976 Dialog d = new FactoryErrorDialog(
977 mContext, msg.getData().getCharSequence("msg"));
978 d.show();
979 enableScreenAfterBoot();
980 } break;
981 case UPDATE_CONFIGURATION_MSG: {
982 final ContentResolver resolver = mContext.getContentResolver();
983 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
984 } break;
985 case GC_BACKGROUND_PROCESSES_MSG: {
986 synchronized (ActivityManagerService.this) {
987 performAppGcsIfAppropriateLocked();
988 }
989 } break;
990 case WAIT_FOR_DEBUGGER_MSG: {
991 synchronized (ActivityManagerService.this) {
992 ProcessRecord app = (ProcessRecord)msg.obj;
993 if (msg.arg1 != 0) {
994 if (!app.waitedForDebugger) {
995 Dialog d = new AppWaitingForDebuggerDialog(
996 ActivityManagerService.this,
997 mContext, app);
998 app.waitDialog = d;
999 app.waitedForDebugger = true;
1000 d.show();
1001 }
1002 } else {
1003 if (app.waitDialog != null) {
1004 app.waitDialog.dismiss();
1005 app.waitDialog = null;
1006 }
1007 }
1008 }
1009 } break;
1010 case BROADCAST_INTENT_MSG: {
1011 if (DEBUG_BROADCAST) Log.v(
1012 TAG, "Received BROADCAST_INTENT_MSG");
1013 processNextBroadcast(true);
1014 } break;
1015 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001016 if (mDidDexOpt) {
1017 mDidDexOpt = false;
1018 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1019 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1020 return;
1021 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 broadcastTimeout();
1023 } break;
1024 case PAUSE_TIMEOUT_MSG: {
1025 IBinder token = (IBinder)msg.obj;
1026 // We don't at this point know if the activity is fullscreen,
1027 // so we need to be conservative and assume it isn't.
1028 Log.w(TAG, "Activity pause timeout for " + token);
1029 activityPaused(token, null, true);
1030 } break;
1031 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001032 if (mDidDexOpt) {
1033 mDidDexOpt = false;
1034 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1035 nmsg.obj = msg.obj;
1036 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1037 return;
1038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 // We don't at this point know if the activity is fullscreen,
1040 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001041 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 Log.w(TAG, "Activity idle timeout for " + token);
1043 activityIdleInternal(token, true);
1044 } break;
1045 case DESTROY_TIMEOUT_MSG: {
1046 IBinder token = (IBinder)msg.obj;
1047 // We don't at this point know if the activity is fullscreen,
1048 // so we need to be conservative and assume it isn't.
1049 Log.w(TAG, "Activity destroy timeout for " + token);
1050 activityDestroyed(token);
1051 } break;
1052 case IDLE_NOW_MSG: {
1053 IBinder token = (IBinder)msg.obj;
1054 activityIdle(token);
1055 } break;
1056 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001057 if (mDidDexOpt) {
1058 mDidDexOpt = false;
1059 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1060 nmsg.obj = msg.obj;
1061 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1062 return;
1063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 serviceTimeout((ProcessRecord)msg.obj);
1065 } break;
1066 case UPDATE_TIME_ZONE: {
1067 synchronized (ActivityManagerService.this) {
1068 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1069 ProcessRecord r = mLRUProcesses.get(i);
1070 if (r.thread != null) {
1071 try {
1072 r.thread.updateTimeZone();
1073 } catch (RemoteException ex) {
1074 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1075 }
1076 }
1077 }
1078 }
1079 break;
1080 }
1081 case SHOW_UID_ERROR_MSG: {
1082 // XXX This is a temporary dialog, no need to localize.
1083 AlertDialog d = new BaseErrorDialog(mContext);
1084 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1085 d.setCancelable(false);
1086 d.setTitle("System UIDs Inconsistent");
1087 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1088 d.setButton("I'm Feeling Lucky",
1089 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1090 mUidAlert = d;
1091 d.show();
1092 } break;
1093 case IM_FEELING_LUCKY_MSG: {
1094 if (mUidAlert != null) {
1095 mUidAlert.dismiss();
1096 mUidAlert = null;
1097 }
1098 } break;
1099 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001100 if (mDidDexOpt) {
1101 mDidDexOpt = false;
1102 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1103 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1104 return;
1105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 synchronized (ActivityManagerService.this) {
1107 if (mLaunchingActivity.isHeld()) {
1108 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1109 mLaunchingActivity.release();
1110 }
1111 }
1112 } break;
1113 case SERVICE_ERROR_MSG: {
1114 ServiceRecord srv = (ServiceRecord)msg.obj;
1115 // This needs to be *un*synchronized to avoid deadlock.
1116 Checkin.logEvent(mContext.getContentResolver(),
1117 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1118 srv.name.toShortString());
1119 } break;
1120 case RESUME_TOP_ACTIVITY_MSG: {
1121 synchronized (ActivityManagerService.this) {
1122 resumeTopActivityLocked(null);
1123 }
1124 }
1125 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001126 if (mDidDexOpt) {
1127 mDidDexOpt = false;
1128 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1129 nmsg.obj = msg.obj;
1130 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1131 return;
1132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 ProcessRecord app = (ProcessRecord)msg.obj;
1134 synchronized (ActivityManagerService.this) {
1135 processStartTimedOutLocked(app);
1136 }
1137 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001138 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1139 synchronized (ActivityManagerService.this) {
1140 doPendingActivityLaunchesLocked(true);
1141 }
1142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 }
1144 }
1145 };
1146
1147 public static void setSystemProcess() {
1148 try {
1149 ActivityManagerService m = mSelf;
1150
1151 ServiceManager.addService("activity", m);
1152 ServiceManager.addService("meminfo", new MemBinder(m));
1153 if (MONITOR_CPU_USAGE) {
1154 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1155 }
1156 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1157 ServiceManager.addService("activity.services", new ServicesBinder(m));
1158 ServiceManager.addService("activity.senders", new SendersBinder(m));
1159 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1160 ServiceManager.addService("permission", new PermissionController(m));
1161
1162 ApplicationInfo info =
1163 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001164 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 synchronized (mSelf) {
1166 ProcessRecord app = mSelf.newProcessRecordLocked(
1167 mSystemThread.getApplicationThread(), info,
1168 info.processName);
1169 app.persistent = true;
1170 app.pid = Process.myPid();
1171 app.maxAdj = SYSTEM_ADJ;
1172 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1173 synchronized (mSelf.mPidsSelfLocked) {
1174 mSelf.mPidsSelfLocked.put(app.pid, app);
1175 }
1176 mSelf.updateLRUListLocked(app, true);
1177 }
1178 } catch (PackageManager.NameNotFoundException e) {
1179 throw new RuntimeException(
1180 "Unable to find android system package", e);
1181 }
1182 }
1183
1184 public void setWindowManager(WindowManagerService wm) {
1185 mWindowManager = wm;
1186 }
1187
1188 public static final Context main(int factoryTest) {
1189 AThread thr = new AThread();
1190 thr.start();
1191
1192 synchronized (thr) {
1193 while (thr.mService == null) {
1194 try {
1195 thr.wait();
1196 } catch (InterruptedException e) {
1197 }
1198 }
1199 }
1200
1201 ActivityManagerService m = thr.mService;
1202 mSelf = m;
1203 ActivityThread at = ActivityThread.systemMain();
1204 mSystemThread = at;
1205 Context context = at.getSystemContext();
1206 m.mContext = context;
1207 m.mFactoryTest = factoryTest;
1208 PowerManager pm =
1209 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1210 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1211 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1212 m.mLaunchingActivity.setReferenceCounted(false);
1213
1214 m.mBatteryStatsService.publish(context);
1215 m.mUsageStatsService.publish(context);
1216
1217 synchronized (thr) {
1218 thr.mReady = true;
1219 thr.notifyAll();
1220 }
1221
1222 m.startRunning(null, null, null, null);
1223
1224 return context;
1225 }
1226
1227 public static ActivityManagerService self() {
1228 return mSelf;
1229 }
1230
1231 static class AThread extends Thread {
1232 ActivityManagerService mService;
1233 boolean mReady = false;
1234
1235 public AThread() {
1236 super("ActivityManager");
1237 }
1238
1239 public void run() {
1240 Looper.prepare();
1241
1242 android.os.Process.setThreadPriority(
1243 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1244
1245 ActivityManagerService m = new ActivityManagerService();
1246
1247 synchronized (this) {
1248 mService = m;
1249 notifyAll();
1250 }
1251
1252 synchronized (this) {
1253 while (!mReady) {
1254 try {
1255 wait();
1256 } catch (InterruptedException e) {
1257 }
1258 }
1259 }
1260
1261 Looper.loop();
1262 }
1263 }
1264
1265 static class BroadcastsBinder extends Binder {
1266 ActivityManagerService mActivityManagerService;
1267 BroadcastsBinder(ActivityManagerService activityManagerService) {
1268 mActivityManagerService = activityManagerService;
1269 }
1270
1271 @Override
1272 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1273 mActivityManagerService.dumpBroadcasts(pw);
1274 }
1275 }
1276
1277 static class ServicesBinder extends Binder {
1278 ActivityManagerService mActivityManagerService;
1279 ServicesBinder(ActivityManagerService activityManagerService) {
1280 mActivityManagerService = activityManagerService;
1281 }
1282
1283 @Override
1284 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1285 mActivityManagerService.dumpServices(pw);
1286 }
1287 }
1288
1289 static class SendersBinder extends Binder {
1290 ActivityManagerService mActivityManagerService;
1291 SendersBinder(ActivityManagerService activityManagerService) {
1292 mActivityManagerService = activityManagerService;
1293 }
1294
1295 @Override
1296 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1297 mActivityManagerService.dumpSenders(pw);
1298 }
1299 }
1300
1301 static class ProvidersBinder extends Binder {
1302 ActivityManagerService mActivityManagerService;
1303 ProvidersBinder(ActivityManagerService activityManagerService) {
1304 mActivityManagerService = activityManagerService;
1305 }
1306
1307 @Override
1308 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1309 mActivityManagerService.dumpProviders(pw);
1310 }
1311 }
1312
1313 static class MemBinder extends Binder {
1314 ActivityManagerService mActivityManagerService;
1315 MemBinder(ActivityManagerService activityManagerService) {
1316 mActivityManagerService = activityManagerService;
1317 }
1318
1319 @Override
1320 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1321 ActivityManagerService service = mActivityManagerService;
1322 ArrayList<ProcessRecord> procs;
1323 synchronized (mActivityManagerService) {
1324 if (args != null && args.length > 0
1325 && args[0].charAt(0) != '-') {
1326 procs = new ArrayList<ProcessRecord>();
1327 int pid = -1;
1328 try {
1329 pid = Integer.parseInt(args[0]);
1330 } catch (NumberFormatException e) {
1331
1332 }
1333 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1334 ProcessRecord proc = service.mLRUProcesses.get(i);
1335 if (proc.pid == pid) {
1336 procs.add(proc);
1337 } else if (proc.processName.equals(args[0])) {
1338 procs.add(proc);
1339 }
1340 }
1341 if (procs.size() <= 0) {
1342 pw.println("No process found for: " + args[0]);
1343 return;
1344 }
1345 } else {
1346 procs = service.mLRUProcesses;
1347 }
1348 }
1349 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1350 }
1351 }
1352
1353 static class CpuBinder extends Binder {
1354 ActivityManagerService mActivityManagerService;
1355 CpuBinder(ActivityManagerService activityManagerService) {
1356 mActivityManagerService = activityManagerService;
1357 }
1358
1359 @Override
1360 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1361 synchronized (mActivityManagerService.mProcessStatsThread) {
1362 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1363 }
1364 }
1365 }
1366
1367 private ActivityManagerService() {
1368 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1369 if (v != null && Integer.getInteger(v) != 0) {
1370 mSimpleProcessManagement = true;
1371 }
1372 v = System.getenv("ANDROID_DEBUG_APP");
1373 if (v != null) {
1374 mSimpleProcessManagement = true;
1375 }
1376
1377 MY_PID = Process.myPid();
1378
1379 File dataDir = Environment.getDataDirectory();
1380 File systemDir = new File(dataDir, "system");
1381 systemDir.mkdirs();
1382 mBatteryStatsService = new BatteryStatsService(new File(
1383 systemDir, "batterystats.bin").toString());
1384 mBatteryStatsService.getActiveStatistics().readLocked();
1385 mBatteryStatsService.getActiveStatistics().writeLocked();
1386
1387 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001388 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389
1390 mConfiguration.makeDefault();
1391 mProcessStats.init();
1392
1393 // Add ourself to the Watchdog monitors.
1394 Watchdog.getInstance().addMonitor(this);
1395
1396 // These values are set in system/rootdir/init.rc on startup.
1397 FOREGROUND_APP_ADJ =
1398 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1399 VISIBLE_APP_ADJ =
1400 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1401 SECONDARY_SERVER_ADJ =
1402 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001403 BACKUP_APP_ADJ =
1404 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001405 HOME_APP_ADJ =
1406 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 HIDDEN_APP_MIN_ADJ =
1408 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1409 CONTENT_PROVIDER_ADJ =
1410 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1411 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1412 EMPTY_APP_ADJ =
1413 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1414 FOREGROUND_APP_MEM =
1415 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1416 VISIBLE_APP_MEM =
1417 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1418 SECONDARY_SERVER_MEM =
1419 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001420 BACKUP_APP_MEM =
1421 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001422 HOME_APP_MEM =
1423 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 HIDDEN_APP_MEM =
1425 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1426 EMPTY_APP_MEM =
1427 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1428
1429 mProcessStatsThread = new Thread("ProcessStats") {
1430 public void run() {
1431 while (true) {
1432 try {
1433 try {
1434 synchronized(this) {
1435 final long now = SystemClock.uptimeMillis();
1436 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1437 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1438 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1439 // + ", write delay=" + nextWriteDelay);
1440 if (nextWriteDelay < nextCpuDelay) {
1441 nextCpuDelay = nextWriteDelay;
1442 }
1443 if (nextCpuDelay > 0) {
1444 this.wait(nextCpuDelay);
1445 }
1446 }
1447 } catch (InterruptedException e) {
1448 }
1449
1450 updateCpuStatsNow();
1451 } catch (Exception e) {
1452 Log.e(TAG, "Unexpected exception collecting process stats", e);
1453 }
1454 }
1455 }
1456 };
1457 mProcessStatsThread.start();
1458 }
1459
1460 @Override
1461 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1462 throws RemoteException {
1463 try {
1464 return super.onTransact(code, data, reply, flags);
1465 } catch (RuntimeException e) {
1466 // The activity manager only throws security exceptions, so let's
1467 // log all others.
1468 if (!(e instanceof SecurityException)) {
1469 Log.e(TAG, "Activity Manager Crash", e);
1470 }
1471 throw e;
1472 }
1473 }
1474
1475 void updateCpuStats() {
1476 synchronized (mProcessStatsThread) {
1477 final long now = SystemClock.uptimeMillis();
1478 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1479 mProcessStatsThread.notify();
1480 }
1481 }
1482 }
1483
1484 void updateCpuStatsNow() {
1485 synchronized (mProcessStatsThread) {
1486 final long now = SystemClock.uptimeMillis();
1487 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 if (MONITOR_CPU_USAGE &&
1490 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1491 mLastCpuTime = now;
1492 haveNewCpuStats = true;
1493 mProcessStats.update();
1494 //Log.i(TAG, mProcessStats.printCurrentState());
1495 //Log.i(TAG, "Total CPU usage: "
1496 // + mProcessStats.getTotalCpuPercent() + "%");
1497
1498 // Log the cpu usage if the property is set.
1499 if ("true".equals(SystemProperties.get("events.cpu"))) {
1500 int user = mProcessStats.getLastUserTime();
1501 int system = mProcessStats.getLastSystemTime();
1502 int iowait = mProcessStats.getLastIoWaitTime();
1503 int irq = mProcessStats.getLastIrqTime();
1504 int softIrq = mProcessStats.getLastSoftIrqTime();
1505 int idle = mProcessStats.getLastIdleTime();
1506
1507 int total = user + system + iowait + irq + softIrq + idle;
1508 if (total == 0) total = 1;
1509
1510 EventLog.writeEvent(LOG_CPU,
1511 ((user+system+iowait+irq+softIrq) * 100) / total,
1512 (user * 100) / total,
1513 (system * 100) / total,
1514 (iowait * 100) / total,
1515 (irq * 100) / total,
1516 (softIrq * 100) / total);
1517 }
1518 }
1519
1520 synchronized(mBatteryStatsService.getActiveStatistics()) {
1521 synchronized(mPidsSelfLocked) {
1522 if (haveNewCpuStats) {
1523 if (mBatteryStatsService.isOnBattery()) {
1524 final int N = mProcessStats.countWorkingStats();
1525 for (int i=0; i<N; i++) {
1526 ProcessStats.Stats st
1527 = mProcessStats.getWorkingStats(i);
1528 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1529 if (pr != null) {
1530 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1531 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1532 }
1533 }
1534 }
1535 }
1536 }
1537
1538 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1539 mLastWriteTime = now;
1540 mBatteryStatsService.getActiveStatistics().writeLocked();
1541 }
1542 }
1543 }
1544 }
1545
1546 /**
1547 * Initialize the application bind args. These are passed to each
1548 * process when the bindApplication() IPC is sent to the process. They're
1549 * lazily setup to make sure the services are running when they're asked for.
1550 */
1551 private HashMap<String, IBinder> getCommonServicesLocked() {
1552 if (mAppBindArgs == null) {
1553 mAppBindArgs = new HashMap<String, IBinder>();
1554
1555 // Setup the application init args
1556 mAppBindArgs.put("package", ServiceManager.getService("package"));
1557 mAppBindArgs.put("window", ServiceManager.getService("window"));
1558 mAppBindArgs.put(Context.ALARM_SERVICE,
1559 ServiceManager.getService(Context.ALARM_SERVICE));
1560 }
1561 return mAppBindArgs;
1562 }
1563
1564 private final void setFocusedActivityLocked(HistoryRecord r) {
1565 if (mFocusedActivity != r) {
1566 mFocusedActivity = r;
1567 mWindowManager.setFocusedApp(r, true);
1568 }
1569 }
1570
1571 private final void updateLRUListLocked(ProcessRecord app,
1572 boolean oomAdj) {
1573 // put it on the LRU to keep track of when it should be exited.
1574 int lrui = mLRUProcesses.indexOf(app);
1575 if (lrui >= 0) mLRUProcesses.remove(lrui);
1576 mLRUProcesses.add(app);
1577 //Log.i(TAG, "Putting proc to front: " + app.processName);
1578 if (oomAdj) {
1579 updateOomAdjLocked();
1580 }
1581 }
1582
1583 private final boolean updateLRUListLocked(HistoryRecord r) {
1584 final boolean hadit = mLRUActivities.remove(r);
1585 mLRUActivities.add(r);
1586 return hadit;
1587 }
1588
1589 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1590 int i = mHistory.size()-1;
1591 while (i >= 0) {
1592 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1593 if (!r.finishing && r != notTop) {
1594 return r;
1595 }
1596 i--;
1597 }
1598 return null;
1599 }
1600
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001601 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1602 int i = mHistory.size()-1;
1603 while (i >= 0) {
1604 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1605 if (!r.finishing && !r.delayedResume && r != notTop) {
1606 return r;
1607 }
1608 i--;
1609 }
1610 return null;
1611 }
1612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 /**
1614 * This is a simplified version of topRunningActivityLocked that provides a number of
1615 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1616 *
1617 * @param token If non-null, any history records matching this token will be skipped.
1618 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1619 *
1620 * @return Returns the HistoryRecord of the next activity on the stack.
1621 */
1622 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1623 int i = mHistory.size()-1;
1624 while (i >= 0) {
1625 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1626 // Note: the taskId check depends on real taskId fields being non-zero
1627 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1628 return r;
1629 }
1630 i--;
1631 }
1632 return null;
1633 }
1634
1635 private final ProcessRecord getProcessRecordLocked(
1636 String processName, int uid) {
1637 if (uid == Process.SYSTEM_UID) {
1638 // The system gets to run in any process. If there are multiple
1639 // processes with the same uid, just pick the first (this
1640 // should never happen).
1641 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1642 processName);
1643 return procs != null ? procs.valueAt(0) : null;
1644 }
1645 ProcessRecord proc = mProcessNames.get(processName, uid);
1646 return proc;
1647 }
1648
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001649 private void ensurePackageDexOpt(String packageName) {
1650 IPackageManager pm = ActivityThread.getPackageManager();
1651 try {
1652 if (pm.performDexOpt(packageName)) {
1653 mDidDexOpt = true;
1654 }
1655 } catch (RemoteException e) {
1656 }
1657 }
1658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 private boolean isNextTransitionForward() {
1660 int transit = mWindowManager.getPendingAppTransition();
1661 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1662 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1663 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1664 }
1665
1666 private final boolean realStartActivityLocked(HistoryRecord r,
1667 ProcessRecord app, boolean andResume, boolean checkConfig)
1668 throws RemoteException {
1669
1670 r.startFreezingScreenLocked(app, 0);
1671 mWindowManager.setAppVisibility(r, true);
1672
1673 // Have the window manager re-evaluate the orientation of
1674 // the screen based on the new activity order. Note that
1675 // as a result of this, it can call back into the activity
1676 // manager with a new orientation. We don't care about that,
1677 // because the activity is not currently running so we are
1678 // just restarting it anyway.
1679 if (checkConfig) {
1680 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001681 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 r.mayFreezeScreenLocked(app) ? r : null);
1683 updateConfigurationLocked(config, r);
1684 }
1685
1686 r.app = app;
1687
1688 if (localLOGV) Log.v(TAG, "Launching: " + r);
1689
1690 int idx = app.activities.indexOf(r);
1691 if (idx < 0) {
1692 app.activities.add(r);
1693 }
1694 updateLRUListLocked(app, true);
1695
1696 try {
1697 if (app.thread == null) {
1698 throw new RemoteException();
1699 }
1700 List<ResultInfo> results = null;
1701 List<Intent> newIntents = null;
1702 if (andResume) {
1703 results = r.results;
1704 newIntents = r.newIntents;
1705 }
1706 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1707 + " icicle=" + r.icicle
1708 + " with results=" + results + " newIntents=" + newIntents
1709 + " andResume=" + andResume);
1710 if (andResume) {
1711 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1712 System.identityHashCode(r),
1713 r.task.taskId, r.shortComponentName);
1714 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001715 if (r.isHomeActivity) {
1716 mHomeProcess = app;
1717 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001718 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1720 r.info, r.icicle, results, newIntents, !andResume,
1721 isNextTransitionForward());
1722 // Update usage stats for launched activity
1723 updateUsageStats(r, true);
1724 } catch (RemoteException e) {
1725 if (r.launchFailed) {
1726 // This is the second time we failed -- finish activity
1727 // and give up.
1728 Log.e(TAG, "Second failure launching "
1729 + r.intent.getComponent().flattenToShortString()
1730 + ", giving up", e);
1731 appDiedLocked(app, app.pid, app.thread);
1732 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1733 "2nd-crash");
1734 return false;
1735 }
1736
1737 // This is the first time we failed -- restart process and
1738 // retry.
1739 app.activities.remove(r);
1740 throw e;
1741 }
1742
1743 r.launchFailed = false;
1744 if (updateLRUListLocked(r)) {
1745 Log.w(TAG, "Activity " + r
1746 + " being launched, but already in LRU list");
1747 }
1748
1749 if (andResume) {
1750 // As part of the process of launching, ActivityThread also performs
1751 // a resume.
1752 r.state = ActivityState.RESUMED;
1753 r.icicle = null;
1754 r.haveState = false;
1755 r.stopped = false;
1756 mResumedActivity = r;
1757 r.task.touchActiveTime();
1758 completeResumeLocked(r);
1759 pauseIfSleepingLocked();
1760 } else {
1761 // This activity is not starting in the resumed state... which
1762 // should look like we asked it to pause+stop (but remain visible),
1763 // and it has done so and reported back the current icicle and
1764 // other state.
1765 r.state = ActivityState.STOPPED;
1766 r.stopped = true;
1767 }
1768
1769 return true;
1770 }
1771
1772 private final void startSpecificActivityLocked(HistoryRecord r,
1773 boolean andResume, boolean checkConfig) {
1774 // Is this activity's application already running?
1775 ProcessRecord app = getProcessRecordLocked(r.processName,
1776 r.info.applicationInfo.uid);
1777
1778 if (r.startTime == 0) {
1779 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001780 if (mInitialStartTime == 0) {
1781 mInitialStartTime = r.startTime;
1782 }
1783 } else if (mInitialStartTime == 0) {
1784 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 }
1786
1787 if (app != null && app.thread != null) {
1788 try {
1789 realStartActivityLocked(r, app, andResume, checkConfig);
1790 return;
1791 } catch (RemoteException e) {
1792 Log.w(TAG, "Exception when starting activity "
1793 + r.intent.getComponent().flattenToShortString(), e);
1794 }
1795
1796 // If a dead object exception was thrown -- fall through to
1797 // restart the application.
1798 }
1799
1800 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1801 "activity", r.intent.getComponent());
1802 }
1803
1804 private final ProcessRecord startProcessLocked(String processName,
1805 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1806 String hostingType, ComponentName hostingName) {
1807 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1808 // We don't have to do anything more if:
1809 // (1) There is an existing application record; and
1810 // (2) The caller doesn't think it is dead, OR there is no thread
1811 // object attached to it so we know it couldn't have crashed; and
1812 // (3) There is a pid assigned to it, so it is either starting or
1813 // already running.
1814 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1815 + " app=" + app + " knownToBeDead=" + knownToBeDead
1816 + " thread=" + (app != null ? app.thread : null)
1817 + " pid=" + (app != null ? app.pid : -1));
1818 if (app != null &&
1819 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1820 return app;
1821 }
1822
1823 String hostingNameStr = hostingName != null
1824 ? hostingName.flattenToShortString() : null;
1825
1826 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1827 // If we are in the background, then check to see if this process
1828 // is bad. If so, we will just silently fail.
1829 if (mBadProcesses.get(info.processName, info.uid) != null) {
1830 return null;
1831 }
1832 } else {
1833 // When the user is explicitly starting a process, then clear its
1834 // crash count so that we won't make it bad until they see at
1835 // least one crash dialog again, and make the process good again
1836 // if it had been bad.
1837 mProcessCrashTimes.remove(info.processName, info.uid);
1838 if (mBadProcesses.get(info.processName, info.uid) != null) {
1839 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1840 info.processName);
1841 mBadProcesses.remove(info.processName, info.uid);
1842 if (app != null) {
1843 app.bad = false;
1844 }
1845 }
1846 }
1847
1848 if (app == null) {
1849 app = newProcessRecordLocked(null, info, processName);
1850 mProcessNames.put(processName, info.uid, app);
1851 } else {
1852 // If this is a new package in the process, add the package to the list
1853 app.addPackage(info.packageName);
1854 }
1855
1856 // If the system is not ready yet, then hold off on starting this
1857 // process until it is.
1858 if (!mSystemReady
1859 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1860 if (!mProcessesOnHold.contains(app)) {
1861 mProcessesOnHold.add(app);
1862 }
1863 return app;
1864 }
1865
1866 startProcessLocked(app, hostingType, hostingNameStr);
1867 return (app.pid != 0) ? app : null;
1868 }
1869
1870 private final void startProcessLocked(ProcessRecord app,
1871 String hostingType, String hostingNameStr) {
1872 if (app.pid > 0 && app.pid != MY_PID) {
1873 synchronized (mPidsSelfLocked) {
1874 mPidsSelfLocked.remove(app.pid);
1875 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1876 }
1877 app.pid = 0;
1878 }
1879
1880 mProcessesOnHold.remove(app);
1881
1882 updateCpuStats();
1883
1884 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1885 mProcDeaths[0] = 0;
1886
1887 try {
1888 int uid = app.info.uid;
1889 int[] gids = null;
1890 try {
1891 gids = mContext.getPackageManager().getPackageGids(
1892 app.info.packageName);
1893 } catch (PackageManager.NameNotFoundException e) {
1894 Log.w(TAG, "Unable to retrieve gids", e);
1895 }
1896 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1897 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1898 && mTopComponent != null
1899 && app.processName.equals(mTopComponent.getPackageName())) {
1900 uid = 0;
1901 }
1902 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1903 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1904 uid = 0;
1905 }
1906 }
1907 int debugFlags = 0;
1908 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1909 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1910 }
1911 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1912 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1913 }
1914 if ("1".equals(SystemProperties.get("debug.assert"))) {
1915 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1916 }
1917 int pid = Process.start("android.app.ActivityThread",
1918 mSimpleProcessManagement ? app.processName : null, uid, uid,
1919 gids, debugFlags, null);
1920 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1921 synchronized (bs) {
1922 if (bs.isOnBattery()) {
1923 app.batteryStats.incStartsLocked();
1924 }
1925 }
1926
1927 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1928 app.processName, hostingType,
1929 hostingNameStr != null ? hostingNameStr : "");
1930
1931 if (app.persistent) {
1932 Watchdog.getInstance().processStarted(app, app.processName, pid);
1933 }
1934
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001935 StringBuilder buf = mStringBuilder;
1936 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 buf.append("Start proc ");
1938 buf.append(app.processName);
1939 buf.append(" for ");
1940 buf.append(hostingType);
1941 if (hostingNameStr != null) {
1942 buf.append(" ");
1943 buf.append(hostingNameStr);
1944 }
1945 buf.append(": pid=");
1946 buf.append(pid);
1947 buf.append(" uid=");
1948 buf.append(uid);
1949 buf.append(" gids={");
1950 if (gids != null) {
1951 for (int gi=0; gi<gids.length; gi++) {
1952 if (gi != 0) buf.append(", ");
1953 buf.append(gids[gi]);
1954
1955 }
1956 }
1957 buf.append("}");
1958 Log.i(TAG, buf.toString());
1959 if (pid == 0 || pid == MY_PID) {
1960 // Processes are being emulated with threads.
1961 app.pid = MY_PID;
1962 app.removed = false;
1963 mStartingProcesses.add(app);
1964 } else if (pid > 0) {
1965 app.pid = pid;
1966 app.removed = false;
1967 synchronized (mPidsSelfLocked) {
1968 this.mPidsSelfLocked.put(pid, app);
1969 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1970 msg.obj = app;
1971 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1972 }
1973 } else {
1974 app.pid = 0;
1975 RuntimeException e = new RuntimeException(
1976 "Failure starting process " + app.processName
1977 + ": returned pid=" + pid);
1978 Log.e(TAG, e.getMessage(), e);
1979 }
1980 } catch (RuntimeException e) {
1981 // XXX do better error recovery.
1982 app.pid = 0;
1983 Log.e(TAG, "Failure starting process " + app.processName, e);
1984 }
1985 }
1986
1987 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1988 if (mPausingActivity != null) {
1989 RuntimeException e = new RuntimeException();
1990 Log.e(TAG, "Trying to pause when pause is already pending for "
1991 + mPausingActivity, e);
1992 }
1993 HistoryRecord prev = mResumedActivity;
1994 if (prev == null) {
1995 RuntimeException e = new RuntimeException();
1996 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1997 resumeTopActivityLocked(null);
1998 return;
1999 }
2000 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2001 mResumedActivity = null;
2002 mPausingActivity = prev;
2003 mLastPausedActivity = prev;
2004 prev.state = ActivityState.PAUSING;
2005 prev.task.touchActiveTime();
2006
2007 updateCpuStats();
2008
2009 if (prev.app != null && prev.app.thread != null) {
2010 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2011 try {
2012 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2013 System.identityHashCode(prev),
2014 prev.shortComponentName);
2015 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2016 prev.configChangeFlags);
2017 updateUsageStats(prev, false);
2018 } catch (Exception e) {
2019 // Ignore exception, if process died other code will cleanup.
2020 Log.w(TAG, "Exception thrown during pause", e);
2021 mPausingActivity = null;
2022 mLastPausedActivity = null;
2023 }
2024 } else {
2025 mPausingActivity = null;
2026 mLastPausedActivity = null;
2027 }
2028
2029 // If we are not going to sleep, we want to ensure the device is
2030 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002031 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 mLaunchingActivity.acquire();
2033 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2034 // To be safe, don't allow the wake lock to be held for too long.
2035 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2036 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2037 }
2038 }
2039
2040
2041 if (mPausingActivity != null) {
2042 // Have the window manager pause its key dispatching until the new
2043 // activity has started. If we're pausing the activity just because
2044 // the screen is being turned off and the UI is sleeping, don't interrupt
2045 // key dispatch; the same activity will pick it up again on wakeup.
2046 if (!uiSleeping) {
2047 prev.pauseKeyDispatchingLocked();
2048 } else {
2049 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2050 }
2051
2052 // Schedule a pause timeout in case the app doesn't respond.
2053 // We don't give it much time because this directly impacts the
2054 // responsiveness seen by the user.
2055 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2056 msg.obj = prev;
2057 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2058 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2059 } else {
2060 // This activity failed to schedule the
2061 // pause, so just treat it as being paused now.
2062 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2063 resumeTopActivityLocked(null);
2064 }
2065 }
2066
2067 private final void completePauseLocked() {
2068 HistoryRecord prev = mPausingActivity;
2069 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2070
2071 if (prev != null) {
2072 if (prev.finishing) {
2073 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2074 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2075 } else if (prev.app != null) {
2076 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2077 if (prev.waitingVisible) {
2078 prev.waitingVisible = false;
2079 mWaitingVisibleActivities.remove(prev);
2080 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2081 TAG, "Complete pause, no longer waiting: " + prev);
2082 }
2083 if (prev.configDestroy) {
2084 // The previous is being paused because the configuration
2085 // is changing, which means it is actually stopping...
2086 // To juggle the fact that we are also starting a new
2087 // instance right now, we need to first completely stop
2088 // the current instance before starting the new one.
2089 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2090 destroyActivityLocked(prev, true);
2091 } else {
2092 mStoppingActivities.add(prev);
2093 if (mStoppingActivities.size() > 3) {
2094 // If we already have a few activities waiting to stop,
2095 // then give up on things going idle and start clearing
2096 // them out.
2097 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2098 Message msg = Message.obtain();
2099 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2100 mHandler.sendMessage(msg);
2101 }
2102 }
2103 } else {
2104 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2105 prev = null;
2106 }
2107 mPausingActivity = null;
2108 }
2109
Dianne Hackborn55280a92009-05-07 15:53:46 -07002110 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 resumeTopActivityLocked(prev);
2112 } else {
2113 if (mGoingToSleep.isHeld()) {
2114 mGoingToSleep.release();
2115 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002116 if (mShuttingDown) {
2117 notifyAll();
2118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 }
2120
2121 if (prev != null) {
2122 prev.resumeKeyDispatchingLocked();
2123 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002124
2125 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2126 long diff = 0;
2127 synchronized (mProcessStatsThread) {
2128 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2129 }
2130 if (diff > 0) {
2131 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2132 synchronized (bsi) {
2133 BatteryStatsImpl.Uid.Proc ps =
2134 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2135 prev.info.packageName);
2136 if (ps != null) {
2137 ps.addForegroundTimeLocked(diff);
2138 }
2139 }
2140 }
2141 }
2142 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 }
2144
2145 /**
2146 * Once we know that we have asked an application to put an activity in
2147 * the resumed state (either by launching it or explicitly telling it),
2148 * this function updates the rest of our state to match that fact.
2149 */
2150 private final void completeResumeLocked(HistoryRecord next) {
2151 next.idle = false;
2152 next.results = null;
2153 next.newIntents = null;
2154
2155 // schedule an idle timeout in case the app doesn't do it for us.
2156 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2157 msg.obj = next;
2158 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2159
2160 if (false) {
2161 // The activity was never told to pause, so just keep
2162 // things going as-is. To maintain our own state,
2163 // we need to emulate it coming back and saying it is
2164 // idle.
2165 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2166 msg.obj = next;
2167 mHandler.sendMessage(msg);
2168 }
2169
2170 next.thumbnail = null;
2171 setFocusedActivityLocked(next);
2172 next.resumeKeyDispatchingLocked();
2173 ensureActivitiesVisibleLocked(null, 0);
2174 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002175
2176 // Mark the point when the activity is resuming
2177 // TODO: To be more accurate, the mark should be before the onCreate,
2178 // not after the onResume. But for subsequent starts, onResume is fine.
2179 if (next.app != null) {
2180 synchronized (mProcessStatsThread) {
2181 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2182 }
2183 } else {
2184 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 }
2187
2188 /**
2189 * Make sure that all activities that need to be visible (that is, they
2190 * currently can be seen by the user) actually are.
2191 */
2192 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2193 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2194 if (DEBUG_VISBILITY) Log.v(
2195 TAG, "ensureActivitiesVisible behind " + top
2196 + " configChanges=0x" + Integer.toHexString(configChanges));
2197
2198 // If the top activity is not fullscreen, then we need to
2199 // make sure any activities under it are now visible.
2200 final int count = mHistory.size();
2201 int i = count-1;
2202 while (mHistory.get(i) != top) {
2203 i--;
2204 }
2205 HistoryRecord r;
2206 boolean behindFullscreen = false;
2207 for (; i>=0; i--) {
2208 r = (HistoryRecord)mHistory.get(i);
2209 if (DEBUG_VISBILITY) Log.v(
2210 TAG, "Make visible? " + r + " finishing=" + r.finishing
2211 + " state=" + r.state);
2212 if (r.finishing) {
2213 continue;
2214 }
2215
2216 final boolean doThisProcess = onlyThisProcess == null
2217 || onlyThisProcess.equals(r.processName);
2218
2219 // First: if this is not the current activity being started, make
2220 // sure it matches the current configuration.
2221 if (r != starting && doThisProcess) {
2222 ensureActivityConfigurationLocked(r, 0);
2223 }
2224
2225 if (r.app == null || r.app.thread == null) {
2226 if (onlyThisProcess == null
2227 || onlyThisProcess.equals(r.processName)) {
2228 // This activity needs to be visible, but isn't even
2229 // running... get it started, but don't resume it
2230 // at this point.
2231 if (DEBUG_VISBILITY) Log.v(
2232 TAG, "Start and freeze screen for " + r);
2233 if (r != starting) {
2234 r.startFreezingScreenLocked(r.app, configChanges);
2235 }
2236 if (!r.visible) {
2237 if (DEBUG_VISBILITY) Log.v(
2238 TAG, "Starting and making visible: " + r);
2239 mWindowManager.setAppVisibility(r, true);
2240 }
2241 if (r != starting) {
2242 startSpecificActivityLocked(r, false, false);
2243 }
2244 }
2245
2246 } else if (r.visible) {
2247 // If this activity is already visible, then there is nothing
2248 // else to do here.
2249 if (DEBUG_VISBILITY) Log.v(
2250 TAG, "Skipping: already visible at " + r);
2251 r.stopFreezingScreenLocked(false);
2252
2253 } else if (onlyThisProcess == null) {
2254 // This activity is not currently visible, but is running.
2255 // Tell it to become visible.
2256 r.visible = true;
2257 if (r.state != ActivityState.RESUMED && r != starting) {
2258 // If this activity is paused, tell it
2259 // to now show its window.
2260 if (DEBUG_VISBILITY) Log.v(
2261 TAG, "Making visible and scheduling visibility: " + r);
2262 try {
2263 mWindowManager.setAppVisibility(r, true);
2264 r.app.thread.scheduleWindowVisibility(r, true);
2265 r.stopFreezingScreenLocked(false);
2266 } catch (Exception e) {
2267 // Just skip on any failure; we'll make it
2268 // visible when it next restarts.
2269 Log.w(TAG, "Exception thrown making visibile: "
2270 + r.intent.getComponent(), e);
2271 }
2272 }
2273 }
2274
2275 // Aggregate current change flags.
2276 configChanges |= r.configChangeFlags;
2277
2278 if (r.fullscreen) {
2279 // At this point, nothing else needs to be shown
2280 if (DEBUG_VISBILITY) Log.v(
2281 TAG, "Stopping: fullscreen at " + r);
2282 behindFullscreen = true;
2283 i--;
2284 break;
2285 }
2286 }
2287
2288 // Now for any activities that aren't visible to the user, make
2289 // sure they no longer are keeping the screen frozen.
2290 while (i >= 0) {
2291 r = (HistoryRecord)mHistory.get(i);
2292 if (DEBUG_VISBILITY) Log.v(
2293 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2294 + " state=" + r.state
2295 + " behindFullscreen=" + behindFullscreen);
2296 if (!r.finishing) {
2297 if (behindFullscreen) {
2298 if (r.visible) {
2299 if (DEBUG_VISBILITY) Log.v(
2300 TAG, "Making invisible: " + r);
2301 r.visible = false;
2302 try {
2303 mWindowManager.setAppVisibility(r, false);
2304 if ((r.state == ActivityState.STOPPING
2305 || r.state == ActivityState.STOPPED)
2306 && r.app != null && r.app.thread != null) {
2307 if (DEBUG_VISBILITY) Log.v(
2308 TAG, "Scheduling invisibility: " + r);
2309 r.app.thread.scheduleWindowVisibility(r, false);
2310 }
2311 } catch (Exception e) {
2312 // Just skip on any failure; we'll make it
2313 // visible when it next restarts.
2314 Log.w(TAG, "Exception thrown making hidden: "
2315 + r.intent.getComponent(), e);
2316 }
2317 } else {
2318 if (DEBUG_VISBILITY) Log.v(
2319 TAG, "Already invisible: " + r);
2320 }
2321 } else if (r.fullscreen) {
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Now behindFullscreen: " + r);
2324 behindFullscreen = true;
2325 }
2326 }
2327 i--;
2328 }
2329 }
2330
2331 /**
2332 * Version of ensureActivitiesVisible that can easily be called anywhere.
2333 */
2334 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2335 int configChanges) {
2336 HistoryRecord r = topRunningActivityLocked(null);
2337 if (r != null) {
2338 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2339 }
2340 }
2341
2342 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2343 if (resumed) {
2344 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2345 } else {
2346 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2347 }
2348 }
2349
2350 /**
2351 * Ensure that the top activity in the stack is resumed.
2352 *
2353 * @param prev The previously resumed activity, for when in the process
2354 * of pausing; can be null to call from elsewhere.
2355 *
2356 * @return Returns true if something is being resumed, or false if
2357 * nothing happened.
2358 */
2359 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2360 // Find the first activity that is not finishing.
2361 HistoryRecord next = topRunningActivityLocked(null);
2362
2363 // Remember how we'll process this pause/resume situation, and ensure
2364 // that the state is reset however we wind up proceeding.
2365 final boolean userLeaving = mUserLeaving;
2366 mUserLeaving = false;
2367
2368 if (next == null) {
2369 // There are no more activities! Let's just start up the
2370 // Launcher...
2371 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2372 && mTopAction == null) {
2373 // We are running in factory test mode, but unable to find
2374 // the factory test app, so just sit around displaying the
2375 // error message and don't try to start anything.
2376 return false;
2377 }
2378 Intent intent = new Intent(
2379 mTopAction,
2380 mTopData != null ? Uri.parse(mTopData) : null);
2381 intent.setComponent(mTopComponent);
2382 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2383 intent.addCategory(Intent.CATEGORY_HOME);
2384 }
2385 ActivityInfo aInfo =
2386 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002387 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002388 if (aInfo != null) {
2389 intent.setComponent(new ComponentName(
2390 aInfo.applicationInfo.packageName, aInfo.name));
2391 // Don't do this if the home app is currently being
2392 // instrumented.
2393 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2394 aInfo.applicationInfo.uid);
2395 if (app == null || app.instrumentationClass == null) {
2396 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2397 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002398 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 }
2400 }
2401 return true;
2402 }
2403
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002404 next.delayedResume = false;
2405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002406 // If the top activity is the resumed one, nothing to do.
2407 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2408 // Make sure we have executed any pending transitions, since there
2409 // should be nothing left to do at this point.
2410 mWindowManager.executeAppTransition();
2411 return false;
2412 }
2413
2414 // If we are sleeping, and there is no resumed activity, and the top
2415 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002416 if ((mSleeping || mShuttingDown)
2417 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002418 // Make sure we have executed any pending transitions, since there
2419 // should be nothing left to do at this point.
2420 mWindowManager.executeAppTransition();
2421 return false;
2422 }
2423
2424 // The activity may be waiting for stop, but that is no longer
2425 // appropriate for it.
2426 mStoppingActivities.remove(next);
2427 mWaitingVisibleActivities.remove(next);
2428
2429 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2430
2431 // If we are currently pausing an activity, then don't do anything
2432 // until that is done.
2433 if (mPausingActivity != null) {
2434 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2435 return false;
2436 }
2437
2438 // We need to start pausing the current activity so the top one
2439 // can be resumed...
2440 if (mResumedActivity != null) {
2441 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2442 startPausingLocked(userLeaving, false);
2443 return true;
2444 }
2445
2446 if (prev != null && prev != next) {
2447 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2448 prev.waitingVisible = true;
2449 mWaitingVisibleActivities.add(prev);
2450 if (DEBUG_SWITCH) Log.v(
2451 TAG, "Resuming top, waiting visible to hide: " + prev);
2452 } else {
2453 // The next activity is already visible, so hide the previous
2454 // activity's windows right now so we can show the new one ASAP.
2455 // We only do this if the previous is finishing, which should mean
2456 // it is on top of the one being resumed so hiding it quickly
2457 // is good. Otherwise, we want to do the normal route of allowing
2458 // the resumed activity to be shown so we can decide if the
2459 // previous should actually be hidden depending on whether the
2460 // new one is found to be full-screen or not.
2461 if (prev.finishing) {
2462 mWindowManager.setAppVisibility(prev, false);
2463 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2464 + prev + ", waitingVisible="
2465 + (prev != null ? prev.waitingVisible : null)
2466 + ", nowVisible=" + next.nowVisible);
2467 } else {
2468 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2469 + prev + ", waitingVisible="
2470 + (prev != null ? prev.waitingVisible : null)
2471 + ", nowVisible=" + next.nowVisible);
2472 }
2473 }
2474 }
2475
2476 // We are starting up the next activity, so tell the window manager
2477 // that the previous one will be hidden soon. This way it can know
2478 // to ignore it when computing the desired screen orientation.
2479 if (prev != null) {
2480 if (prev.finishing) {
2481 if (DEBUG_TRANSITION) Log.v(TAG,
2482 "Prepare close transition: prev=" + prev);
2483 mWindowManager.prepareAppTransition(prev.task == next.task
2484 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2485 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2486 mWindowManager.setAppWillBeHidden(prev);
2487 mWindowManager.setAppVisibility(prev, false);
2488 } else {
2489 if (DEBUG_TRANSITION) Log.v(TAG,
2490 "Prepare open transition: prev=" + prev);
2491 mWindowManager.prepareAppTransition(prev.task == next.task
2492 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2493 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2494 }
2495 if (false) {
2496 mWindowManager.setAppWillBeHidden(prev);
2497 mWindowManager.setAppVisibility(prev, false);
2498 }
2499 } else if (mHistory.size() > 1) {
2500 if (DEBUG_TRANSITION) Log.v(TAG,
2501 "Prepare open transition: no previous");
2502 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2503 }
2504
2505 if (next.app != null && next.app.thread != null) {
2506 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2507
2508 // This activity is now becoming visible.
2509 mWindowManager.setAppVisibility(next, true);
2510
2511 HistoryRecord lastResumedActivity = mResumedActivity;
2512 ActivityState lastState = next.state;
2513
2514 updateCpuStats();
2515
2516 next.state = ActivityState.RESUMED;
2517 mResumedActivity = next;
2518 next.task.touchActiveTime();
2519 updateLRUListLocked(next.app, true);
2520 updateLRUListLocked(next);
2521
2522 // Have the window manager re-evaluate the orientation of
2523 // the screen based on the new activity order.
2524 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002525 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 next.mayFreezeScreenLocked(next.app) ? next : null);
2527 if (config != null) {
2528 next.frozenBeforeDestroy = true;
2529 }
2530 if (!updateConfigurationLocked(config, next)) {
2531 // The configuration update wasn't able to keep the existing
2532 // instance of the activity, and instead started a new one.
2533 // We should be all done, but let's just make sure our activity
2534 // is still at the top and schedule another run if something
2535 // weird happened.
2536 HistoryRecord nextNext = topRunningActivityLocked(null);
2537 if (DEBUG_SWITCH) Log.i(TAG,
2538 "Activity config changed during resume: " + next
2539 + ", new next: " + nextNext);
2540 if (nextNext != next) {
2541 // Do over!
2542 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2543 }
2544 mWindowManager.executeAppTransition();
2545 return true;
2546 }
2547
2548 try {
2549 // Deliver all pending results.
2550 ArrayList a = next.results;
2551 if (a != null) {
2552 final int N = a.size();
2553 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002554 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 TAG, "Delivering results to " + next
2556 + ": " + a);
2557 next.app.thread.scheduleSendResult(next, a);
2558 }
2559 }
2560
2561 if (next.newIntents != null) {
2562 next.app.thread.scheduleNewIntent(next.newIntents, next);
2563 }
2564
2565 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2566 System.identityHashCode(next),
2567 next.task.taskId, next.shortComponentName);
2568 updateUsageStats(next, true);
2569
2570 next.app.thread.scheduleResumeActivity(next,
2571 isNextTransitionForward());
2572 pauseIfSleepingLocked();
2573
2574 } catch (Exception e) {
2575 // Whoops, need to restart this activity!
2576 next.state = lastState;
2577 mResumedActivity = lastResumedActivity;
2578 if (Config.LOGD) Log.d(TAG,
2579 "Restarting because process died: " + next);
2580 if (!next.hasBeenLaunched) {
2581 next.hasBeenLaunched = true;
2582 } else {
2583 if (SHOW_APP_STARTING_ICON) {
2584 mWindowManager.setAppStartingWindow(
2585 next, next.packageName, next.theme,
2586 next.nonLocalizedLabel,
2587 next.labelRes, next.icon, null, true);
2588 }
2589 }
2590 startSpecificActivityLocked(next, true, false);
2591 return true;
2592 }
2593
2594 // From this point on, if something goes wrong there is no way
2595 // to recover the activity.
2596 try {
2597 next.visible = true;
2598 completeResumeLocked(next);
2599 } catch (Exception e) {
2600 // If any exception gets thrown, toss away this
2601 // activity and try the next one.
2602 Log.w(TAG, "Exception thrown during resume of " + next, e);
2603 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2604 "resume-exception");
2605 return true;
2606 }
2607
2608 // Didn't need to use the icicle, and it is now out of date.
2609 next.icicle = null;
2610 next.haveState = false;
2611 next.stopped = false;
2612
2613 } else {
2614 // Whoops, need to restart this activity!
2615 if (!next.hasBeenLaunched) {
2616 next.hasBeenLaunched = true;
2617 } else {
2618 if (SHOW_APP_STARTING_ICON) {
2619 mWindowManager.setAppStartingWindow(
2620 next, next.packageName, next.theme,
2621 next.nonLocalizedLabel,
2622 next.labelRes, next.icon, null, true);
2623 }
2624 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2625 }
2626 startSpecificActivityLocked(next, true, true);
2627 }
2628
2629 return true;
2630 }
2631
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002632 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2633 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002634 final int NH = mHistory.size();
2635
2636 int addPos = -1;
2637
2638 if (!newTask) {
2639 // If starting in an existing task, find where that is...
2640 HistoryRecord next = null;
2641 boolean startIt = true;
2642 for (int i = NH-1; i >= 0; i--) {
2643 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2644 if (p.finishing) {
2645 continue;
2646 }
2647 if (p.task == r.task) {
2648 // Here it is! Now, if this is not yet visible to the
2649 // user, then just add it without starting; it will
2650 // get started when the user navigates back to it.
2651 addPos = i+1;
2652 if (!startIt) {
2653 mHistory.add(addPos, r);
2654 r.inHistory = true;
2655 r.task.numActivities++;
2656 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2657 r.info.screenOrientation, r.fullscreen);
2658 if (VALIDATE_TOKENS) {
2659 mWindowManager.validateAppTokens(mHistory);
2660 }
2661 return;
2662 }
2663 break;
2664 }
2665 if (p.fullscreen) {
2666 startIt = false;
2667 }
2668 next = p;
2669 }
2670 }
2671
2672 // Place a new activity at top of stack, so it is next to interact
2673 // with the user.
2674 if (addPos < 0) {
2675 addPos = mHistory.size();
2676 }
2677
2678 // If we are not placing the new activity frontmost, we do not want
2679 // to deliver the onUserLeaving callback to the actual frontmost
2680 // activity
2681 if (addPos < NH) {
2682 mUserLeaving = false;
2683 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2684 }
2685
2686 // Slot the activity into the history stack and proceed
2687 mHistory.add(addPos, r);
2688 r.inHistory = true;
2689 r.frontOfTask = newTask;
2690 r.task.numActivities++;
2691 if (NH > 0) {
2692 // We want to show the starting preview window if we are
2693 // switching to a new task, or the next activity's process is
2694 // not currently running.
2695 boolean showStartingIcon = newTask;
2696 ProcessRecord proc = r.app;
2697 if (proc == null) {
2698 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2699 }
2700 if (proc == null || proc.thread == null) {
2701 showStartingIcon = true;
2702 }
2703 if (DEBUG_TRANSITION) Log.v(TAG,
2704 "Prepare open transition: starting " + r);
2705 mWindowManager.prepareAppTransition(newTask
2706 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2707 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2708 mWindowManager.addAppToken(
2709 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2710 boolean doShow = true;
2711 if (newTask) {
2712 // Even though this activity is starting fresh, we still need
2713 // to reset it to make sure we apply affinities to move any
2714 // existing activities from other tasks in to it.
2715 // If the caller has requested that the target task be
2716 // reset, then do so.
2717 if ((r.intent.getFlags()
2718 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2719 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002720 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002721 }
2722 }
2723 if (SHOW_APP_STARTING_ICON && doShow) {
2724 // Figure out if we are transitioning from another activity that is
2725 // "has the same starting icon" as the next one. This allows the
2726 // window manager to keep the previous window it had previously
2727 // created, if it still had one.
2728 HistoryRecord prev = mResumedActivity;
2729 if (prev != null) {
2730 // We don't want to reuse the previous starting preview if:
2731 // (1) The current activity is in a different task.
2732 if (prev.task != r.task) prev = null;
2733 // (2) The current activity is already displayed.
2734 else if (prev.nowVisible) prev = null;
2735 }
2736 mWindowManager.setAppStartingWindow(
2737 r, r.packageName, r.theme, r.nonLocalizedLabel,
2738 r.labelRes, r.icon, prev, showStartingIcon);
2739 }
2740 } else {
2741 // If this is the first activity, don't do any fancy animations,
2742 // because there is nothing for it to animate on top of.
2743 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2744 r.info.screenOrientation, r.fullscreen);
2745 }
2746 if (VALIDATE_TOKENS) {
2747 mWindowManager.validateAppTokens(mHistory);
2748 }
2749
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002750 if (doResume) {
2751 resumeTopActivityLocked(null);
2752 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753 }
2754
2755 /**
2756 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002757 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2758 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002759 * an instance of that activity in the stack and, if found, finish all
2760 * activities on top of it and return the instance.
2761 *
2762 * @param newR Description of the new activity being started.
2763 * @return Returns the old activity that should be continue to be used,
2764 * or null if none was found.
2765 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002766 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 HistoryRecord newR, boolean doClear) {
2768 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002769
2770 // First find the requested task.
2771 while (i > 0) {
2772 i--;
2773 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2774 if (r.task.taskId == taskId) {
2775 i++;
2776 break;
2777 }
2778 }
2779
2780 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 while (i > 0) {
2782 i--;
2783 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2784 if (r.finishing) {
2785 continue;
2786 }
2787 if (r.task.taskId != taskId) {
2788 return null;
2789 }
2790 if (r.realActivity.equals(newR.realActivity)) {
2791 // Here it is! Now finish everything in front...
2792 HistoryRecord ret = r;
2793 if (doClear) {
2794 while (i < (mHistory.size()-1)) {
2795 i++;
2796 r = (HistoryRecord)mHistory.get(i);
2797 if (r.finishing) {
2798 continue;
2799 }
2800 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2801 null, "clear")) {
2802 i--;
2803 }
2804 }
2805 }
2806
2807 // Finally, if this is a normal launch mode (that is, not
2808 // expecting onNewIntent()), then we will finish the current
2809 // instance of the activity so a new fresh one can be started.
2810 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2811 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002812 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002813 if (index >= 0) {
2814 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2815 null, "clear");
2816 }
2817 return null;
2818 }
2819 }
2820
2821 return ret;
2822 }
2823 }
2824
2825 return null;
2826 }
2827
2828 /**
2829 * Find the activity in the history stack within the given task. Returns
2830 * the index within the history at which it's found, or < 0 if not found.
2831 */
2832 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2833 int i = mHistory.size();
2834 while (i > 0) {
2835 i--;
2836 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2837 if (candidate.task.taskId != task) {
2838 break;
2839 }
2840 if (candidate.realActivity.equals(r.realActivity)) {
2841 return i;
2842 }
2843 }
2844
2845 return -1;
2846 }
2847
2848 /**
2849 * Reorder the history stack so that the activity at the given index is
2850 * brought to the front.
2851 */
2852 private final HistoryRecord moveActivityToFrontLocked(int where) {
2853 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2854 int top = mHistory.size();
2855 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2856 mHistory.add(top, newTop);
2857 oldTop.frontOfTask = false;
2858 newTop.frontOfTask = true;
2859 return newTop;
2860 }
2861
2862 /**
2863 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2864 * method will be called at the proper time.
2865 */
2866 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2867 boolean sent = false;
2868 if (r.state == ActivityState.RESUMED
2869 && r.app != null && r.app.thread != null) {
2870 try {
2871 ArrayList<Intent> ar = new ArrayList<Intent>();
2872 ar.add(new Intent(intent));
2873 r.app.thread.scheduleNewIntent(ar, r);
2874 sent = true;
2875 } catch (Exception e) {
2876 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2877 }
2878 }
2879 if (!sent) {
2880 r.addNewIntentLocked(new Intent(intent));
2881 }
2882 }
2883
2884 private final void logStartActivity(int tag, HistoryRecord r,
2885 TaskRecord task) {
2886 EventLog.writeEvent(tag,
2887 System.identityHashCode(r), task.taskId,
2888 r.shortComponentName, r.intent.getAction(),
2889 r.intent.getType(), r.intent.getDataString(),
2890 r.intent.getFlags());
2891 }
2892
2893 private final int startActivityLocked(IApplicationThread caller,
2894 Intent intent, String resolvedType,
2895 Uri[] grantedUriPermissions,
2896 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2897 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002898 int callingPid, int callingUid, boolean onlyIfNeeded,
2899 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002900 Log.i(TAG, "Starting activity: " + intent);
2901
2902 HistoryRecord sourceRecord = null;
2903 HistoryRecord resultRecord = null;
2904 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002905 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002906 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002907 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2908 if (index >= 0) {
2909 sourceRecord = (HistoryRecord)mHistory.get(index);
2910 if (requestCode >= 0 && !sourceRecord.finishing) {
2911 resultRecord = sourceRecord;
2912 }
2913 }
2914 }
2915
2916 int launchFlags = intent.getFlags();
2917
2918 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2919 && sourceRecord != null) {
2920 // Transfer the result target from the source activity to the new
2921 // one being started, including any failures.
2922 if (requestCode >= 0) {
2923 return START_FORWARD_AND_REQUEST_CONFLICT;
2924 }
2925 resultRecord = sourceRecord.resultTo;
2926 resultWho = sourceRecord.resultWho;
2927 requestCode = sourceRecord.requestCode;
2928 sourceRecord.resultTo = null;
2929 if (resultRecord != null) {
2930 resultRecord.removeResultsLocked(
2931 sourceRecord, resultWho, requestCode);
2932 }
2933 }
2934
2935 int err = START_SUCCESS;
2936
2937 if (intent.getComponent() == null) {
2938 // We couldn't find a class that can handle the given Intent.
2939 // That's the end of that!
2940 err = START_INTENT_NOT_RESOLVED;
2941 }
2942
2943 if (err == START_SUCCESS && aInfo == null) {
2944 // We couldn't find the specific class specified in the Intent.
2945 // Also the end of the line.
2946 err = START_CLASS_NOT_FOUND;
2947 }
2948
2949 ProcessRecord callerApp = null;
2950 if (err == START_SUCCESS && caller != null) {
2951 callerApp = getRecordForAppLocked(caller);
2952 if (callerApp != null) {
2953 callingPid = callerApp.pid;
2954 callingUid = callerApp.info.uid;
2955 } else {
2956 Log.w(TAG, "Unable to find app for caller " + caller
2957 + " (pid=" + callingPid + ") when starting: "
2958 + intent.toString());
2959 err = START_PERMISSION_DENIED;
2960 }
2961 }
2962
2963 if (err != START_SUCCESS) {
2964 if (resultRecord != null) {
2965 sendActivityResultLocked(-1,
2966 resultRecord, resultWho, requestCode,
2967 Activity.RESULT_CANCELED, null);
2968 }
2969 return err;
2970 }
2971
2972 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2973 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2974 if (perm != PackageManager.PERMISSION_GRANTED) {
2975 if (resultRecord != null) {
2976 sendActivityResultLocked(-1,
2977 resultRecord, resultWho, requestCode,
2978 Activity.RESULT_CANCELED, null);
2979 }
2980 String msg = "Permission Denial: starting " + intent.toString()
2981 + " from " + callerApp + " (pid=" + callingPid
2982 + ", uid=" + callingUid + ")"
2983 + " requires " + aInfo.permission;
2984 Log.w(TAG, msg);
2985 throw new SecurityException(msg);
2986 }
2987
2988 if (mWatcher != null) {
2989 boolean abort = false;
2990 try {
2991 // The Intent we give to the watcher has the extra data
2992 // stripped off, since it can contain private information.
2993 Intent watchIntent = intent.cloneFilter();
2994 abort = !mWatcher.activityStarting(watchIntent,
2995 aInfo.applicationInfo.packageName);
2996 } catch (RemoteException e) {
2997 mWatcher = null;
2998 }
2999
3000 if (abort) {
3001 if (resultRecord != null) {
3002 sendActivityResultLocked(-1,
3003 resultRecord, resultWho, requestCode,
3004 Activity.RESULT_CANCELED, null);
3005 }
3006 // We pretend to the caller that it was really started, but
3007 // they will just get a cancel result.
3008 return START_SUCCESS;
3009 }
3010 }
3011
3012 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3013 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003014 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003015
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003016 if (mResumedActivity == null
3017 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3018 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3019 PendingActivityLaunch pal = new PendingActivityLaunch();
3020 pal.r = r;
3021 pal.sourceRecord = sourceRecord;
3022 pal.grantedUriPermissions = grantedUriPermissions;
3023 pal.grantedMode = grantedMode;
3024 pal.onlyIfNeeded = onlyIfNeeded;
3025 mPendingActivityLaunches.add(pal);
3026 return START_SWITCHES_CANCELED;
3027 }
3028 }
3029
3030 if (mDidAppSwitch) {
3031 // This is the second allowed switch since we stopped switches,
3032 // so now just generally allow switches. Use case: user presses
3033 // home (switches disabled, switch to home, mDidAppSwitch now true);
3034 // user taps a home icon (coming from home so allowed, we hit here
3035 // and now allow anyone to switch again).
3036 mAppSwitchesAllowedTime = 0;
3037 } else {
3038 mDidAppSwitch = true;
3039 }
3040
3041 doPendingActivityLaunchesLocked(false);
3042
3043 return startActivityUncheckedLocked(r, sourceRecord,
3044 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3045 }
3046
3047 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3048 final int N = mPendingActivityLaunches.size();
3049 if (N <= 0) {
3050 return;
3051 }
3052 for (int i=0; i<N; i++) {
3053 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3054 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3055 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3056 doResume && i == (N-1));
3057 }
3058 mPendingActivityLaunches.clear();
3059 }
3060
3061 private final int startActivityUncheckedLocked(HistoryRecord r,
3062 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3063 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3064 final Intent intent = r.intent;
3065 final int callingUid = r.launchedFromUid;
3066
3067 int launchFlags = intent.getFlags();
3068
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 // We'll invoke onUserLeaving before onPause only if the launching
3070 // activity did not explicitly state that this is an automated launch.
3071 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3072 if (DEBUG_USER_LEAVING) Log.v(TAG,
3073 "startActivity() => mUserLeaving=" + mUserLeaving);
3074
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003075 // If the caller has asked not to resume at this point, we make note
3076 // of this in the record so that we can skip it when trying to find
3077 // the top running activity.
3078 if (!doResume) {
3079 r.delayedResume = true;
3080 }
3081
3082 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3083 != 0 ? r : null;
3084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085 // If the onlyIfNeeded flag is set, then we can do this if the activity
3086 // being launched is the same as the one making the call... or, as
3087 // a special case, if we do not know the caller then we count the
3088 // current top activity as the caller.
3089 if (onlyIfNeeded) {
3090 HistoryRecord checkedCaller = sourceRecord;
3091 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003092 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 }
3094 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3095 // Caller is not the same as launcher, so always needed.
3096 onlyIfNeeded = false;
3097 }
3098 }
3099
3100 if (grantedUriPermissions != null && callingUid > 0) {
3101 for (int i=0; i<grantedUriPermissions.length; i++) {
3102 grantUriPermissionLocked(callingUid, r.packageName,
3103 grantedUriPermissions[i], grantedMode, r);
3104 }
3105 }
3106
3107 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3108 intent, r);
3109
3110 if (sourceRecord == null) {
3111 // This activity is not being started from another... in this
3112 // case we -always- start a new task.
3113 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3114 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3115 + intent);
3116 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3117 }
3118 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3119 // The original activity who is starting us is running as a single
3120 // instance... this new activity it is starting must go on its
3121 // own task.
3122 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3123 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3124 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3125 // The activity being started is a single instance... it always
3126 // gets launched into its own task.
3127 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3128 }
3129
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003130 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003131 // For whatever reason this activity is being launched into a new
3132 // task... yet the caller has requested a result back. Well, that
3133 // is pretty messed up, so instead immediately send back a cancel
3134 // and let the new task continue launched as normal without a
3135 // dependency on its originator.
3136 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3137 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003138 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003139 Activity.RESULT_CANCELED, null);
3140 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 }
3142
3143 boolean addingToTask = false;
3144 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3145 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3146 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3147 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3148 // If bring to front is requested, and no result is requested, and
3149 // we can find a task that was started with this same
3150 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003151 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 // See if there is a task to bring to the front. If this is
3153 // a SINGLE_INSTANCE activity, there can be one and only one
3154 // instance of it in the history, and it is always in its own
3155 // unique task, so we do a special search.
3156 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3157 ? findTaskLocked(intent, r.info)
3158 : findActivityLocked(intent, r.info);
3159 if (taskTop != null) {
3160 if (taskTop.task.intent == null) {
3161 // This task was started because of movement of
3162 // the activity based on affinity... now that we
3163 // are actually launching it, we can assign the
3164 // base intent.
3165 taskTop.task.setIntent(intent, r.info);
3166 }
3167 // If the target task is not in the front, then we need
3168 // to bring it to the front... except... well, with
3169 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3170 // to have the same behavior as if a new instance was
3171 // being started, which means not bringing it to the front
3172 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003173 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003174 if (curTop.task != taskTop.task) {
3175 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3176 boolean callerAtFront = sourceRecord == null
3177 || curTop.task == sourceRecord.task;
3178 if (callerAtFront) {
3179 // We really do want to push this one into the
3180 // user's face, right now.
3181 moveTaskToFrontLocked(taskTop.task);
3182 }
3183 }
3184 // If the caller has requested that the target task be
3185 // reset, then do so.
3186 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3187 taskTop = resetTaskIfNeededLocked(taskTop, r);
3188 }
3189 if (onlyIfNeeded) {
3190 // We don't need to start a new activity, and
3191 // the client said not to do anything if that
3192 // is the case, so this is it! And for paranoia, make
3193 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003194 if (doResume) {
3195 resumeTopActivityLocked(null);
3196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 return START_RETURN_INTENT_TO_CALLER;
3198 }
3199 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3200 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3201 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3202 // In this situation we want to remove all activities
3203 // from the task up to the one being started. In most
3204 // cases this means we are resetting the task to its
3205 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003206 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 taskTop.task.taskId, r, true);
3208 if (top != null) {
3209 if (top.frontOfTask) {
3210 // Activity aliases may mean we use different
3211 // intents for the top activity, so make sure
3212 // the task now has the identity of the new
3213 // intent.
3214 top.task.setIntent(r.intent, r.info);
3215 }
3216 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3217 deliverNewIntentLocked(top, r.intent);
3218 } else {
3219 // A special case: we need to
3220 // start the activity because it is not currently
3221 // running, and the caller has asked to clear the
3222 // current task to have this activity at the top.
3223 addingToTask = true;
3224 // Now pretend like this activity is being started
3225 // by the top of its task, so it is put in the
3226 // right place.
3227 sourceRecord = taskTop;
3228 }
3229 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3230 // In this case the top activity on the task is the
3231 // same as the one being launched, so we take that
3232 // as a request to bring the task to the foreground.
3233 // If the top activity in the task is the root
3234 // activity, deliver this new intent to it if it
3235 // desires.
3236 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3237 && taskTop.realActivity.equals(r.realActivity)) {
3238 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3239 if (taskTop.frontOfTask) {
3240 taskTop.task.setIntent(r.intent, r.info);
3241 }
3242 deliverNewIntentLocked(taskTop, r.intent);
3243 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3244 // In this case we are launching the root activity
3245 // of the task, but with a different intent. We
3246 // should start a new instance on top.
3247 addingToTask = true;
3248 sourceRecord = taskTop;
3249 }
3250 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3251 // In this case an activity is being launched in to an
3252 // existing task, without resetting that task. This
3253 // is typically the situation of launching an activity
3254 // from a notification or shortcut. We want to place
3255 // the new activity on top of the current task.
3256 addingToTask = true;
3257 sourceRecord = taskTop;
3258 } else if (!taskTop.task.rootWasReset) {
3259 // In this case we are launching in to an existing task
3260 // that has not yet been started from its front door.
3261 // The current task has been brought to the front.
3262 // Ideally, we'd probably like to place this new task
3263 // at the bottom of its stack, but that's a little hard
3264 // to do with the current organization of the code so
3265 // for now we'll just drop it.
3266 taskTop.task.setIntent(r.intent, r.info);
3267 }
3268 if (!addingToTask) {
3269 // We didn't do anything... but it was needed (a.k.a., client
3270 // don't use that intent!) And for paranoia, make
3271 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003272 if (doResume) {
3273 resumeTopActivityLocked(null);
3274 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 return START_TASK_TO_FRONT;
3276 }
3277 }
3278 }
3279 }
3280
3281 //String uri = r.intent.toURI();
3282 //Intent intent2 = new Intent(uri);
3283 //Log.i(TAG, "Given intent: " + r.intent);
3284 //Log.i(TAG, "URI is: " + uri);
3285 //Log.i(TAG, "To intent: " + intent2);
3286
3287 if (r.packageName != null) {
3288 // If the activity being launched is the same as the one currently
3289 // at the top, then we need to check if it should only be launched
3290 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003291 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3292 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 if (top.realActivity.equals(r.realActivity)) {
3294 if (top.app != null && top.app.thread != null) {
3295 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3296 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3297 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3298 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3299 // For paranoia, make sure we have correctly
3300 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003301 if (doResume) {
3302 resumeTopActivityLocked(null);
3303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 if (onlyIfNeeded) {
3305 // We don't need to start a new activity, and
3306 // the client said not to do anything if that
3307 // is the case, so this is it!
3308 return START_RETURN_INTENT_TO_CALLER;
3309 }
3310 deliverNewIntentLocked(top, r.intent);
3311 return START_DELIVERED_TO_TOP;
3312 }
3313 }
3314 }
3315 }
3316
3317 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003318 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 Activity.RESULT_CANCELED, null);
3322 }
3323 return START_CLASS_NOT_FOUND;
3324 }
3325
3326 boolean newTask = false;
3327
3328 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003329 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3331 // todo: should do better management of integers.
3332 mCurTask++;
3333 if (mCurTask <= 0) {
3334 mCurTask = 1;
3335 }
3336 r.task = new TaskRecord(mCurTask, r.info, intent,
3337 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3338 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3339 + " in new task " + r.task);
3340 newTask = true;
3341 addRecentTask(r.task);
3342
3343 } else if (sourceRecord != null) {
3344 if (!addingToTask &&
3345 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3346 // In this case, we are adding the activity to an existing
3347 // task, but the caller has asked to clear that task if the
3348 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003349 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 sourceRecord.task.taskId, r, true);
3351 if (top != null) {
3352 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3353 deliverNewIntentLocked(top, r.intent);
3354 // For paranoia, make sure we have correctly
3355 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003356 if (doResume) {
3357 resumeTopActivityLocked(null);
3358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 return START_DELIVERED_TO_TOP;
3360 }
3361 } else if (!addingToTask &&
3362 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3363 // In this case, we are launching an activity in our own task
3364 // that may already be running somewhere in the history, and
3365 // we want to shuffle it to the front of the stack if so.
3366 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3367 if (where >= 0) {
3368 HistoryRecord top = moveActivityToFrontLocked(where);
3369 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3370 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003371 if (doResume) {
3372 resumeTopActivityLocked(null);
3373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 return START_DELIVERED_TO_TOP;
3375 }
3376 }
3377 // An existing activity is starting this new activity, so we want
3378 // to keep the new one in the same task as the one that is starting
3379 // it.
3380 r.task = sourceRecord.task;
3381 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3382 + " in existing task " + r.task);
3383
3384 } else {
3385 // This not being started from an existing activity, and not part
3386 // of a new task... just put it in the top task, though these days
3387 // this case should never happen.
3388 final int N = mHistory.size();
3389 HistoryRecord prev =
3390 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3391 r.task = prev != null
3392 ? prev.task
3393 : new TaskRecord(mCurTask, r.info, intent,
3394 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3395 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3396 + " in new guessed " + r.task);
3397 }
3398 if (newTask) {
3399 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3400 }
3401 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003402 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 return START_SUCCESS;
3404 }
3405
3406 public final int startActivity(IApplicationThread caller,
3407 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3408 int grantedMode, IBinder resultTo,
3409 String resultWho, int requestCode, boolean onlyIfNeeded,
3410 boolean debug) {
3411 // Refuse possible leaked file descriptors
3412 if (intent != null && intent.hasFileDescriptors()) {
3413 throw new IllegalArgumentException("File descriptors passed in Intent");
3414 }
3415
The Android Open Source Project4df24232009-03-05 14:34:35 -08003416 final boolean componentSpecified = intent.getComponent() != null;
3417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 // Don't modify the client's object!
3419 intent = new Intent(intent);
3420
3421 // Collect information about the target of the Intent.
3422 // Must do this before locking, because resolving the intent
3423 // may require launching a process to run its content provider.
3424 ActivityInfo aInfo;
3425 try {
3426 ResolveInfo rInfo =
3427 ActivityThread.getPackageManager().resolveIntent(
3428 intent, resolvedType,
3429 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003430 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 aInfo = rInfo != null ? rInfo.activityInfo : null;
3432 } catch (RemoteException e) {
3433 aInfo = null;
3434 }
3435
3436 if (aInfo != null) {
3437 // Store the found target back into the intent, because now that
3438 // we have it we never want to do this again. For example, if the
3439 // user navigates back to this point in the history, we should
3440 // always restart the exact same activity.
3441 intent.setComponent(new ComponentName(
3442 aInfo.applicationInfo.packageName, aInfo.name));
3443
3444 // Don't debug things in the system process
3445 if (debug) {
3446 if (!aInfo.processName.equals("system")) {
3447 setDebugApp(aInfo.processName, true, false);
3448 }
3449 }
3450 }
3451
3452 synchronized(this) {
3453 final long origId = Binder.clearCallingIdentity();
3454 int res = startActivityLocked(caller, intent, resolvedType,
3455 grantedUriPermissions, grantedMode, aInfo,
3456 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003457 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 Binder.restoreCallingIdentity(origId);
3459 return res;
3460 }
3461 }
3462
3463 public boolean startNextMatchingActivity(IBinder callingActivity,
3464 Intent intent) {
3465 // Refuse possible leaked file descriptors
3466 if (intent != null && intent.hasFileDescriptors() == true) {
3467 throw new IllegalArgumentException("File descriptors passed in Intent");
3468 }
3469
3470 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003471 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 if (index < 0) {
3473 return false;
3474 }
3475 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3476 if (r.app == null || r.app.thread == null) {
3477 // The caller is not running... d'oh!
3478 return false;
3479 }
3480 intent = new Intent(intent);
3481 // The caller is not allowed to change the data.
3482 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3483 // And we are resetting to find the next component...
3484 intent.setComponent(null);
3485
3486 ActivityInfo aInfo = null;
3487 try {
3488 List<ResolveInfo> resolves =
3489 ActivityThread.getPackageManager().queryIntentActivities(
3490 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003491 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003492
3493 // Look for the original activity in the list...
3494 final int N = resolves != null ? resolves.size() : 0;
3495 for (int i=0; i<N; i++) {
3496 ResolveInfo rInfo = resolves.get(i);
3497 if (rInfo.activityInfo.packageName.equals(r.packageName)
3498 && rInfo.activityInfo.name.equals(r.info.name)) {
3499 // We found the current one... the next matching is
3500 // after it.
3501 i++;
3502 if (i<N) {
3503 aInfo = resolves.get(i).activityInfo;
3504 }
3505 break;
3506 }
3507 }
3508 } catch (RemoteException e) {
3509 }
3510
3511 if (aInfo == null) {
3512 // Nobody who is next!
3513 return false;
3514 }
3515
3516 intent.setComponent(new ComponentName(
3517 aInfo.applicationInfo.packageName, aInfo.name));
3518 intent.setFlags(intent.getFlags()&~(
3519 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3520 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3521 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3522 Intent.FLAG_ACTIVITY_NEW_TASK));
3523
3524 // Okay now we need to start the new activity, replacing the
3525 // currently running activity. This is a little tricky because
3526 // we want to start the new one as if the current one is finished,
3527 // but not finish the current one first so that there is no flicker.
3528 // And thus...
3529 final boolean wasFinishing = r.finishing;
3530 r.finishing = true;
3531
3532 // Propagate reply information over to the new activity.
3533 final HistoryRecord resultTo = r.resultTo;
3534 final String resultWho = r.resultWho;
3535 final int requestCode = r.requestCode;
3536 r.resultTo = null;
3537 if (resultTo != null) {
3538 resultTo.removeResultsLocked(r, resultWho, requestCode);
3539 }
3540
3541 final long origId = Binder.clearCallingIdentity();
3542 // XXX we are not dealing with propagating grantedUriPermissions...
3543 // those are not yet exposed to user code, so there is no need.
3544 int res = startActivityLocked(r.app.thread, intent,
3545 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003546 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 Binder.restoreCallingIdentity(origId);
3548
3549 r.finishing = wasFinishing;
3550 if (res != START_SUCCESS) {
3551 return false;
3552 }
3553 return true;
3554 }
3555 }
3556
3557 final int startActivityInPackage(int uid,
3558 Intent intent, String resolvedType, IBinder resultTo,
3559 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003560 final boolean componentSpecified = intent.getComponent() != null;
3561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003562 // Don't modify the client's object!
3563 intent = new Intent(intent);
3564
3565 // Collect information about the target of the Intent.
3566 // Must do this before locking, because resolving the intent
3567 // may require launching a process to run its content provider.
3568 ActivityInfo aInfo;
3569 try {
3570 ResolveInfo rInfo =
3571 ActivityThread.getPackageManager().resolveIntent(
3572 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003573 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 aInfo = rInfo != null ? rInfo.activityInfo : null;
3575 } catch (RemoteException e) {
3576 aInfo = null;
3577 }
3578
3579 if (aInfo != null) {
3580 // Store the found target back into the intent, because now that
3581 // we have it we never want to do this again. For example, if the
3582 // user navigates back to this point in the history, we should
3583 // always restart the exact same activity.
3584 intent.setComponent(new ComponentName(
3585 aInfo.applicationInfo.packageName, aInfo.name));
3586 }
3587
3588 synchronized(this) {
3589 return startActivityLocked(null, intent, resolvedType,
3590 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003591 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592 }
3593 }
3594
3595 private final void addRecentTask(TaskRecord task) {
3596 // Remove any existing entries that are the same kind of task.
3597 int N = mRecentTasks.size();
3598 for (int i=0; i<N; i++) {
3599 TaskRecord tr = mRecentTasks.get(i);
3600 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3601 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3602 mRecentTasks.remove(i);
3603 i--;
3604 N--;
3605 if (task.intent == null) {
3606 // If the new recent task we are adding is not fully
3607 // specified, then replace it with the existing recent task.
3608 task = tr;
3609 }
3610 }
3611 }
3612 if (N >= MAX_RECENT_TASKS) {
3613 mRecentTasks.remove(N-1);
3614 }
3615 mRecentTasks.add(0, task);
3616 }
3617
3618 public void setRequestedOrientation(IBinder token,
3619 int requestedOrientation) {
3620 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003621 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003622 if (index < 0) {
3623 return;
3624 }
3625 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3626 final long origId = Binder.clearCallingIdentity();
3627 mWindowManager.setAppOrientation(r, requestedOrientation);
3628 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003629 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630 r.mayFreezeScreenLocked(r.app) ? r : null);
3631 if (config != null) {
3632 r.frozenBeforeDestroy = true;
3633 if (!updateConfigurationLocked(config, r)) {
3634 resumeTopActivityLocked(null);
3635 }
3636 }
3637 Binder.restoreCallingIdentity(origId);
3638 }
3639 }
3640
3641 public int getRequestedOrientation(IBinder token) {
3642 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003643 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644 if (index < 0) {
3645 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3646 }
3647 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3648 return mWindowManager.getAppOrientation(r);
3649 }
3650 }
3651
3652 private final void stopActivityLocked(HistoryRecord r) {
3653 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3654 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3655 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3656 if (!r.finishing) {
3657 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3658 "no-history");
3659 }
3660 } else if (r.app != null && r.app.thread != null) {
3661 if (mFocusedActivity == r) {
3662 setFocusedActivityLocked(topRunningActivityLocked(null));
3663 }
3664 r.resumeKeyDispatchingLocked();
3665 try {
3666 r.stopped = false;
3667 r.state = ActivityState.STOPPING;
3668 if (DEBUG_VISBILITY) Log.v(
3669 TAG, "Stopping visible=" + r.visible + " for " + r);
3670 if (!r.visible) {
3671 mWindowManager.setAppVisibility(r, false);
3672 }
3673 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3674 } catch (Exception e) {
3675 // Maybe just ignore exceptions here... if the process
3676 // has crashed, our death notification will clean things
3677 // up.
3678 Log.w(TAG, "Exception thrown during pause", e);
3679 // Just in case, assume it to be stopped.
3680 r.stopped = true;
3681 r.state = ActivityState.STOPPED;
3682 if (r.configDestroy) {
3683 destroyActivityLocked(r, true);
3684 }
3685 }
3686 }
3687 }
3688
3689 /**
3690 * @return Returns true if the activity is being finished, false if for
3691 * some reason it is being left as-is.
3692 */
3693 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3694 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003695 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003696 TAG, "Finishing activity: token=" + token
3697 + ", result=" + resultCode + ", data=" + resultData);
3698
Dianne Hackborn75b03852009-06-12 15:43:26 -07003699 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 if (index < 0) {
3701 return false;
3702 }
3703 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3704
3705 // Is this the last activity left?
3706 boolean lastActivity = true;
3707 for (int i=mHistory.size()-1; i>=0; i--) {
3708 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3709 if (!p.finishing && p != r) {
3710 lastActivity = false;
3711 break;
3712 }
3713 }
3714
3715 // If this is the last activity, but it is the home activity, then
3716 // just don't finish it.
3717 if (lastActivity) {
3718 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3719 return false;
3720 }
3721 }
3722
3723 finishActivityLocked(r, index, resultCode, resultData, reason);
3724 return true;
3725 }
3726
3727 /**
3728 * @return Returns true if this activity has been removed from the history
3729 * list, or false if it is still in the list and will be removed later.
3730 */
3731 private final boolean finishActivityLocked(HistoryRecord r, int index,
3732 int resultCode, Intent resultData, String reason) {
3733 if (r.finishing) {
3734 Log.w(TAG, "Duplicate finish request for " + r);
3735 return false;
3736 }
3737
3738 r.finishing = true;
3739 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3740 System.identityHashCode(r),
3741 r.task.taskId, r.shortComponentName, reason);
3742 r.task.numActivities--;
3743 if (r.frontOfTask && index < (mHistory.size()-1)) {
3744 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3745 if (next.task == r.task) {
3746 next.frontOfTask = true;
3747 }
3748 }
3749
3750 r.pauseKeyDispatchingLocked();
3751 if (mFocusedActivity == r) {
3752 setFocusedActivityLocked(topRunningActivityLocked(null));
3753 }
3754
3755 // send the result
3756 HistoryRecord resultTo = r.resultTo;
3757 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003758 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3759 + " who=" + r.resultWho + " req=" + r.requestCode
3760 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761 if (r.info.applicationInfo.uid > 0) {
3762 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3763 r.packageName, resultData, r);
3764 }
3765 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3766 resultData);
3767 r.resultTo = null;
3768 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003769 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770
3771 // Make sure this HistoryRecord is not holding on to other resources,
3772 // because clients have remote IPC references to this object so we
3773 // can't assume that will go away and want to avoid circular IPC refs.
3774 r.results = null;
3775 r.pendingResults = null;
3776 r.newIntents = null;
3777 r.icicle = null;
3778
3779 if (mPendingThumbnails.size() > 0) {
3780 // There are clients waiting to receive thumbnails so, in case
3781 // this is an activity that someone is waiting for, add it
3782 // to the pending list so we can correctly update the clients.
3783 mCancelledThumbnails.add(r);
3784 }
3785
3786 if (mResumedActivity == r) {
3787 boolean endTask = index <= 0
3788 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3789 if (DEBUG_TRANSITION) Log.v(TAG,
3790 "Prepare close transition: finishing " + r);
3791 mWindowManager.prepareAppTransition(endTask
3792 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3793 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3794
3795 // Tell window manager to prepare for this one to be removed.
3796 mWindowManager.setAppVisibility(r, false);
3797
3798 if (mPausingActivity == null) {
3799 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3800 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3801 startPausingLocked(false, false);
3802 }
3803
3804 } else if (r.state != ActivityState.PAUSING) {
3805 // If the activity is PAUSING, we will complete the finish once
3806 // it is done pausing; else we can just directly finish it here.
3807 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3808 return finishCurrentActivityLocked(r, index,
3809 FINISH_AFTER_PAUSE) == null;
3810 } else {
3811 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3812 }
3813
3814 return false;
3815 }
3816
3817 private static final int FINISH_IMMEDIATELY = 0;
3818 private static final int FINISH_AFTER_PAUSE = 1;
3819 private static final int FINISH_AFTER_VISIBLE = 2;
3820
3821 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3822 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003823 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003824 if (index < 0) {
3825 return null;
3826 }
3827
3828 return finishCurrentActivityLocked(r, index, mode);
3829 }
3830
3831 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3832 int index, int mode) {
3833 // First things first: if this activity is currently visible,
3834 // and the resumed activity is not yet visible, then hold off on
3835 // finishing until the resumed one becomes visible.
3836 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3837 if (!mStoppingActivities.contains(r)) {
3838 mStoppingActivities.add(r);
3839 if (mStoppingActivities.size() > 3) {
3840 // If we already have a few activities waiting to stop,
3841 // then give up on things going idle and start clearing
3842 // them out.
3843 Message msg = Message.obtain();
3844 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3845 mHandler.sendMessage(msg);
3846 }
3847 }
3848 r.state = ActivityState.STOPPING;
3849 updateOomAdjLocked();
3850 return r;
3851 }
3852
3853 // make sure the record is cleaned out of other places.
3854 mStoppingActivities.remove(r);
3855 mWaitingVisibleActivities.remove(r);
3856 if (mResumedActivity == r) {
3857 mResumedActivity = null;
3858 }
3859 final ActivityState prevState = r.state;
3860 r.state = ActivityState.FINISHING;
3861
3862 if (mode == FINISH_IMMEDIATELY
3863 || prevState == ActivityState.STOPPED
3864 || prevState == ActivityState.INITIALIZING) {
3865 // If this activity is already stopped, we can just finish
3866 // it right now.
3867 return destroyActivityLocked(r, true) ? null : r;
3868 } else {
3869 // Need to go through the full pause cycle to get this
3870 // activity into the stopped state and then finish it.
3871 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3872 mFinishingActivities.add(r);
3873 resumeTopActivityLocked(null);
3874 }
3875 return r;
3876 }
3877
3878 /**
3879 * This is the internal entry point for handling Activity.finish().
3880 *
3881 * @param token The Binder token referencing the Activity we want to finish.
3882 * @param resultCode Result code, if any, from this Activity.
3883 * @param resultData Result data (Intent), if any, from this Activity.
3884 *
3885 * @result Returns true if the activity successfully finished, or false if it is still running.
3886 */
3887 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3888 // Refuse possible leaked file descriptors
3889 if (resultData != null && resultData.hasFileDescriptors() == true) {
3890 throw new IllegalArgumentException("File descriptors passed in Intent");
3891 }
3892
3893 synchronized(this) {
3894 if (mWatcher != null) {
3895 // Find the first activity that is not finishing.
3896 HistoryRecord next = topRunningActivityLocked(token, 0);
3897 if (next != null) {
3898 // ask watcher if this is allowed
3899 boolean resumeOK = true;
3900 try {
3901 resumeOK = mWatcher.activityResuming(next.packageName);
3902 } catch (RemoteException e) {
3903 mWatcher = null;
3904 }
3905
3906 if (!resumeOK) {
3907 return false;
3908 }
3909 }
3910 }
3911 final long origId = Binder.clearCallingIdentity();
3912 boolean res = requestFinishActivityLocked(token, resultCode,
3913 resultData, "app-request");
3914 Binder.restoreCallingIdentity(origId);
3915 return res;
3916 }
3917 }
3918
3919 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3920 String resultWho, int requestCode, int resultCode, Intent data) {
3921
3922 if (callingUid > 0) {
3923 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3924 data, r);
3925 }
3926
The Android Open Source Project10592532009-03-18 17:39:46 -07003927 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3928 + " : who=" + resultWho + " req=" + requestCode
3929 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3931 try {
3932 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3933 list.add(new ResultInfo(resultWho, requestCode,
3934 resultCode, data));
3935 r.app.thread.scheduleSendResult(r, list);
3936 return;
3937 } catch (Exception e) {
3938 Log.w(TAG, "Exception thrown sending result to " + r, e);
3939 }
3940 }
3941
3942 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3943 }
3944
3945 public final void finishSubActivity(IBinder token, String resultWho,
3946 int requestCode) {
3947 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003948 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003949 if (index < 0) {
3950 return;
3951 }
3952 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3953
3954 final long origId = Binder.clearCallingIdentity();
3955
3956 int i;
3957 for (i=mHistory.size()-1; i>=0; i--) {
3958 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3959 if (r.resultTo == self && r.requestCode == requestCode) {
3960 if ((r.resultWho == null && resultWho == null) ||
3961 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3962 finishActivityLocked(r, i,
3963 Activity.RESULT_CANCELED, null, "request-sub");
3964 }
3965 }
3966 }
3967
3968 Binder.restoreCallingIdentity(origId);
3969 }
3970 }
3971
3972 /**
3973 * Perform clean-up of service connections in an activity record.
3974 */
3975 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3976 // Throw away any services that have been bound by this activity.
3977 if (r.connections != null) {
3978 Iterator<ConnectionRecord> it = r.connections.iterator();
3979 while (it.hasNext()) {
3980 ConnectionRecord c = it.next();
3981 removeConnectionLocked(c, null, r);
3982 }
3983 r.connections = null;
3984 }
3985 }
3986
3987 /**
3988 * Perform the common clean-up of an activity record. This is called both
3989 * as part of destroyActivityLocked() (when destroying the client-side
3990 * representation) and cleaning things up as a result of its hosting
3991 * processing going away, in which case there is no remaining client-side
3992 * state to destroy so only the cleanup here is needed.
3993 */
3994 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3995 if (mResumedActivity == r) {
3996 mResumedActivity = null;
3997 }
3998 if (mFocusedActivity == r) {
3999 mFocusedActivity = null;
4000 }
4001
4002 r.configDestroy = false;
4003 r.frozenBeforeDestroy = false;
4004
4005 // Make sure this record is no longer in the pending finishes list.
4006 // This could happen, for example, if we are trimming activities
4007 // down to the max limit while they are still waiting to finish.
4008 mFinishingActivities.remove(r);
4009 mWaitingVisibleActivities.remove(r);
4010
4011 // Remove any pending results.
4012 if (r.finishing && r.pendingResults != null) {
4013 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4014 PendingIntentRecord rec = apr.get();
4015 if (rec != null) {
4016 cancelIntentSenderLocked(rec, false);
4017 }
4018 }
4019 r.pendingResults = null;
4020 }
4021
4022 if (cleanServices) {
4023 cleanUpActivityServicesLocked(r);
4024 }
4025
4026 if (mPendingThumbnails.size() > 0) {
4027 // There are clients waiting to receive thumbnails so, in case
4028 // this is an activity that someone is waiting for, add it
4029 // to the pending list so we can correctly update the clients.
4030 mCancelledThumbnails.add(r);
4031 }
4032
4033 // Get rid of any pending idle timeouts.
4034 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4035 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4036 }
4037
4038 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4039 if (r.state != ActivityState.DESTROYED) {
4040 mHistory.remove(r);
4041 r.inHistory = false;
4042 r.state = ActivityState.DESTROYED;
4043 mWindowManager.removeAppToken(r);
4044 if (VALIDATE_TOKENS) {
4045 mWindowManager.validateAppTokens(mHistory);
4046 }
4047 cleanUpActivityServicesLocked(r);
4048 removeActivityUriPermissionsLocked(r);
4049 }
4050 }
4051
4052 /**
4053 * Destroy the current CLIENT SIDE instance of an activity. This may be
4054 * called both when actually finishing an activity, or when performing
4055 * a configuration switch where we destroy the current client-side object
4056 * but then create a new client-side object for this same HistoryRecord.
4057 */
4058 private final boolean destroyActivityLocked(HistoryRecord r,
4059 boolean removeFromApp) {
4060 if (DEBUG_SWITCH) Log.v(
4061 TAG, "Removing activity: token=" + r
4062 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4063 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4064 System.identityHashCode(r),
4065 r.task.taskId, r.shortComponentName);
4066
4067 boolean removedFromHistory = false;
4068
4069 cleanUpActivityLocked(r, false);
4070
4071 if (r.app != null) {
4072 if (removeFromApp) {
4073 int idx = r.app.activities.indexOf(r);
4074 if (idx >= 0) {
4075 r.app.activities.remove(idx);
4076 }
4077 if (r.persistent) {
4078 decPersistentCountLocked(r.app);
4079 }
4080 }
4081
4082 boolean skipDestroy = false;
4083
4084 try {
4085 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4086 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4087 r.configChangeFlags);
4088 } catch (Exception e) {
4089 // We can just ignore exceptions here... if the process
4090 // has crashed, our death notification will clean things
4091 // up.
4092 //Log.w(TAG, "Exception thrown during finish", e);
4093 if (r.finishing) {
4094 removeActivityFromHistoryLocked(r);
4095 removedFromHistory = true;
4096 skipDestroy = true;
4097 }
4098 }
4099
4100 r.app = null;
4101 r.nowVisible = false;
4102
4103 if (r.finishing && !skipDestroy) {
4104 r.state = ActivityState.DESTROYING;
4105 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4106 msg.obj = r;
4107 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4108 } else {
4109 r.state = ActivityState.DESTROYED;
4110 }
4111 } else {
4112 // remove this record from the history.
4113 if (r.finishing) {
4114 removeActivityFromHistoryLocked(r);
4115 removedFromHistory = true;
4116 } else {
4117 r.state = ActivityState.DESTROYED;
4118 }
4119 }
4120
4121 r.configChangeFlags = 0;
4122
4123 if (!mLRUActivities.remove(r)) {
4124 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4125 }
4126
4127 return removedFromHistory;
4128 }
4129
4130 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4131 ProcessRecord app)
4132 {
4133 int i = list.size();
4134 if (localLOGV) Log.v(
4135 TAG, "Removing app " + app + " from list " + list
4136 + " with " + i + " entries");
4137 while (i > 0) {
4138 i--;
4139 HistoryRecord r = (HistoryRecord)list.get(i);
4140 if (localLOGV) Log.v(
4141 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4142 if (r.app == app) {
4143 if (localLOGV) Log.v(TAG, "Removing this entry!");
4144 list.remove(i);
4145 }
4146 }
4147 }
4148
4149 /**
4150 * Main function for removing an existing process from the activity manager
4151 * as a result of that process going away. Clears out all connections
4152 * to the process.
4153 */
4154 private final void handleAppDiedLocked(ProcessRecord app,
4155 boolean restarting) {
4156 cleanUpApplicationRecordLocked(app, restarting, -1);
4157 if (!restarting) {
4158 mLRUProcesses.remove(app);
4159 }
4160
4161 // Just in case...
4162 if (mPausingActivity != null && mPausingActivity.app == app) {
4163 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4164 mPausingActivity = null;
4165 }
4166 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4167 mLastPausedActivity = null;
4168 }
4169
4170 // Remove this application's activities from active lists.
4171 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4172 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4173 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4174 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4175
4176 boolean atTop = true;
4177 boolean hasVisibleActivities = false;
4178
4179 // Clean out the history list.
4180 int i = mHistory.size();
4181 if (localLOGV) Log.v(
4182 TAG, "Removing app " + app + " from history with " + i + " entries");
4183 while (i > 0) {
4184 i--;
4185 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4186 if (localLOGV) Log.v(
4187 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4188 if (r.app == app) {
4189 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4190 if (localLOGV) Log.v(
4191 TAG, "Removing this entry! frozen=" + r.haveState
4192 + " finishing=" + r.finishing);
4193 mHistory.remove(i);
4194
4195 r.inHistory = false;
4196 mWindowManager.removeAppToken(r);
4197 if (VALIDATE_TOKENS) {
4198 mWindowManager.validateAppTokens(mHistory);
4199 }
4200 removeActivityUriPermissionsLocked(r);
4201
4202 } else {
4203 // We have the current state for this activity, so
4204 // it can be restarted later when needed.
4205 if (localLOGV) Log.v(
4206 TAG, "Keeping entry, setting app to null");
4207 if (r.visible) {
4208 hasVisibleActivities = true;
4209 }
4210 r.app = null;
4211 r.nowVisible = false;
4212 if (!r.haveState) {
4213 r.icicle = null;
4214 }
4215 }
4216
4217 cleanUpActivityLocked(r, true);
4218 r.state = ActivityState.STOPPED;
4219 }
4220 atTop = false;
4221 }
4222
4223 app.activities.clear();
4224
4225 if (app.instrumentationClass != null) {
4226 Log.w(TAG, "Crash of app " + app.processName
4227 + " running instrumentation " + app.instrumentationClass);
4228 Bundle info = new Bundle();
4229 info.putString("shortMsg", "Process crashed.");
4230 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4231 }
4232
4233 if (!restarting) {
4234 if (!resumeTopActivityLocked(null)) {
4235 // If there was nothing to resume, and we are not already
4236 // restarting this process, but there is a visible activity that
4237 // is hosted by the process... then make sure all visible
4238 // activities are running, taking care of restarting this
4239 // process.
4240 if (hasVisibleActivities) {
4241 ensureActivitiesVisibleLocked(null, 0);
4242 }
4243 }
4244 }
4245 }
4246
4247 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4248 IBinder threadBinder = thread.asBinder();
4249
4250 // Find the application record.
4251 int count = mLRUProcesses.size();
4252 int i;
4253 for (i=0; i<count; i++) {
4254 ProcessRecord rec = mLRUProcesses.get(i);
4255 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4256 return i;
4257 }
4258 }
4259 return -1;
4260 }
4261
4262 private final ProcessRecord getRecordForAppLocked(
4263 IApplicationThread thread) {
4264 if (thread == null) {
4265 return null;
4266 }
4267
4268 int appIndex = getLRURecordIndexForAppLocked(thread);
4269 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4270 }
4271
4272 private final void appDiedLocked(ProcessRecord app, int pid,
4273 IApplicationThread thread) {
4274
4275 mProcDeaths[0]++;
4276
4277 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4278 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4279 + ") has died.");
4280 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4281 if (localLOGV) Log.v(
4282 TAG, "Dying app: " + app + ", pid: " + pid
4283 + ", thread: " + thread.asBinder());
4284 boolean doLowMem = app.instrumentationClass == null;
4285 handleAppDiedLocked(app, false);
4286
4287 if (doLowMem) {
4288 // If there are no longer any background processes running,
4289 // and the app that died was not running instrumentation,
4290 // then tell everyone we are now low on memory.
4291 boolean haveBg = false;
4292 int count = mLRUProcesses.size();
4293 int i;
4294 for (i=0; i<count; i++) {
4295 ProcessRecord rec = mLRUProcesses.get(i);
4296 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4297 haveBg = true;
4298 break;
4299 }
4300 }
4301
4302 if (!haveBg) {
4303 Log.i(TAG, "Low Memory: No more background processes.");
4304 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4305 for (i=0; i<count; i++) {
4306 ProcessRecord rec = mLRUProcesses.get(i);
4307 if (rec.thread != null) {
4308 rec.lastRequestedGc = SystemClock.uptimeMillis();
4309 try {
4310 rec.thread.scheduleLowMemory();
4311 } catch (RemoteException e) {
4312 // Don't care if the process is gone.
4313 }
4314 }
4315 }
4316 }
4317 }
4318 } else if (Config.LOGD) {
4319 Log.d(TAG, "Received spurious death notification for thread "
4320 + thread.asBinder());
4321 }
4322 }
4323
4324 final String readFile(String filename) {
4325 try {
4326 FileInputStream fs = new FileInputStream(filename);
4327 byte[] inp = new byte[8192];
4328 int size = fs.read(inp);
4329 fs.close();
4330 return new String(inp, 0, 0, size);
4331 } catch (java.io.IOException e) {
4332 }
4333 return "";
4334 }
4335
4336 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4337 final String annotation) {
4338 if (app.notResponding || app.crashing) {
4339 return;
4340 }
4341
4342 // Log the ANR to the event log.
4343 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4344
4345 // If we are on a secure build and the application is not interesting to the user (it is
4346 // not visible or in the background), just kill it instead of displaying a dialog.
4347 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4348 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4349 Process.killProcess(app.pid);
4350 return;
4351 }
4352
4353 // DeviceMonitor.start();
4354
4355 String processInfo = null;
4356 if (MONITOR_CPU_USAGE) {
4357 updateCpuStatsNow();
4358 synchronized (mProcessStatsThread) {
4359 processInfo = mProcessStats.printCurrentState();
4360 }
4361 }
4362
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004363 StringBuilder info = mStringBuilder;
4364 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004365 info.append("ANR (application not responding) in process: ");
4366 info.append(app.processName);
4367 if (annotation != null) {
4368 info.append("\nAnnotation: ");
4369 info.append(annotation);
4370 }
4371 if (MONITOR_CPU_USAGE) {
4372 info.append("\nCPU usage:\n");
4373 info.append(processInfo);
4374 }
4375 Log.i(TAG, info.toString());
4376
4377 // The application is not responding. Dump as many thread traces as we can.
4378 boolean fileDump = prepareTraceFile(true);
4379 if (!fileDump) {
4380 // Dumping traces to the log, just dump the process that isn't responding so
4381 // we don't overflow the log
4382 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4383 } else {
4384 // Dumping traces to a file so dump all active processes we know about
4385 synchronized (this) {
4386 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4387 ProcessRecord r = mLRUProcesses.get(i);
4388 if (r.thread != null) {
4389 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4390 }
4391 }
4392 }
4393 }
4394
4395 if (mWatcher != null) {
4396 try {
4397 int res = mWatcher.appNotResponding(app.processName,
4398 app.pid, info.toString());
4399 if (res != 0) {
4400 if (res < 0) {
4401 // wait until the SIGQUIT has had a chance to process before killing the
4402 // process.
4403 try {
4404 wait(2000);
4405 } catch (InterruptedException e) {
4406 }
4407
4408 Process.killProcess(app.pid);
4409 return;
4410 }
4411 }
4412 } catch (RemoteException e) {
4413 mWatcher = null;
4414 }
4415 }
4416
4417 makeAppNotRespondingLocked(app,
4418 activity != null ? activity.shortComponentName : null,
4419 annotation != null ? "ANR " + annotation : "ANR",
4420 info.toString(), null);
4421 Message msg = Message.obtain();
4422 HashMap map = new HashMap();
4423 msg.what = SHOW_NOT_RESPONDING_MSG;
4424 msg.obj = map;
4425 map.put("app", app);
4426 if (activity != null) {
4427 map.put("activity", activity);
4428 }
4429
4430 mHandler.sendMessage(msg);
4431 return;
4432 }
4433
4434 /**
4435 * If a stack trace file has been configured, prepare the filesystem
4436 * by creating the directory if it doesn't exist and optionally
4437 * removing the old trace file.
4438 *
4439 * @param removeExisting If set, the existing trace file will be removed.
4440 * @return Returns true if the trace file preparations succeeded
4441 */
4442 public static boolean prepareTraceFile(boolean removeExisting) {
4443 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4444 boolean fileReady = false;
4445 if (!TextUtils.isEmpty(tracesPath)) {
4446 File f = new File(tracesPath);
4447 if (!f.exists()) {
4448 // Ensure the enclosing directory exists
4449 File dir = f.getParentFile();
4450 if (!dir.exists()) {
4451 fileReady = dir.mkdirs();
4452 FileUtils.setPermissions(dir.getAbsolutePath(),
4453 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4454 } else if (dir.isDirectory()) {
4455 fileReady = true;
4456 }
4457 } else if (removeExisting) {
4458 // Remove the previous traces file, so we don't fill the disk.
4459 // The VM will recreate it
4460 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4461 fileReady = f.delete();
4462 }
4463 }
4464
4465 return fileReady;
4466 }
4467
4468
4469 private final void decPersistentCountLocked(ProcessRecord app)
4470 {
4471 app.persistentActivities--;
4472 if (app.persistentActivities > 0) {
4473 // Still more of 'em...
4474 return;
4475 }
4476 if (app.persistent) {
4477 // Ah, but the application itself is persistent. Whatever!
4478 return;
4479 }
4480
4481 // App is no longer persistent... make sure it and the ones
4482 // following it in the LRU list have the correc oom_adj.
4483 updateOomAdjLocked();
4484 }
4485
4486 public void setPersistent(IBinder token, boolean isPersistent) {
4487 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4488 != PackageManager.PERMISSION_GRANTED) {
4489 String msg = "Permission Denial: setPersistent() from pid="
4490 + Binder.getCallingPid()
4491 + ", uid=" + Binder.getCallingUid()
4492 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4493 Log.w(TAG, msg);
4494 throw new SecurityException(msg);
4495 }
4496
4497 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004498 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004499 if (index < 0) {
4500 return;
4501 }
4502 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4503 ProcessRecord app = r.app;
4504
4505 if (localLOGV) Log.v(
4506 TAG, "Setting persistence " + isPersistent + ": " + r);
4507
4508 if (isPersistent) {
4509 if (r.persistent) {
4510 // Okay okay, I heard you already!
4511 if (localLOGV) Log.v(TAG, "Already persistent!");
4512 return;
4513 }
4514 r.persistent = true;
4515 app.persistentActivities++;
4516 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4517 if (app.persistentActivities > 1) {
4518 // We aren't the first...
4519 if (localLOGV) Log.v(TAG, "Not the first!");
4520 return;
4521 }
4522 if (app.persistent) {
4523 // This would be redundant.
4524 if (localLOGV) Log.v(TAG, "App is persistent!");
4525 return;
4526 }
4527
4528 // App is now persistent... make sure it and the ones
4529 // following it now have the correct oom_adj.
4530 final long origId = Binder.clearCallingIdentity();
4531 updateOomAdjLocked();
4532 Binder.restoreCallingIdentity(origId);
4533
4534 } else {
4535 if (!r.persistent) {
4536 // Okay okay, I heard you already!
4537 return;
4538 }
4539 r.persistent = false;
4540 final long origId = Binder.clearCallingIdentity();
4541 decPersistentCountLocked(app);
4542 Binder.restoreCallingIdentity(origId);
4543
4544 }
4545 }
4546 }
4547
4548 public boolean clearApplicationUserData(final String packageName,
4549 final IPackageDataObserver observer) {
4550 int uid = Binder.getCallingUid();
4551 int pid = Binder.getCallingPid();
4552 long callingId = Binder.clearCallingIdentity();
4553 try {
4554 IPackageManager pm = ActivityThread.getPackageManager();
4555 int pkgUid = -1;
4556 synchronized(this) {
4557 try {
4558 pkgUid = pm.getPackageUid(packageName);
4559 } catch (RemoteException e) {
4560 }
4561 if (pkgUid == -1) {
4562 Log.w(TAG, "Invalid packageName:" + packageName);
4563 return false;
4564 }
4565 if (uid == pkgUid || checkComponentPermission(
4566 android.Manifest.permission.CLEAR_APP_USER_DATA,
4567 pid, uid, -1)
4568 == PackageManager.PERMISSION_GRANTED) {
4569 restartPackageLocked(packageName, pkgUid);
4570 } else {
4571 throw new SecurityException(pid+" does not have permission:"+
4572 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4573 "for process:"+packageName);
4574 }
4575 }
4576
4577 try {
4578 //clear application user data
4579 pm.clearApplicationUserData(packageName, observer);
4580 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4581 Uri.fromParts("package", packageName, null));
4582 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4583 broadcastIntentLocked(null, null, intent,
4584 null, null, 0, null, null, null,
4585 false, false, MY_PID, Process.SYSTEM_UID);
4586 } catch (RemoteException e) {
4587 }
4588 } finally {
4589 Binder.restoreCallingIdentity(callingId);
4590 }
4591 return true;
4592 }
4593
4594 public void restartPackage(final String packageName) {
4595 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4596 != PackageManager.PERMISSION_GRANTED) {
4597 String msg = "Permission Denial: restartPackage() from pid="
4598 + Binder.getCallingPid()
4599 + ", uid=" + Binder.getCallingUid()
4600 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4601 Log.w(TAG, msg);
4602 throw new SecurityException(msg);
4603 }
4604
4605 long callingId = Binder.clearCallingIdentity();
4606 try {
4607 IPackageManager pm = ActivityThread.getPackageManager();
4608 int pkgUid = -1;
4609 synchronized(this) {
4610 try {
4611 pkgUid = pm.getPackageUid(packageName);
4612 } catch (RemoteException e) {
4613 }
4614 if (pkgUid == -1) {
4615 Log.w(TAG, "Invalid packageName: " + packageName);
4616 return;
4617 }
4618 restartPackageLocked(packageName, pkgUid);
4619 }
4620 } finally {
4621 Binder.restoreCallingIdentity(callingId);
4622 }
4623 }
4624
4625 private void restartPackageLocked(final String packageName, int uid) {
4626 uninstallPackageLocked(packageName, uid, false);
4627 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4628 Uri.fromParts("package", packageName, null));
4629 intent.putExtra(Intent.EXTRA_UID, uid);
4630 broadcastIntentLocked(null, null, intent,
4631 null, null, 0, null, null, null,
4632 false, false, MY_PID, Process.SYSTEM_UID);
4633 }
4634
4635 private final void uninstallPackageLocked(String name, int uid,
4636 boolean callerWillRestart) {
4637 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4638
4639 int i, N;
4640
4641 final String procNamePrefix = name + ":";
4642 if (uid < 0) {
4643 try {
4644 uid = ActivityThread.getPackageManager().getPackageUid(name);
4645 } catch (RemoteException e) {
4646 }
4647 }
4648
4649 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4650 while (badApps.hasNext()) {
4651 SparseArray<Long> ba = badApps.next();
4652 if (ba.get(uid) != null) {
4653 badApps.remove();
4654 }
4655 }
4656
4657 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4658
4659 // Remove all processes this package may have touched: all with the
4660 // same UID (except for the system or root user), and all whose name
4661 // matches the package name.
4662 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4663 final int NA = apps.size();
4664 for (int ia=0; ia<NA; ia++) {
4665 ProcessRecord app = apps.valueAt(ia);
4666 if (app.removed) {
4667 procs.add(app);
4668 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4669 || app.processName.equals(name)
4670 || app.processName.startsWith(procNamePrefix)) {
4671 app.removed = true;
4672 procs.add(app);
4673 }
4674 }
4675 }
4676
4677 N = procs.size();
4678 for (i=0; i<N; i++) {
4679 removeProcessLocked(procs.get(i), callerWillRestart);
4680 }
4681
4682 for (i=mHistory.size()-1; i>=0; i--) {
4683 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4684 if (r.packageName.equals(name)) {
4685 if (Config.LOGD) Log.d(
4686 TAG, " Force finishing activity "
4687 + r.intent.getComponent().flattenToShortString());
4688 if (r.app != null) {
4689 r.app.removed = true;
4690 }
4691 r.app = null;
4692 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4693 }
4694 }
4695
4696 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4697 for (ServiceRecord service : mServices.values()) {
4698 if (service.packageName.equals(name)) {
4699 if (service.app != null) {
4700 service.app.removed = true;
4701 }
4702 service.app = null;
4703 services.add(service);
4704 }
4705 }
4706
4707 N = services.size();
4708 for (i=0; i<N; i++) {
4709 bringDownServiceLocked(services.get(i), true);
4710 }
4711
4712 resumeTopActivityLocked(null);
4713 }
4714
4715 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4716 final String name = app.processName;
4717 final int uid = app.info.uid;
4718 if (Config.LOGD) Log.d(
4719 TAG, "Force removing process " + app + " (" + name
4720 + "/" + uid + ")");
4721
4722 mProcessNames.remove(name, uid);
4723 boolean needRestart = false;
4724 if (app.pid > 0 && app.pid != MY_PID) {
4725 int pid = app.pid;
4726 synchronized (mPidsSelfLocked) {
4727 mPidsSelfLocked.remove(pid);
4728 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4729 }
4730 handleAppDiedLocked(app, true);
4731 mLRUProcesses.remove(app);
4732 Process.killProcess(pid);
4733
4734 if (app.persistent) {
4735 if (!callerWillRestart) {
4736 addAppLocked(app.info);
4737 } else {
4738 needRestart = true;
4739 }
4740 }
4741 } else {
4742 mRemovedProcesses.add(app);
4743 }
4744
4745 return needRestart;
4746 }
4747
4748 private final void processStartTimedOutLocked(ProcessRecord app) {
4749 final int pid = app.pid;
4750 boolean gone = false;
4751 synchronized (mPidsSelfLocked) {
4752 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4753 if (knownApp != null && knownApp.thread == null) {
4754 mPidsSelfLocked.remove(pid);
4755 gone = true;
4756 }
4757 }
4758
4759 if (gone) {
4760 Log.w(TAG, "Process " + app + " failed to attach");
4761 mProcessNames.remove(app.processName, app.info.uid);
4762 Process.killProcess(pid);
4763 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4764 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4765 mPendingBroadcast = null;
4766 scheduleBroadcastsLocked();
4767 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004768 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4769 Log.w(TAG, "Unattached app died before backup, skipping");
4770 try {
4771 IBackupManager bm = IBackupManager.Stub.asInterface(
4772 ServiceManager.getService(Context.BACKUP_SERVICE));
4773 bm.agentDisconnected(app.info.packageName);
4774 } catch (RemoteException e) {
4775 // Can't happen; the backup manager is local
4776 }
4777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004778 } else {
4779 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4780 }
4781 }
4782
4783 private final boolean attachApplicationLocked(IApplicationThread thread,
4784 int pid) {
4785
4786 // Find the application record that is being attached... either via
4787 // the pid if we are running in multiple processes, or just pull the
4788 // next app record if we are emulating process with anonymous threads.
4789 ProcessRecord app;
4790 if (pid != MY_PID && pid >= 0) {
4791 synchronized (mPidsSelfLocked) {
4792 app = mPidsSelfLocked.get(pid);
4793 }
4794 } else if (mStartingProcesses.size() > 0) {
4795 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004796 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004797 } else {
4798 app = null;
4799 }
4800
4801 if (app == null) {
4802 Log.w(TAG, "No pending application record for pid " + pid
4803 + " (IApplicationThread " + thread + "); dropping process");
4804 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4805 if (pid > 0 && pid != MY_PID) {
4806 Process.killProcess(pid);
4807 } else {
4808 try {
4809 thread.scheduleExit();
4810 } catch (Exception e) {
4811 // Ignore exceptions.
4812 }
4813 }
4814 return false;
4815 }
4816
4817 // If this application record is still attached to a previous
4818 // process, clean it up now.
4819 if (app.thread != null) {
4820 handleAppDiedLocked(app, true);
4821 }
4822
4823 // Tell the process all about itself.
4824
4825 if (localLOGV) Log.v(
4826 TAG, "Binding process pid " + pid + " to record " + app);
4827
4828 String processName = app.processName;
4829 try {
4830 thread.asBinder().linkToDeath(new AppDeathRecipient(
4831 app, pid, thread), 0);
4832 } catch (RemoteException e) {
4833 app.resetPackageList();
4834 startProcessLocked(app, "link fail", processName);
4835 return false;
4836 }
4837
4838 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4839
4840 app.thread = thread;
4841 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004842 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004843 app.forcingToForeground = null;
4844 app.foregroundServices = false;
4845 app.debugging = false;
4846
4847 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4848
4849 List providers = generateApplicationProvidersLocked(app);
4850
4851 if (localLOGV) Log.v(
4852 TAG, "New app record " + app
4853 + " thread=" + thread.asBinder() + " pid=" + pid);
4854 try {
4855 int testMode = IApplicationThread.DEBUG_OFF;
4856 if (mDebugApp != null && mDebugApp.equals(processName)) {
4857 testMode = mWaitForDebugger
4858 ? IApplicationThread.DEBUG_WAIT
4859 : IApplicationThread.DEBUG_ON;
4860 app.debugging = true;
4861 if (mDebugTransient) {
4862 mDebugApp = mOrigDebugApp;
4863 mWaitForDebugger = mOrigWaitForDebugger;
4864 }
4865 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004866 // If the app is being launched for restore or full backup, set it up specially
4867 boolean isRestrictedBackupMode = false;
4868 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4869 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4870 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4871 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004872 ensurePackageDexOpt(app.instrumentationInfo != null
4873 ? app.instrumentationInfo.packageName
4874 : app.info.packageName);
4875 if (app.instrumentationClass != null) {
4876 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004877 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004878 thread.bindApplication(processName, app.instrumentationInfo != null
4879 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004880 app.instrumentationClass, app.instrumentationProfileFile,
4881 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004882 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004883 updateLRUListLocked(app, false);
4884 app.lastRequestedGc = SystemClock.uptimeMillis();
4885 } catch (Exception e) {
4886 // todo: Yikes! What should we do? For now we will try to
4887 // start another process, but that could easily get us in
4888 // an infinite loop of restarting processes...
4889 Log.w(TAG, "Exception thrown during bind!", e);
4890
4891 app.resetPackageList();
4892 startProcessLocked(app, "bind fail", processName);
4893 return false;
4894 }
4895
4896 // Remove this record from the list of starting applications.
4897 mPersistentStartingProcesses.remove(app);
4898 mProcessesOnHold.remove(app);
4899
4900 boolean badApp = false;
4901 boolean didSomething = false;
4902
4903 // See if the top visible activity is waiting to run in this process...
4904 HistoryRecord hr = topRunningActivityLocked(null);
4905 if (hr != null) {
4906 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4907 && processName.equals(hr.processName)) {
4908 try {
4909 if (realStartActivityLocked(hr, app, true, true)) {
4910 didSomething = true;
4911 }
4912 } catch (Exception e) {
4913 Log.w(TAG, "Exception in new application when starting activity "
4914 + hr.intent.getComponent().flattenToShortString(), e);
4915 badApp = true;
4916 }
4917 } else {
4918 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4919 }
4920 }
4921
4922 // Find any services that should be running in this process...
4923 if (!badApp && mPendingServices.size() > 0) {
4924 ServiceRecord sr = null;
4925 try {
4926 for (int i=0; i<mPendingServices.size(); i++) {
4927 sr = mPendingServices.get(i);
4928 if (app.info.uid != sr.appInfo.uid
4929 || !processName.equals(sr.processName)) {
4930 continue;
4931 }
4932
4933 mPendingServices.remove(i);
4934 i--;
4935 realStartServiceLocked(sr, app);
4936 didSomething = true;
4937 }
4938 } catch (Exception e) {
4939 Log.w(TAG, "Exception in new application when starting service "
4940 + sr.shortName, e);
4941 badApp = true;
4942 }
4943 }
4944
4945 // Check if the next broadcast receiver is in this process...
4946 BroadcastRecord br = mPendingBroadcast;
4947 if (!badApp && br != null && br.curApp == app) {
4948 try {
4949 mPendingBroadcast = null;
4950 processCurBroadcastLocked(br, app);
4951 didSomething = true;
4952 } catch (Exception e) {
4953 Log.w(TAG, "Exception in new application when starting receiver "
4954 + br.curComponent.flattenToShortString(), e);
4955 badApp = true;
4956 logBroadcastReceiverDiscard(br);
4957 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4958 br.resultExtras, br.resultAbort, true);
4959 scheduleBroadcastsLocked();
4960 }
4961 }
4962
Christopher Tate181fafa2009-05-14 11:12:14 -07004963 // Check whether the next backup agent is in this process...
4964 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4965 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004966 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07004967 try {
4968 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4969 } catch (Exception e) {
4970 Log.w(TAG, "Exception scheduling backup agent creation: ");
4971 e.printStackTrace();
4972 }
4973 }
4974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004975 if (badApp) {
4976 // todo: Also need to kill application to deal with all
4977 // kinds of exceptions.
4978 handleAppDiedLocked(app, false);
4979 return false;
4980 }
4981
4982 if (!didSomething) {
4983 updateOomAdjLocked();
4984 }
4985
4986 return true;
4987 }
4988
4989 public final void attachApplication(IApplicationThread thread) {
4990 synchronized (this) {
4991 int callingPid = Binder.getCallingPid();
4992 final long origId = Binder.clearCallingIdentity();
4993 attachApplicationLocked(thread, callingPid);
4994 Binder.restoreCallingIdentity(origId);
4995 }
4996 }
4997
4998 public final void activityIdle(IBinder token) {
4999 final long origId = Binder.clearCallingIdentity();
5000 activityIdleInternal(token, false);
5001 Binder.restoreCallingIdentity(origId);
5002 }
5003
5004 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5005 boolean remove) {
5006 int N = mStoppingActivities.size();
5007 if (N <= 0) return null;
5008
5009 ArrayList<HistoryRecord> stops = null;
5010
5011 final boolean nowVisible = mResumedActivity != null
5012 && mResumedActivity.nowVisible
5013 && !mResumedActivity.waitingVisible;
5014 for (int i=0; i<N; i++) {
5015 HistoryRecord s = mStoppingActivities.get(i);
5016 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5017 + nowVisible + " waitingVisible=" + s.waitingVisible
5018 + " finishing=" + s.finishing);
5019 if (s.waitingVisible && nowVisible) {
5020 mWaitingVisibleActivities.remove(s);
5021 s.waitingVisible = false;
5022 if (s.finishing) {
5023 // If this activity is finishing, it is sitting on top of
5024 // everyone else but we now know it is no longer needed...
5025 // so get rid of it. Otherwise, we need to go through the
5026 // normal flow and hide it once we determine that it is
5027 // hidden by the activities in front of it.
5028 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5029 mWindowManager.setAppVisibility(s, false);
5030 }
5031 }
5032 if (!s.waitingVisible && remove) {
5033 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5034 if (stops == null) {
5035 stops = new ArrayList<HistoryRecord>();
5036 }
5037 stops.add(s);
5038 mStoppingActivities.remove(i);
5039 N--;
5040 i--;
5041 }
5042 }
5043
5044 return stops;
5045 }
5046
5047 void enableScreenAfterBoot() {
5048 mWindowManager.enableScreenAfterBoot();
5049 }
5050
5051 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5052 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5053
5054 ArrayList<HistoryRecord> stops = null;
5055 ArrayList<HistoryRecord> finishes = null;
5056 ArrayList<HistoryRecord> thumbnails = null;
5057 int NS = 0;
5058 int NF = 0;
5059 int NT = 0;
5060 IApplicationThread sendThumbnail = null;
5061 boolean booting = false;
5062 boolean enableScreen = false;
5063
5064 synchronized (this) {
5065 if (token != null) {
5066 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5067 }
5068
5069 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005070 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005071 if (index >= 0) {
5072 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5073
5074 // No longer need to keep the device awake.
5075 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5076 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5077 mLaunchingActivity.release();
5078 }
5079
5080 // We are now idle. If someone is waiting for a thumbnail from
5081 // us, we can now deliver.
5082 r.idle = true;
5083 scheduleAppGcsLocked();
5084 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5085 sendThumbnail = r.app.thread;
5086 r.thumbnailNeeded = false;
5087 }
5088
5089 // If this activity is fullscreen, set up to hide those under it.
5090
5091 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5092 ensureActivitiesVisibleLocked(null, 0);
5093
5094 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5095 if (!mBooted && !fromTimeout) {
5096 mBooted = true;
5097 enableScreen = true;
5098 }
5099 }
5100
5101 // Atomically retrieve all of the other things to do.
5102 stops = processStoppingActivitiesLocked(true);
5103 NS = stops != null ? stops.size() : 0;
5104 if ((NF=mFinishingActivities.size()) > 0) {
5105 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5106 mFinishingActivities.clear();
5107 }
5108 if ((NT=mCancelledThumbnails.size()) > 0) {
5109 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5110 mCancelledThumbnails.clear();
5111 }
5112
5113 booting = mBooting;
5114 mBooting = false;
5115 }
5116
5117 int i;
5118
5119 // Send thumbnail if requested.
5120 if (sendThumbnail != null) {
5121 try {
5122 sendThumbnail.requestThumbnail(token);
5123 } catch (Exception e) {
5124 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5125 sendPendingThumbnail(null, token, null, null, true);
5126 }
5127 }
5128
5129 // Stop any activities that are scheduled to do so but have been
5130 // waiting for the next one to start.
5131 for (i=0; i<NS; i++) {
5132 HistoryRecord r = (HistoryRecord)stops.get(i);
5133 synchronized (this) {
5134 if (r.finishing) {
5135 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5136 } else {
5137 stopActivityLocked(r);
5138 }
5139 }
5140 }
5141
5142 // Finish any activities that are scheduled to do so but have been
5143 // waiting for the next one to start.
5144 for (i=0; i<NF; i++) {
5145 HistoryRecord r = (HistoryRecord)finishes.get(i);
5146 synchronized (this) {
5147 destroyActivityLocked(r, true);
5148 }
5149 }
5150
5151 // Report back to any thumbnail receivers.
5152 for (i=0; i<NT; i++) {
5153 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5154 sendPendingThumbnail(r, null, null, null, true);
5155 }
5156
5157 if (booting) {
5158 // Ensure that any processes we had put on hold are now started
5159 // up.
5160 final int NP = mProcessesOnHold.size();
5161 if (NP > 0) {
5162 ArrayList<ProcessRecord> procs =
5163 new ArrayList<ProcessRecord>(mProcessesOnHold);
5164 for (int ip=0; ip<NP; ip++) {
5165 this.startProcessLocked(procs.get(ip), "on-hold", null);
5166 }
5167 }
5168 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5169 // Tell anyone interested that we are done booting!
5170 synchronized (this) {
5171 broadcastIntentLocked(null, null,
5172 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5173 null, null, 0, null, null,
5174 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5175 false, false, MY_PID, Process.SYSTEM_UID);
5176 }
5177 }
5178 }
5179
5180 trimApplications();
5181 //dump();
5182 //mWindowManager.dump();
5183
5184 if (enableScreen) {
5185 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5186 SystemClock.uptimeMillis());
5187 enableScreenAfterBoot();
5188 }
5189 }
5190
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005191 final void ensureScreenEnabled() {
5192 boolean enableScreen;
5193 synchronized (this) {
5194 enableScreen = !mBooted;
5195 mBooted = true;
5196 }
5197
5198 if (enableScreen) {
5199 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5200 SystemClock.uptimeMillis());
5201 enableScreenAfterBoot();
5202 }
5203 }
5204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005205 public final void activityPaused(IBinder token, Bundle icicle) {
5206 // Refuse possible leaked file descriptors
5207 if (icicle != null && icicle.hasFileDescriptors()) {
5208 throw new IllegalArgumentException("File descriptors passed in Bundle");
5209 }
5210
5211 final long origId = Binder.clearCallingIdentity();
5212 activityPaused(token, icicle, false);
5213 Binder.restoreCallingIdentity(origId);
5214 }
5215
5216 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5217 if (DEBUG_PAUSE) Log.v(
5218 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5219 + ", timeout=" + timeout);
5220
5221 HistoryRecord r = null;
5222
5223 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005224 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005225 if (index >= 0) {
5226 r = (HistoryRecord)mHistory.get(index);
5227 if (!timeout) {
5228 r.icicle = icicle;
5229 r.haveState = true;
5230 }
5231 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5232 if (mPausingActivity == r) {
5233 r.state = ActivityState.PAUSED;
5234 completePauseLocked();
5235 } else {
5236 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5237 System.identityHashCode(r), r.shortComponentName,
5238 mPausingActivity != null
5239 ? mPausingActivity.shortComponentName : "(none)");
5240 }
5241 }
5242 }
5243 }
5244
5245 public final void activityStopped(IBinder token, Bitmap thumbnail,
5246 CharSequence description) {
5247 if (localLOGV) Log.v(
5248 TAG, "Activity stopped: token=" + token);
5249
5250 HistoryRecord r = null;
5251
5252 final long origId = Binder.clearCallingIdentity();
5253
5254 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005255 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005256 if (index >= 0) {
5257 r = (HistoryRecord)mHistory.get(index);
5258 r.thumbnail = thumbnail;
5259 r.description = description;
5260 r.stopped = true;
5261 r.state = ActivityState.STOPPED;
5262 if (!r.finishing) {
5263 if (r.configDestroy) {
5264 destroyActivityLocked(r, true);
5265 resumeTopActivityLocked(null);
5266 }
5267 }
5268 }
5269 }
5270
5271 if (r != null) {
5272 sendPendingThumbnail(r, null, null, null, false);
5273 }
5274
5275 trimApplications();
5276
5277 Binder.restoreCallingIdentity(origId);
5278 }
5279
5280 public final void activityDestroyed(IBinder token) {
5281 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5282 synchronized (this) {
5283 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5284
Dianne Hackborn75b03852009-06-12 15:43:26 -07005285 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 if (index >= 0) {
5287 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5288 if (r.state == ActivityState.DESTROYING) {
5289 final long origId = Binder.clearCallingIdentity();
5290 removeActivityFromHistoryLocked(r);
5291 Binder.restoreCallingIdentity(origId);
5292 }
5293 }
5294 }
5295 }
5296
5297 public String getCallingPackage(IBinder token) {
5298 synchronized (this) {
5299 HistoryRecord r = getCallingRecordLocked(token);
5300 return r != null && r.app != null ? r.app.processName : null;
5301 }
5302 }
5303
5304 public ComponentName getCallingActivity(IBinder token) {
5305 synchronized (this) {
5306 HistoryRecord r = getCallingRecordLocked(token);
5307 return r != null ? r.intent.getComponent() : null;
5308 }
5309 }
5310
5311 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005312 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 if (index >= 0) {
5314 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5315 if (r != null) {
5316 return r.resultTo;
5317 }
5318 }
5319 return null;
5320 }
5321
5322 public ComponentName getActivityClassForToken(IBinder token) {
5323 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005324 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005325 if (index >= 0) {
5326 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5327 return r.intent.getComponent();
5328 }
5329 return null;
5330 }
5331 }
5332
5333 public String getPackageForToken(IBinder token) {
5334 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005335 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005336 if (index >= 0) {
5337 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5338 return r.packageName;
5339 }
5340 return null;
5341 }
5342 }
5343
5344 public IIntentSender getIntentSender(int type,
5345 String packageName, IBinder token, String resultWho,
5346 int requestCode, Intent intent, String resolvedType, int flags) {
5347 // Refuse possible leaked file descriptors
5348 if (intent != null && intent.hasFileDescriptors() == true) {
5349 throw new IllegalArgumentException("File descriptors passed in Intent");
5350 }
5351
5352 synchronized(this) {
5353 int callingUid = Binder.getCallingUid();
5354 try {
5355 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5356 Process.supportsProcesses()) {
5357 int uid = ActivityThread.getPackageManager()
5358 .getPackageUid(packageName);
5359 if (uid != Binder.getCallingUid()) {
5360 String msg = "Permission Denial: getIntentSender() from pid="
5361 + Binder.getCallingPid()
5362 + ", uid=" + Binder.getCallingUid()
5363 + ", (need uid=" + uid + ")"
5364 + " is not allowed to send as package " + packageName;
5365 Log.w(TAG, msg);
5366 throw new SecurityException(msg);
5367 }
5368 }
5369 } catch (RemoteException e) {
5370 throw new SecurityException(e);
5371 }
5372 HistoryRecord activity = null;
5373 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005374 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005375 if (index < 0) {
5376 return null;
5377 }
5378 activity = (HistoryRecord)mHistory.get(index);
5379 if (activity.finishing) {
5380 return null;
5381 }
5382 }
5383
5384 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5385 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5386 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5387 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5388 |PendingIntent.FLAG_UPDATE_CURRENT);
5389
5390 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5391 type, packageName, activity, resultWho,
5392 requestCode, intent, resolvedType, flags);
5393 WeakReference<PendingIntentRecord> ref;
5394 ref = mIntentSenderRecords.get(key);
5395 PendingIntentRecord rec = ref != null ? ref.get() : null;
5396 if (rec != null) {
5397 if (!cancelCurrent) {
5398 if (updateCurrent) {
5399 rec.key.requestIntent.replaceExtras(intent);
5400 }
5401 return rec;
5402 }
5403 rec.canceled = true;
5404 mIntentSenderRecords.remove(key);
5405 }
5406 if (noCreate) {
5407 return rec;
5408 }
5409 rec = new PendingIntentRecord(this, key, callingUid);
5410 mIntentSenderRecords.put(key, rec.ref);
5411 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5412 if (activity.pendingResults == null) {
5413 activity.pendingResults
5414 = new HashSet<WeakReference<PendingIntentRecord>>();
5415 }
5416 activity.pendingResults.add(rec.ref);
5417 }
5418 return rec;
5419 }
5420 }
5421
5422 public void cancelIntentSender(IIntentSender sender) {
5423 if (!(sender instanceof PendingIntentRecord)) {
5424 return;
5425 }
5426 synchronized(this) {
5427 PendingIntentRecord rec = (PendingIntentRecord)sender;
5428 try {
5429 int uid = ActivityThread.getPackageManager()
5430 .getPackageUid(rec.key.packageName);
5431 if (uid != Binder.getCallingUid()) {
5432 String msg = "Permission Denial: cancelIntentSender() from pid="
5433 + Binder.getCallingPid()
5434 + ", uid=" + Binder.getCallingUid()
5435 + " is not allowed to cancel packges "
5436 + rec.key.packageName;
5437 Log.w(TAG, msg);
5438 throw new SecurityException(msg);
5439 }
5440 } catch (RemoteException e) {
5441 throw new SecurityException(e);
5442 }
5443 cancelIntentSenderLocked(rec, true);
5444 }
5445 }
5446
5447 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5448 rec.canceled = true;
5449 mIntentSenderRecords.remove(rec.key);
5450 if (cleanActivity && rec.key.activity != null) {
5451 rec.key.activity.pendingResults.remove(rec.ref);
5452 }
5453 }
5454
5455 public String getPackageForIntentSender(IIntentSender pendingResult) {
5456 if (!(pendingResult instanceof PendingIntentRecord)) {
5457 return null;
5458 }
5459 synchronized(this) {
5460 try {
5461 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5462 return res.key.packageName;
5463 } catch (ClassCastException e) {
5464 }
5465 }
5466 return null;
5467 }
5468
5469 public void setProcessLimit(int max) {
5470 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5471 "setProcessLimit()");
5472 mProcessLimit = max;
5473 }
5474
5475 public int getProcessLimit() {
5476 return mProcessLimit;
5477 }
5478
5479 void foregroundTokenDied(ForegroundToken token) {
5480 synchronized (ActivityManagerService.this) {
5481 synchronized (mPidsSelfLocked) {
5482 ForegroundToken cur
5483 = mForegroundProcesses.get(token.pid);
5484 if (cur != token) {
5485 return;
5486 }
5487 mForegroundProcesses.remove(token.pid);
5488 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5489 if (pr == null) {
5490 return;
5491 }
5492 pr.forcingToForeground = null;
5493 pr.foregroundServices = false;
5494 }
5495 updateOomAdjLocked();
5496 }
5497 }
5498
5499 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5500 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5501 "setProcessForeground()");
5502 synchronized(this) {
5503 boolean changed = false;
5504
5505 synchronized (mPidsSelfLocked) {
5506 ProcessRecord pr = mPidsSelfLocked.get(pid);
5507 if (pr == null) {
5508 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5509 return;
5510 }
5511 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5512 if (oldToken != null) {
5513 oldToken.token.unlinkToDeath(oldToken, 0);
5514 mForegroundProcesses.remove(pid);
5515 pr.forcingToForeground = null;
5516 changed = true;
5517 }
5518 if (isForeground && token != null) {
5519 ForegroundToken newToken = new ForegroundToken() {
5520 public void binderDied() {
5521 foregroundTokenDied(this);
5522 }
5523 };
5524 newToken.pid = pid;
5525 newToken.token = token;
5526 try {
5527 token.linkToDeath(newToken, 0);
5528 mForegroundProcesses.put(pid, newToken);
5529 pr.forcingToForeground = token;
5530 changed = true;
5531 } catch (RemoteException e) {
5532 // If the process died while doing this, we will later
5533 // do the cleanup with the process death link.
5534 }
5535 }
5536 }
5537
5538 if (changed) {
5539 updateOomAdjLocked();
5540 }
5541 }
5542 }
5543
5544 // =========================================================
5545 // PERMISSIONS
5546 // =========================================================
5547
5548 static class PermissionController extends IPermissionController.Stub {
5549 ActivityManagerService mActivityManagerService;
5550 PermissionController(ActivityManagerService activityManagerService) {
5551 mActivityManagerService = activityManagerService;
5552 }
5553
5554 public boolean checkPermission(String permission, int pid, int uid) {
5555 return mActivityManagerService.checkPermission(permission, pid,
5556 uid) == PackageManager.PERMISSION_GRANTED;
5557 }
5558 }
5559
5560 /**
5561 * This can be called with or without the global lock held.
5562 */
5563 int checkComponentPermission(String permission, int pid, int uid,
5564 int reqUid) {
5565 // We might be performing an operation on behalf of an indirect binder
5566 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5567 // client identity accordingly before proceeding.
5568 Identity tlsIdentity = sCallerIdentity.get();
5569 if (tlsIdentity != null) {
5570 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5571 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5572 uid = tlsIdentity.uid;
5573 pid = tlsIdentity.pid;
5574 }
5575
5576 // Root, system server and our own process get to do everything.
5577 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5578 !Process.supportsProcesses()) {
5579 return PackageManager.PERMISSION_GRANTED;
5580 }
5581 // If the target requires a specific UID, always fail for others.
5582 if (reqUid >= 0 && uid != reqUid) {
5583 return PackageManager.PERMISSION_DENIED;
5584 }
5585 if (permission == null) {
5586 return PackageManager.PERMISSION_GRANTED;
5587 }
5588 try {
5589 return ActivityThread.getPackageManager()
5590 .checkUidPermission(permission, uid);
5591 } catch (RemoteException e) {
5592 // Should never happen, but if it does... deny!
5593 Log.e(TAG, "PackageManager is dead?!?", e);
5594 }
5595 return PackageManager.PERMISSION_DENIED;
5596 }
5597
5598 /**
5599 * As the only public entry point for permissions checking, this method
5600 * can enforce the semantic that requesting a check on a null global
5601 * permission is automatically denied. (Internally a null permission
5602 * string is used when calling {@link #checkComponentPermission} in cases
5603 * when only uid-based security is needed.)
5604 *
5605 * This can be called with or without the global lock held.
5606 */
5607 public int checkPermission(String permission, int pid, int uid) {
5608 if (permission == null) {
5609 return PackageManager.PERMISSION_DENIED;
5610 }
5611 return checkComponentPermission(permission, pid, uid, -1);
5612 }
5613
5614 /**
5615 * Binder IPC calls go through the public entry point.
5616 * This can be called with or without the global lock held.
5617 */
5618 int checkCallingPermission(String permission) {
5619 return checkPermission(permission,
5620 Binder.getCallingPid(),
5621 Binder.getCallingUid());
5622 }
5623
5624 /**
5625 * This can be called with or without the global lock held.
5626 */
5627 void enforceCallingPermission(String permission, String func) {
5628 if (checkCallingPermission(permission)
5629 == PackageManager.PERMISSION_GRANTED) {
5630 return;
5631 }
5632
5633 String msg = "Permission Denial: " + func + " from pid="
5634 + Binder.getCallingPid()
5635 + ", uid=" + Binder.getCallingUid()
5636 + " requires " + permission;
5637 Log.w(TAG, msg);
5638 throw new SecurityException(msg);
5639 }
5640
5641 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5642 ProviderInfo pi, int uid, int modeFlags) {
5643 try {
5644 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5645 if ((pi.readPermission != null) &&
5646 (pm.checkUidPermission(pi.readPermission, uid)
5647 != PackageManager.PERMISSION_GRANTED)) {
5648 return false;
5649 }
5650 }
5651 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5652 if ((pi.writePermission != null) &&
5653 (pm.checkUidPermission(pi.writePermission, uid)
5654 != PackageManager.PERMISSION_GRANTED)) {
5655 return false;
5656 }
5657 }
5658 return true;
5659 } catch (RemoteException e) {
5660 return false;
5661 }
5662 }
5663
5664 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5665 int modeFlags) {
5666 // Root gets to do everything.
5667 if (uid == 0 || !Process.supportsProcesses()) {
5668 return true;
5669 }
5670 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5671 if (perms == null) return false;
5672 UriPermission perm = perms.get(uri);
5673 if (perm == null) return false;
5674 return (modeFlags&perm.modeFlags) == modeFlags;
5675 }
5676
5677 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5678 // Another redirected-binder-call permissions check as in
5679 // {@link checkComponentPermission}.
5680 Identity tlsIdentity = sCallerIdentity.get();
5681 if (tlsIdentity != null) {
5682 uid = tlsIdentity.uid;
5683 pid = tlsIdentity.pid;
5684 }
5685
5686 // Our own process gets to do everything.
5687 if (pid == MY_PID) {
5688 return PackageManager.PERMISSION_GRANTED;
5689 }
5690 synchronized(this) {
5691 return checkUriPermissionLocked(uri, uid, modeFlags)
5692 ? PackageManager.PERMISSION_GRANTED
5693 : PackageManager.PERMISSION_DENIED;
5694 }
5695 }
5696
5697 private void grantUriPermissionLocked(int callingUid,
5698 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5699 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5700 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5701 if (modeFlags == 0) {
5702 return;
5703 }
5704
5705 final IPackageManager pm = ActivityThread.getPackageManager();
5706
5707 // If this is not a content: uri, we can't do anything with it.
5708 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5709 return;
5710 }
5711
5712 String name = uri.getAuthority();
5713 ProviderInfo pi = null;
5714 ContentProviderRecord cpr
5715 = (ContentProviderRecord)mProvidersByName.get(name);
5716 if (cpr != null) {
5717 pi = cpr.info;
5718 } else {
5719 try {
5720 pi = pm.resolveContentProvider(name,
5721 PackageManager.GET_URI_PERMISSION_PATTERNS);
5722 } catch (RemoteException ex) {
5723 }
5724 }
5725 if (pi == null) {
5726 Log.w(TAG, "No content provider found for: " + name);
5727 return;
5728 }
5729
5730 int targetUid;
5731 try {
5732 targetUid = pm.getPackageUid(targetPkg);
5733 if (targetUid < 0) {
5734 return;
5735 }
5736 } catch (RemoteException ex) {
5737 return;
5738 }
5739
5740 // First... does the target actually need this permission?
5741 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5742 // No need to grant the target this permission.
5743 return;
5744 }
5745
5746 // Second... maybe someone else has already granted the
5747 // permission?
5748 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5749 // No need to grant the target this permission.
5750 return;
5751 }
5752
5753 // Third... is the provider allowing granting of URI permissions?
5754 if (!pi.grantUriPermissions) {
5755 throw new SecurityException("Provider " + pi.packageName
5756 + "/" + pi.name
5757 + " does not allow granting of Uri permissions (uri "
5758 + uri + ")");
5759 }
5760 if (pi.uriPermissionPatterns != null) {
5761 final int N = pi.uriPermissionPatterns.length;
5762 boolean allowed = false;
5763 for (int i=0; i<N; i++) {
5764 if (pi.uriPermissionPatterns[i] != null
5765 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5766 allowed = true;
5767 break;
5768 }
5769 }
5770 if (!allowed) {
5771 throw new SecurityException("Provider " + pi.packageName
5772 + "/" + pi.name
5773 + " does not allow granting of permission to path of Uri "
5774 + uri);
5775 }
5776 }
5777
5778 // Fourth... does the caller itself have permission to access
5779 // this uri?
5780 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5781 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5782 throw new SecurityException("Uid " + callingUid
5783 + " does not have permission to uri " + uri);
5784 }
5785 }
5786
5787 // Okay! So here we are: the caller has the assumed permission
5788 // to the uri, and the target doesn't. Let's now give this to
5789 // the target.
5790
5791 HashMap<Uri, UriPermission> targetUris
5792 = mGrantedUriPermissions.get(targetUid);
5793 if (targetUris == null) {
5794 targetUris = new HashMap<Uri, UriPermission>();
5795 mGrantedUriPermissions.put(targetUid, targetUris);
5796 }
5797
5798 UriPermission perm = targetUris.get(uri);
5799 if (perm == null) {
5800 perm = new UriPermission(targetUid, uri);
5801 targetUris.put(uri, perm);
5802
5803 }
5804 perm.modeFlags |= modeFlags;
5805 if (activity == null) {
5806 perm.globalModeFlags |= modeFlags;
5807 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5808 perm.readActivities.add(activity);
5809 if (activity.readUriPermissions == null) {
5810 activity.readUriPermissions = new HashSet<UriPermission>();
5811 }
5812 activity.readUriPermissions.add(perm);
5813 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5814 perm.writeActivities.add(activity);
5815 if (activity.writeUriPermissions == null) {
5816 activity.writeUriPermissions = new HashSet<UriPermission>();
5817 }
5818 activity.writeUriPermissions.add(perm);
5819 }
5820 }
5821
5822 private void grantUriPermissionFromIntentLocked(int callingUid,
5823 String targetPkg, Intent intent, HistoryRecord activity) {
5824 if (intent == null) {
5825 return;
5826 }
5827 Uri data = intent.getData();
5828 if (data == null) {
5829 return;
5830 }
5831 grantUriPermissionLocked(callingUid, targetPkg, data,
5832 intent.getFlags(), activity);
5833 }
5834
5835 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5836 Uri uri, int modeFlags) {
5837 synchronized(this) {
5838 final ProcessRecord r = getRecordForAppLocked(caller);
5839 if (r == null) {
5840 throw new SecurityException("Unable to find app for caller "
5841 + caller
5842 + " when granting permission to uri " + uri);
5843 }
5844 if (targetPkg == null) {
5845 Log.w(TAG, "grantUriPermission: null target");
5846 return;
5847 }
5848 if (uri == null) {
5849 Log.w(TAG, "grantUriPermission: null uri");
5850 return;
5851 }
5852
5853 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5854 null);
5855 }
5856 }
5857
5858 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5859 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5860 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5861 HashMap<Uri, UriPermission> perms
5862 = mGrantedUriPermissions.get(perm.uid);
5863 if (perms != null) {
5864 perms.remove(perm.uri);
5865 if (perms.size() == 0) {
5866 mGrantedUriPermissions.remove(perm.uid);
5867 }
5868 }
5869 }
5870 }
5871
5872 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5873 if (activity.readUriPermissions != null) {
5874 for (UriPermission perm : activity.readUriPermissions) {
5875 perm.readActivities.remove(activity);
5876 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5877 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5878 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5879 removeUriPermissionIfNeededLocked(perm);
5880 }
5881 }
5882 }
5883 if (activity.writeUriPermissions != null) {
5884 for (UriPermission perm : activity.writeUriPermissions) {
5885 perm.writeActivities.remove(activity);
5886 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5887 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5888 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5889 removeUriPermissionIfNeededLocked(perm);
5890 }
5891 }
5892 }
5893 }
5894
5895 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5896 int modeFlags) {
5897 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5898 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5899 if (modeFlags == 0) {
5900 return;
5901 }
5902
5903 final IPackageManager pm = ActivityThread.getPackageManager();
5904
5905 final String authority = uri.getAuthority();
5906 ProviderInfo pi = null;
5907 ContentProviderRecord cpr
5908 = (ContentProviderRecord)mProvidersByName.get(authority);
5909 if (cpr != null) {
5910 pi = cpr.info;
5911 } else {
5912 try {
5913 pi = pm.resolveContentProvider(authority,
5914 PackageManager.GET_URI_PERMISSION_PATTERNS);
5915 } catch (RemoteException ex) {
5916 }
5917 }
5918 if (pi == null) {
5919 Log.w(TAG, "No content provider found for: " + authority);
5920 return;
5921 }
5922
5923 // Does the caller have this permission on the URI?
5924 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5925 // Right now, if you are not the original owner of the permission,
5926 // you are not allowed to revoke it.
5927 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5928 throw new SecurityException("Uid " + callingUid
5929 + " does not have permission to uri " + uri);
5930 //}
5931 }
5932
5933 // Go through all of the permissions and remove any that match.
5934 final List<String> SEGMENTS = uri.getPathSegments();
5935 if (SEGMENTS != null) {
5936 final int NS = SEGMENTS.size();
5937 int N = mGrantedUriPermissions.size();
5938 for (int i=0; i<N; i++) {
5939 HashMap<Uri, UriPermission> perms
5940 = mGrantedUriPermissions.valueAt(i);
5941 Iterator<UriPermission> it = perms.values().iterator();
5942 toploop:
5943 while (it.hasNext()) {
5944 UriPermission perm = it.next();
5945 Uri targetUri = perm.uri;
5946 if (!authority.equals(targetUri.getAuthority())) {
5947 continue;
5948 }
5949 List<String> targetSegments = targetUri.getPathSegments();
5950 if (targetSegments == null) {
5951 continue;
5952 }
5953 if (targetSegments.size() < NS) {
5954 continue;
5955 }
5956 for (int j=0; j<NS; j++) {
5957 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5958 continue toploop;
5959 }
5960 }
5961 perm.clearModes(modeFlags);
5962 if (perm.modeFlags == 0) {
5963 it.remove();
5964 }
5965 }
5966 if (perms.size() == 0) {
5967 mGrantedUriPermissions.remove(
5968 mGrantedUriPermissions.keyAt(i));
5969 N--;
5970 i--;
5971 }
5972 }
5973 }
5974 }
5975
5976 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5977 int modeFlags) {
5978 synchronized(this) {
5979 final ProcessRecord r = getRecordForAppLocked(caller);
5980 if (r == null) {
5981 throw new SecurityException("Unable to find app for caller "
5982 + caller
5983 + " when revoking permission to uri " + uri);
5984 }
5985 if (uri == null) {
5986 Log.w(TAG, "revokeUriPermission: null uri");
5987 return;
5988 }
5989
5990 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5991 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5992 if (modeFlags == 0) {
5993 return;
5994 }
5995
5996 final IPackageManager pm = ActivityThread.getPackageManager();
5997
5998 final String authority = uri.getAuthority();
5999 ProviderInfo pi = null;
6000 ContentProviderRecord cpr
6001 = (ContentProviderRecord)mProvidersByName.get(authority);
6002 if (cpr != null) {
6003 pi = cpr.info;
6004 } else {
6005 try {
6006 pi = pm.resolveContentProvider(authority,
6007 PackageManager.GET_URI_PERMISSION_PATTERNS);
6008 } catch (RemoteException ex) {
6009 }
6010 }
6011 if (pi == null) {
6012 Log.w(TAG, "No content provider found for: " + authority);
6013 return;
6014 }
6015
6016 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6017 }
6018 }
6019
6020 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6021 synchronized (this) {
6022 ProcessRecord app =
6023 who != null ? getRecordForAppLocked(who) : null;
6024 if (app == null) return;
6025
6026 Message msg = Message.obtain();
6027 msg.what = WAIT_FOR_DEBUGGER_MSG;
6028 msg.obj = app;
6029 msg.arg1 = waiting ? 1 : 0;
6030 mHandler.sendMessage(msg);
6031 }
6032 }
6033
6034 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6035 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006036 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006037 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006038 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006039 }
6040
6041 // =========================================================
6042 // TASK MANAGEMENT
6043 // =========================================================
6044
6045 public List getTasks(int maxNum, int flags,
6046 IThumbnailReceiver receiver) {
6047 ArrayList list = new ArrayList();
6048
6049 PendingThumbnailsRecord pending = null;
6050 IApplicationThread topThumbnail = null;
6051 HistoryRecord topRecord = null;
6052
6053 synchronized(this) {
6054 if (localLOGV) Log.v(
6055 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6056 + ", receiver=" + receiver);
6057
6058 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6059 != PackageManager.PERMISSION_GRANTED) {
6060 if (receiver != null) {
6061 // If the caller wants to wait for pending thumbnails,
6062 // it ain't gonna get them.
6063 try {
6064 receiver.finished();
6065 } catch (RemoteException ex) {
6066 }
6067 }
6068 String msg = "Permission Denial: getTasks() from pid="
6069 + Binder.getCallingPid()
6070 + ", uid=" + Binder.getCallingUid()
6071 + " requires " + android.Manifest.permission.GET_TASKS;
6072 Log.w(TAG, msg);
6073 throw new SecurityException(msg);
6074 }
6075
6076 int pos = mHistory.size()-1;
6077 HistoryRecord next =
6078 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6079 HistoryRecord top = null;
6080 CharSequence topDescription = null;
6081 TaskRecord curTask = null;
6082 int numActivities = 0;
6083 int numRunning = 0;
6084 while (pos >= 0 && maxNum > 0) {
6085 final HistoryRecord r = next;
6086 pos--;
6087 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6088
6089 // Initialize state for next task if needed.
6090 if (top == null ||
6091 (top.state == ActivityState.INITIALIZING
6092 && top.task == r.task)) {
6093 top = r;
6094 topDescription = r.description;
6095 curTask = r.task;
6096 numActivities = numRunning = 0;
6097 }
6098
6099 // Add 'r' into the current task.
6100 numActivities++;
6101 if (r.app != null && r.app.thread != null) {
6102 numRunning++;
6103 }
6104 if (topDescription == null) {
6105 topDescription = r.description;
6106 }
6107
6108 if (localLOGV) Log.v(
6109 TAG, r.intent.getComponent().flattenToShortString()
6110 + ": task=" + r.task);
6111
6112 // If the next one is a different task, generate a new
6113 // TaskInfo entry for what we have.
6114 if (next == null || next.task != curTask) {
6115 ActivityManager.RunningTaskInfo ci
6116 = new ActivityManager.RunningTaskInfo();
6117 ci.id = curTask.taskId;
6118 ci.baseActivity = r.intent.getComponent();
6119 ci.topActivity = top.intent.getComponent();
6120 ci.thumbnail = top.thumbnail;
6121 ci.description = topDescription;
6122 ci.numActivities = numActivities;
6123 ci.numRunning = numRunning;
6124 //System.out.println(
6125 // "#" + maxNum + ": " + " descr=" + ci.description);
6126 if (ci.thumbnail == null && receiver != null) {
6127 if (localLOGV) Log.v(
6128 TAG, "State=" + top.state + "Idle=" + top.idle
6129 + " app=" + top.app
6130 + " thr=" + (top.app != null ? top.app.thread : null));
6131 if (top.state == ActivityState.RESUMED
6132 || top.state == ActivityState.PAUSING) {
6133 if (top.idle && top.app != null
6134 && top.app.thread != null) {
6135 topRecord = top;
6136 topThumbnail = top.app.thread;
6137 } else {
6138 top.thumbnailNeeded = true;
6139 }
6140 }
6141 if (pending == null) {
6142 pending = new PendingThumbnailsRecord(receiver);
6143 }
6144 pending.pendingRecords.add(top);
6145 }
6146 list.add(ci);
6147 maxNum--;
6148 top = null;
6149 }
6150 }
6151
6152 if (pending != null) {
6153 mPendingThumbnails.add(pending);
6154 }
6155 }
6156
6157 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6158
6159 if (topThumbnail != null) {
6160 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6161 try {
6162 topThumbnail.requestThumbnail(topRecord);
6163 } catch (Exception e) {
6164 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6165 sendPendingThumbnail(null, topRecord, null, null, true);
6166 }
6167 }
6168
6169 if (pending == null && receiver != null) {
6170 // In this case all thumbnails were available and the client
6171 // is being asked to be told when the remaining ones come in...
6172 // which is unusually, since the top-most currently running
6173 // activity should never have a canned thumbnail! Oh well.
6174 try {
6175 receiver.finished();
6176 } catch (RemoteException ex) {
6177 }
6178 }
6179
6180 return list;
6181 }
6182
6183 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6184 int flags) {
6185 synchronized (this) {
6186 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6187 "getRecentTasks()");
6188
6189 final int N = mRecentTasks.size();
6190 ArrayList<ActivityManager.RecentTaskInfo> res
6191 = new ArrayList<ActivityManager.RecentTaskInfo>(
6192 maxNum < N ? maxNum : N);
6193 for (int i=0; i<N && maxNum > 0; i++) {
6194 TaskRecord tr = mRecentTasks.get(i);
6195 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6196 || (tr.intent == null)
6197 || ((tr.intent.getFlags()
6198 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6199 ActivityManager.RecentTaskInfo rti
6200 = new ActivityManager.RecentTaskInfo();
6201 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6202 rti.baseIntent = new Intent(
6203 tr.intent != null ? tr.intent : tr.affinityIntent);
6204 rti.origActivity = tr.origActivity;
6205 res.add(rti);
6206 maxNum--;
6207 }
6208 }
6209 return res;
6210 }
6211 }
6212
6213 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6214 int j;
6215 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6216 TaskRecord jt = startTask;
6217
6218 // First look backwards
6219 for (j=startIndex-1; j>=0; j--) {
6220 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6221 if (r.task != jt) {
6222 jt = r.task;
6223 if (affinity.equals(jt.affinity)) {
6224 return j;
6225 }
6226 }
6227 }
6228
6229 // Now look forwards
6230 final int N = mHistory.size();
6231 jt = startTask;
6232 for (j=startIndex+1; j<N; j++) {
6233 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6234 if (r.task != jt) {
6235 if (affinity.equals(jt.affinity)) {
6236 return j;
6237 }
6238 jt = r.task;
6239 }
6240 }
6241
6242 // Might it be at the top?
6243 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6244 return N-1;
6245 }
6246
6247 return -1;
6248 }
6249
6250 /**
6251 * Perform a reset of the given task, if needed as part of launching it.
6252 * Returns the new HistoryRecord at the top of the task.
6253 */
6254 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6255 HistoryRecord newActivity) {
6256 boolean forceReset = (newActivity.info.flags
6257 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6258 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6259 if ((newActivity.info.flags
6260 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6261 forceReset = true;
6262 }
6263 }
6264
6265 final TaskRecord task = taskTop.task;
6266
6267 // We are going to move through the history list so that we can look
6268 // at each activity 'target' with 'below' either the interesting
6269 // activity immediately below it in the stack or null.
6270 HistoryRecord target = null;
6271 int targetI = 0;
6272 int taskTopI = -1;
6273 int replyChainEnd = -1;
6274 int lastReparentPos = -1;
6275 for (int i=mHistory.size()-1; i>=-1; i--) {
6276 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6277
6278 if (below != null && below.finishing) {
6279 continue;
6280 }
6281 if (target == null) {
6282 target = below;
6283 targetI = i;
6284 // If we were in the middle of a reply chain before this
6285 // task, it doesn't appear like the root of the chain wants
6286 // anything interesting, so drop it.
6287 replyChainEnd = -1;
6288 continue;
6289 }
6290
6291 final int flags = target.info.flags;
6292
6293 final boolean finishOnTaskLaunch =
6294 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6295 final boolean allowTaskReparenting =
6296 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6297
6298 if (target.task == task) {
6299 // We are inside of the task being reset... we'll either
6300 // finish this activity, push it out for another task,
6301 // or leave it as-is. We only do this
6302 // for activities that are not the root of the task (since
6303 // if we finish the root, we may no longer have the task!).
6304 if (taskTopI < 0) {
6305 taskTopI = targetI;
6306 }
6307 if (below != null && below.task == task) {
6308 final boolean clearWhenTaskReset =
6309 (target.intent.getFlags()
6310 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006311 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006312 // If this activity is sending a reply to a previous
6313 // activity, we can't do anything with it now until
6314 // we reach the start of the reply chain.
6315 // XXX note that we are assuming the result is always
6316 // to the previous activity, which is almost always
6317 // the case but we really shouldn't count on.
6318 if (replyChainEnd < 0) {
6319 replyChainEnd = targetI;
6320 }
Ed Heyl73798232009-03-24 21:32:21 -07006321 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006322 && target.taskAffinity != null
6323 && !target.taskAffinity.equals(task.affinity)) {
6324 // If this activity has an affinity for another
6325 // task, then we need to move it out of here. We will
6326 // move it as far out of the way as possible, to the
6327 // bottom of the activity stack. This also keeps it
6328 // correctly ordered with any activities we previously
6329 // moved.
6330 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6331 if (target.taskAffinity != null
6332 && target.taskAffinity.equals(p.task.affinity)) {
6333 // If the activity currently at the bottom has the
6334 // same task affinity as the one we are moving,
6335 // then merge it into the same task.
6336 target.task = p.task;
6337 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6338 + " out to bottom task " + p.task);
6339 } else {
6340 mCurTask++;
6341 if (mCurTask <= 0) {
6342 mCurTask = 1;
6343 }
6344 target.task = new TaskRecord(mCurTask, target.info, null,
6345 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6346 target.task.affinityIntent = target.intent;
6347 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6348 + " out to new task " + target.task);
6349 }
6350 mWindowManager.setAppGroupId(target, task.taskId);
6351 if (replyChainEnd < 0) {
6352 replyChainEnd = targetI;
6353 }
6354 int dstPos = 0;
6355 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6356 p = (HistoryRecord)mHistory.get(srcPos);
6357 if (p.finishing) {
6358 continue;
6359 }
6360 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6361 + " out to target's task " + target.task);
6362 task.numActivities--;
6363 p.task = target.task;
6364 target.task.numActivities++;
6365 mHistory.remove(srcPos);
6366 mHistory.add(dstPos, p);
6367 mWindowManager.moveAppToken(dstPos, p);
6368 mWindowManager.setAppGroupId(p, p.task.taskId);
6369 dstPos++;
6370 if (VALIDATE_TOKENS) {
6371 mWindowManager.validateAppTokens(mHistory);
6372 }
6373 i++;
6374 }
6375 if (taskTop == p) {
6376 taskTop = below;
6377 }
6378 if (taskTopI == replyChainEnd) {
6379 taskTopI = -1;
6380 }
6381 replyChainEnd = -1;
6382 addRecentTask(target.task);
6383 } else if (forceReset || finishOnTaskLaunch
6384 || clearWhenTaskReset) {
6385 // If the activity should just be removed -- either
6386 // because it asks for it, or the task should be
6387 // cleared -- then finish it and anything that is
6388 // part of its reply chain.
6389 if (clearWhenTaskReset) {
6390 // In this case, we want to finish this activity
6391 // and everything above it, so be sneaky and pretend
6392 // like these are all in the reply chain.
6393 replyChainEnd = targetI+1;
6394 while (replyChainEnd < mHistory.size() &&
6395 ((HistoryRecord)mHistory.get(
6396 replyChainEnd)).task == task) {
6397 replyChainEnd++;
6398 }
6399 replyChainEnd--;
6400 } else if (replyChainEnd < 0) {
6401 replyChainEnd = targetI;
6402 }
6403 HistoryRecord p = null;
6404 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6405 p = (HistoryRecord)mHistory.get(srcPos);
6406 if (p.finishing) {
6407 continue;
6408 }
6409 if (finishActivityLocked(p, srcPos,
6410 Activity.RESULT_CANCELED, null, "reset")) {
6411 replyChainEnd--;
6412 srcPos--;
6413 }
6414 }
6415 if (taskTop == p) {
6416 taskTop = below;
6417 }
6418 if (taskTopI == replyChainEnd) {
6419 taskTopI = -1;
6420 }
6421 replyChainEnd = -1;
6422 } else {
6423 // If we were in the middle of a chain, well the
6424 // activity that started it all doesn't want anything
6425 // special, so leave it all as-is.
6426 replyChainEnd = -1;
6427 }
6428 } else {
6429 // Reached the bottom of the task -- any reply chain
6430 // should be left as-is.
6431 replyChainEnd = -1;
6432 }
6433
6434 } else if (target.resultTo != null) {
6435 // If this activity is sending a reply to a previous
6436 // activity, we can't do anything with it now until
6437 // we reach the start of the reply chain.
6438 // XXX note that we are assuming the result is always
6439 // to the previous activity, which is almost always
6440 // the case but we really shouldn't count on.
6441 if (replyChainEnd < 0) {
6442 replyChainEnd = targetI;
6443 }
6444
6445 } else if (taskTopI >= 0 && allowTaskReparenting
6446 && task.affinity != null
6447 && task.affinity.equals(target.taskAffinity)) {
6448 // We are inside of another task... if this activity has
6449 // an affinity for our task, then either remove it if we are
6450 // clearing or move it over to our task. Note that
6451 // we currently punt on the case where we are resetting a
6452 // task that is not at the top but who has activities above
6453 // with an affinity to it... this is really not a normal
6454 // case, and we will need to later pull that task to the front
6455 // and usually at that point we will do the reset and pick
6456 // up those remaining activities. (This only happens if
6457 // someone starts an activity in a new task from an activity
6458 // in a task that is not currently on top.)
6459 if (forceReset || finishOnTaskLaunch) {
6460 if (replyChainEnd < 0) {
6461 replyChainEnd = targetI;
6462 }
6463 HistoryRecord p = null;
6464 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6465 p = (HistoryRecord)mHistory.get(srcPos);
6466 if (p.finishing) {
6467 continue;
6468 }
6469 if (finishActivityLocked(p, srcPos,
6470 Activity.RESULT_CANCELED, null, "reset")) {
6471 taskTopI--;
6472 lastReparentPos--;
6473 replyChainEnd--;
6474 srcPos--;
6475 }
6476 }
6477 replyChainEnd = -1;
6478 } else {
6479 if (replyChainEnd < 0) {
6480 replyChainEnd = targetI;
6481 }
6482 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6483 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6484 if (p.finishing) {
6485 continue;
6486 }
6487 if (lastReparentPos < 0) {
6488 lastReparentPos = taskTopI;
6489 taskTop = p;
6490 } else {
6491 lastReparentPos--;
6492 }
6493 mHistory.remove(srcPos);
6494 p.task.numActivities--;
6495 p.task = task;
6496 mHistory.add(lastReparentPos, p);
6497 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6498 + " in to resetting task " + task);
6499 task.numActivities++;
6500 mWindowManager.moveAppToken(lastReparentPos, p);
6501 mWindowManager.setAppGroupId(p, p.task.taskId);
6502 if (VALIDATE_TOKENS) {
6503 mWindowManager.validateAppTokens(mHistory);
6504 }
6505 }
6506 replyChainEnd = -1;
6507
6508 // Now we've moved it in to place... but what if this is
6509 // a singleTop activity and we have put it on top of another
6510 // instance of the same activity? Then we drop the instance
6511 // below so it remains singleTop.
6512 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6513 for (int j=lastReparentPos-1; j>=0; j--) {
6514 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6515 if (p.finishing) {
6516 continue;
6517 }
6518 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6519 if (finishActivityLocked(p, j,
6520 Activity.RESULT_CANCELED, null, "replace")) {
6521 taskTopI--;
6522 lastReparentPos--;
6523 }
6524 }
6525 }
6526 }
6527 }
6528 }
6529
6530 target = below;
6531 targetI = i;
6532 }
6533
6534 return taskTop;
6535 }
6536
6537 /**
6538 * TODO: Add mWatcher hook
6539 */
6540 public void moveTaskToFront(int task) {
6541 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6542 "moveTaskToFront()");
6543
6544 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006545 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6546 Binder.getCallingUid(), "Task to front")) {
6547 return;
6548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006549 final long origId = Binder.clearCallingIdentity();
6550 try {
6551 int N = mRecentTasks.size();
6552 for (int i=0; i<N; i++) {
6553 TaskRecord tr = mRecentTasks.get(i);
6554 if (tr.taskId == task) {
6555 moveTaskToFrontLocked(tr);
6556 return;
6557 }
6558 }
6559 for (int i=mHistory.size()-1; i>=0; i--) {
6560 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6561 if (hr.task.taskId == task) {
6562 moveTaskToFrontLocked(hr.task);
6563 return;
6564 }
6565 }
6566 } finally {
6567 Binder.restoreCallingIdentity(origId);
6568 }
6569 }
6570 }
6571
6572 private final void moveTaskToFrontLocked(TaskRecord tr) {
6573 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6574
6575 final int task = tr.taskId;
6576 int top = mHistory.size()-1;
6577
6578 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6579 // nothing to do!
6580 return;
6581 }
6582
6583 if (DEBUG_TRANSITION) Log.v(TAG,
6584 "Prepare to front transition: task=" + tr);
6585 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6586
6587 ArrayList moved = new ArrayList();
6588
6589 // Applying the affinities may have removed entries from the history,
6590 // so get the size again.
6591 top = mHistory.size()-1;
6592 int pos = top;
6593
6594 // Shift all activities with this task up to the top
6595 // of the stack, keeping them in the same internal order.
6596 while (pos >= 0) {
6597 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6598 if (localLOGV) Log.v(
6599 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6600 boolean first = true;
6601 if (r.task.taskId == task) {
6602 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6603 mHistory.remove(pos);
6604 mHistory.add(top, r);
6605 moved.add(0, r);
6606 top--;
6607 if (first) {
6608 addRecentTask(r.task);
6609 first = false;
6610 }
6611 }
6612 pos--;
6613 }
6614
6615 mWindowManager.moveAppTokensToTop(moved);
6616 if (VALIDATE_TOKENS) {
6617 mWindowManager.validateAppTokens(mHistory);
6618 }
6619
6620 finishTaskMove(task);
6621 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6622 }
6623
6624 private final void finishTaskMove(int task) {
6625 resumeTopActivityLocked(null);
6626 }
6627
6628 public void moveTaskToBack(int task) {
6629 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6630 "moveTaskToBack()");
6631
6632 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006633 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6634 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6635 Binder.getCallingUid(), "Task to back")) {
6636 return;
6637 }
6638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006639 final long origId = Binder.clearCallingIdentity();
6640 moveTaskToBackLocked(task);
6641 Binder.restoreCallingIdentity(origId);
6642 }
6643 }
6644
6645 /**
6646 * Moves an activity, and all of the other activities within the same task, to the bottom
6647 * of the history stack. The activity's order within the task is unchanged.
6648 *
6649 * @param token A reference to the activity we wish to move
6650 * @param nonRoot If false then this only works if the activity is the root
6651 * of a task; if true it will work for any activity in a task.
6652 * @return Returns true if the move completed, false if not.
6653 */
6654 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6655 synchronized(this) {
6656 final long origId = Binder.clearCallingIdentity();
6657 int taskId = getTaskForActivityLocked(token, !nonRoot);
6658 if (taskId >= 0) {
6659 return moveTaskToBackLocked(taskId);
6660 }
6661 Binder.restoreCallingIdentity(origId);
6662 }
6663 return false;
6664 }
6665
6666 /**
6667 * Worker method for rearranging history stack. Implements the function of moving all
6668 * activities for a specific task (gathering them if disjoint) into a single group at the
6669 * bottom of the stack.
6670 *
6671 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6672 * to premeptively cancel the move.
6673 *
6674 * @param task The taskId to collect and move to the bottom.
6675 * @return Returns true if the move completed, false if not.
6676 */
6677 private final boolean moveTaskToBackLocked(int task) {
6678 Log.i(TAG, "moveTaskToBack: " + task);
6679
6680 // If we have a watcher, preflight the move before committing to it. First check
6681 // for *other* available tasks, but if none are available, then try again allowing the
6682 // current task to be selected.
6683 if (mWatcher != null) {
6684 HistoryRecord next = topRunningActivityLocked(null, task);
6685 if (next == null) {
6686 next = topRunningActivityLocked(null, 0);
6687 }
6688 if (next != null) {
6689 // ask watcher if this is allowed
6690 boolean moveOK = true;
6691 try {
6692 moveOK = mWatcher.activityResuming(next.packageName);
6693 } catch (RemoteException e) {
6694 mWatcher = null;
6695 }
6696 if (!moveOK) {
6697 return false;
6698 }
6699 }
6700 }
6701
6702 ArrayList moved = new ArrayList();
6703
6704 if (DEBUG_TRANSITION) Log.v(TAG,
6705 "Prepare to back transition: task=" + task);
6706 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6707
6708 final int N = mHistory.size();
6709 int bottom = 0;
6710 int pos = 0;
6711
6712 // Shift all activities with this task down to the bottom
6713 // of the stack, keeping them in the same internal order.
6714 while (pos < N) {
6715 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6716 if (localLOGV) Log.v(
6717 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6718 if (r.task.taskId == task) {
6719 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6720 mHistory.remove(pos);
6721 mHistory.add(bottom, r);
6722 moved.add(r);
6723 bottom++;
6724 }
6725 pos++;
6726 }
6727
6728 mWindowManager.moveAppTokensToBottom(moved);
6729 if (VALIDATE_TOKENS) {
6730 mWindowManager.validateAppTokens(mHistory);
6731 }
6732
6733 finishTaskMove(task);
6734 return true;
6735 }
6736
6737 public void moveTaskBackwards(int task) {
6738 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6739 "moveTaskBackwards()");
6740
6741 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006742 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6743 Binder.getCallingUid(), "Task backwards")) {
6744 return;
6745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006746 final long origId = Binder.clearCallingIdentity();
6747 moveTaskBackwardsLocked(task);
6748 Binder.restoreCallingIdentity(origId);
6749 }
6750 }
6751
6752 private final void moveTaskBackwardsLocked(int task) {
6753 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6754 }
6755
6756 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6757 synchronized(this) {
6758 return getTaskForActivityLocked(token, onlyRoot);
6759 }
6760 }
6761
6762 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6763 final int N = mHistory.size();
6764 TaskRecord lastTask = null;
6765 for (int i=0; i<N; i++) {
6766 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6767 if (r == token) {
6768 if (!onlyRoot || lastTask != r.task) {
6769 return r.task.taskId;
6770 }
6771 return -1;
6772 }
6773 lastTask = r.task;
6774 }
6775
6776 return -1;
6777 }
6778
6779 /**
6780 * Returns the top activity in any existing task matching the given
6781 * Intent. Returns null if no such task is found.
6782 */
6783 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6784 ComponentName cls = intent.getComponent();
6785 if (info.targetActivity != null) {
6786 cls = new ComponentName(info.packageName, info.targetActivity);
6787 }
6788
6789 TaskRecord cp = null;
6790
6791 final int N = mHistory.size();
6792 for (int i=(N-1); i>=0; i--) {
6793 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6794 if (!r.finishing && r.task != cp
6795 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6796 cp = r.task;
6797 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6798 // + "/aff=" + r.task.affinity + " to new cls="
6799 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6800 if (r.task.affinity != null) {
6801 if (r.task.affinity.equals(info.taskAffinity)) {
6802 //Log.i(TAG, "Found matching affinity!");
6803 return r;
6804 }
6805 } else if (r.task.intent != null
6806 && r.task.intent.getComponent().equals(cls)) {
6807 //Log.i(TAG, "Found matching class!");
6808 //dump();
6809 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6810 return r;
6811 } else if (r.task.affinityIntent != null
6812 && r.task.affinityIntent.getComponent().equals(cls)) {
6813 //Log.i(TAG, "Found matching class!");
6814 //dump();
6815 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6816 return r;
6817 }
6818 }
6819 }
6820
6821 return null;
6822 }
6823
6824 /**
6825 * Returns the first activity (starting from the top of the stack) that
6826 * is the same as the given activity. Returns null if no such activity
6827 * is found.
6828 */
6829 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6830 ComponentName cls = intent.getComponent();
6831 if (info.targetActivity != null) {
6832 cls = new ComponentName(info.packageName, info.targetActivity);
6833 }
6834
6835 final int N = mHistory.size();
6836 for (int i=(N-1); i>=0; i--) {
6837 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6838 if (!r.finishing) {
6839 if (r.intent.getComponent().equals(cls)) {
6840 //Log.i(TAG, "Found matching class!");
6841 //dump();
6842 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6843 return r;
6844 }
6845 }
6846 }
6847
6848 return null;
6849 }
6850
6851 public void finishOtherInstances(IBinder token, ComponentName className) {
6852 synchronized(this) {
6853 final long origId = Binder.clearCallingIdentity();
6854
6855 int N = mHistory.size();
6856 TaskRecord lastTask = null;
6857 for (int i=0; i<N; i++) {
6858 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6859 if (r.realActivity.equals(className)
6860 && r != token && lastTask != r.task) {
6861 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6862 null, "others")) {
6863 i--;
6864 N--;
6865 }
6866 }
6867 lastTask = r.task;
6868 }
6869
6870 Binder.restoreCallingIdentity(origId);
6871 }
6872 }
6873
6874 // =========================================================
6875 // THUMBNAILS
6876 // =========================================================
6877
6878 public void reportThumbnail(IBinder token,
6879 Bitmap thumbnail, CharSequence description) {
6880 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6881 final long origId = Binder.clearCallingIdentity();
6882 sendPendingThumbnail(null, token, thumbnail, description, true);
6883 Binder.restoreCallingIdentity(origId);
6884 }
6885
6886 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6887 Bitmap thumbnail, CharSequence description, boolean always) {
6888 TaskRecord task = null;
6889 ArrayList receivers = null;
6890
6891 //System.out.println("Send pending thumbnail: " + r);
6892
6893 synchronized(this) {
6894 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006895 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006896 if (index < 0) {
6897 return;
6898 }
6899 r = (HistoryRecord)mHistory.get(index);
6900 }
6901 if (thumbnail == null) {
6902 thumbnail = r.thumbnail;
6903 description = r.description;
6904 }
6905 if (thumbnail == null && !always) {
6906 // If there is no thumbnail, and this entry is not actually
6907 // going away, then abort for now and pick up the next
6908 // thumbnail we get.
6909 return;
6910 }
6911 task = r.task;
6912
6913 int N = mPendingThumbnails.size();
6914 int i=0;
6915 while (i<N) {
6916 PendingThumbnailsRecord pr =
6917 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6918 //System.out.println("Looking in " + pr.pendingRecords);
6919 if (pr.pendingRecords.remove(r)) {
6920 if (receivers == null) {
6921 receivers = new ArrayList();
6922 }
6923 receivers.add(pr);
6924 if (pr.pendingRecords.size() == 0) {
6925 pr.finished = true;
6926 mPendingThumbnails.remove(i);
6927 N--;
6928 continue;
6929 }
6930 }
6931 i++;
6932 }
6933 }
6934
6935 if (receivers != null) {
6936 final int N = receivers.size();
6937 for (int i=0; i<N; i++) {
6938 try {
6939 PendingThumbnailsRecord pr =
6940 (PendingThumbnailsRecord)receivers.get(i);
6941 pr.receiver.newThumbnail(
6942 task != null ? task.taskId : -1, thumbnail, description);
6943 if (pr.finished) {
6944 pr.receiver.finished();
6945 }
6946 } catch (Exception e) {
6947 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6948 }
6949 }
6950 }
6951 }
6952
6953 // =========================================================
6954 // CONTENT PROVIDERS
6955 // =========================================================
6956
6957 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6958 List providers = null;
6959 try {
6960 providers = ActivityThread.getPackageManager().
6961 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006962 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006963 } catch (RemoteException ex) {
6964 }
6965 if (providers != null) {
6966 final int N = providers.size();
6967 for (int i=0; i<N; i++) {
6968 ProviderInfo cpi =
6969 (ProviderInfo)providers.get(i);
6970 ContentProviderRecord cpr =
6971 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6972 if (cpr == null) {
6973 cpr = new ContentProviderRecord(cpi, app.info);
6974 mProvidersByClass.put(cpi.name, cpr);
6975 }
6976 app.pubProviders.put(cpi.name, cpr);
6977 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07006978 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006979 }
6980 }
6981 return providers;
6982 }
6983
6984 private final String checkContentProviderPermissionLocked(
6985 ProviderInfo cpi, ProcessRecord r, int mode) {
6986 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6987 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6988 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6989 cpi.exported ? -1 : cpi.applicationInfo.uid)
6990 == PackageManager.PERMISSION_GRANTED
6991 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6992 return null;
6993 }
6994 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6995 cpi.exported ? -1 : cpi.applicationInfo.uid)
6996 == PackageManager.PERMISSION_GRANTED) {
6997 return null;
6998 }
6999 String msg = "Permission Denial: opening provider " + cpi.name
7000 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7001 + ", uid=" + callingUid + ") requires "
7002 + cpi.readPermission + " or " + cpi.writePermission;
7003 Log.w(TAG, msg);
7004 return msg;
7005 }
7006
7007 private final ContentProviderHolder getContentProviderImpl(
7008 IApplicationThread caller, String name) {
7009 ContentProviderRecord cpr;
7010 ProviderInfo cpi = null;
7011
7012 synchronized(this) {
7013 ProcessRecord r = null;
7014 if (caller != null) {
7015 r = getRecordForAppLocked(caller);
7016 if (r == null) {
7017 throw new SecurityException(
7018 "Unable to find app for caller " + caller
7019 + " (pid=" + Binder.getCallingPid()
7020 + ") when getting content provider " + name);
7021 }
7022 }
7023
7024 // First check if this content provider has been published...
7025 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7026 if (cpr != null) {
7027 cpi = cpr.info;
7028 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7029 return new ContentProviderHolder(cpi,
7030 cpi.readPermission != null
7031 ? cpi.readPermission : cpi.writePermission);
7032 }
7033
7034 if (r != null && cpr.canRunHere(r)) {
7035 // This provider has been published or is in the process
7036 // of being published... but it is also allowed to run
7037 // in the caller's process, so don't make a connection
7038 // and just let the caller instantiate its own instance.
7039 if (cpr.provider != null) {
7040 // don't give caller the provider object, it needs
7041 // to make its own.
7042 cpr = new ContentProviderRecord(cpr);
7043 }
7044 return cpr;
7045 }
7046
7047 final long origId = Binder.clearCallingIdentity();
7048
7049 // In this case the provider is a single instance, so we can
7050 // return it right away.
7051 if (r != null) {
7052 r.conProviders.add(cpr);
7053 cpr.clients.add(r);
7054 } else {
7055 cpr.externals++;
7056 }
7057
7058 if (cpr.app != null) {
7059 updateOomAdjLocked(cpr.app);
7060 }
7061
7062 Binder.restoreCallingIdentity(origId);
7063
7064 } else {
7065 try {
7066 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007067 resolveContentProvider(name,
7068 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007069 } catch (RemoteException ex) {
7070 }
7071 if (cpi == null) {
7072 return null;
7073 }
7074
7075 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7076 return new ContentProviderHolder(cpi,
7077 cpi.readPermission != null
7078 ? cpi.readPermission : cpi.writePermission);
7079 }
7080
7081 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7082 final boolean firstClass = cpr == null;
7083 if (firstClass) {
7084 try {
7085 ApplicationInfo ai =
7086 ActivityThread.getPackageManager().
7087 getApplicationInfo(
7088 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007089 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 if (ai == null) {
7091 Log.w(TAG, "No package info for content provider "
7092 + cpi.name);
7093 return null;
7094 }
7095 cpr = new ContentProviderRecord(cpi, ai);
7096 } catch (RemoteException ex) {
7097 // pm is in same process, this will never happen.
7098 }
7099 }
7100
7101 if (r != null && cpr.canRunHere(r)) {
7102 // If this is a multiprocess provider, then just return its
7103 // info and allow the caller to instantiate it. Only do
7104 // this if the provider is the same user as the caller's
7105 // process, or can run as root (so can be in any process).
7106 return cpr;
7107 }
7108
7109 if (false) {
7110 RuntimeException e = new RuntimeException("foo");
7111 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7112 // + " pruid " + ai.uid + "): " + cpi.className, e);
7113 }
7114
7115 // This is single process, and our app is now connecting to it.
7116 // See if we are already in the process of launching this
7117 // provider.
7118 final int N = mLaunchingProviders.size();
7119 int i;
7120 for (i=0; i<N; i++) {
7121 if (mLaunchingProviders.get(i) == cpr) {
7122 break;
7123 }
7124 if (false) {
7125 final ContentProviderRecord rec =
7126 (ContentProviderRecord)mLaunchingProviders.get(i);
7127 if (rec.info.name.equals(cpr.info.name)) {
7128 cpr = rec;
7129 break;
7130 }
7131 }
7132 }
7133
7134 // If the provider is not already being launched, then get it
7135 // started.
7136 if (i >= N) {
7137 final long origId = Binder.clearCallingIdentity();
7138 ProcessRecord proc = startProcessLocked(cpi.processName,
7139 cpr.appInfo, false, 0, "content provider",
7140 new ComponentName(cpi.applicationInfo.packageName,
7141 cpi.name));
7142 if (proc == null) {
7143 Log.w(TAG, "Unable to launch app "
7144 + cpi.applicationInfo.packageName + "/"
7145 + cpi.applicationInfo.uid + " for provider "
7146 + name + ": process is bad");
7147 return null;
7148 }
7149 cpr.launchingApp = proc;
7150 mLaunchingProviders.add(cpr);
7151 Binder.restoreCallingIdentity(origId);
7152 }
7153
7154 // Make sure the provider is published (the same provider class
7155 // may be published under multiple names).
7156 if (firstClass) {
7157 mProvidersByClass.put(cpi.name, cpr);
7158 }
7159 mProvidersByName.put(name, cpr);
7160
7161 if (r != null) {
7162 r.conProviders.add(cpr);
7163 cpr.clients.add(r);
7164 } else {
7165 cpr.externals++;
7166 }
7167 }
7168 }
7169
7170 // Wait for the provider to be published...
7171 synchronized (cpr) {
7172 while (cpr.provider == null) {
7173 if (cpr.launchingApp == null) {
7174 Log.w(TAG, "Unable to launch app "
7175 + cpi.applicationInfo.packageName + "/"
7176 + cpi.applicationInfo.uid + " for provider "
7177 + name + ": launching app became null");
7178 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7179 cpi.applicationInfo.packageName,
7180 cpi.applicationInfo.uid, name);
7181 return null;
7182 }
7183 try {
7184 cpr.wait();
7185 } catch (InterruptedException ex) {
7186 }
7187 }
7188 }
7189 return cpr;
7190 }
7191
7192 public final ContentProviderHolder getContentProvider(
7193 IApplicationThread caller, String name) {
7194 if (caller == null) {
7195 String msg = "null IApplicationThread when getting content provider "
7196 + name;
7197 Log.w(TAG, msg);
7198 throw new SecurityException(msg);
7199 }
7200
7201 return getContentProviderImpl(caller, name);
7202 }
7203
7204 private ContentProviderHolder getContentProviderExternal(String name) {
7205 return getContentProviderImpl(null, name);
7206 }
7207
7208 /**
7209 * Drop a content provider from a ProcessRecord's bookkeeping
7210 * @param cpr
7211 */
7212 public void removeContentProvider(IApplicationThread caller, String name) {
7213 synchronized (this) {
7214 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7215 if(cpr == null) {
7216 //remove from mProvidersByClass
7217 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7218 return;
7219 }
7220 final ProcessRecord r = getRecordForAppLocked(caller);
7221 if (r == null) {
7222 throw new SecurityException(
7223 "Unable to find app for caller " + caller +
7224 " when removing content provider " + name);
7225 }
7226 //update content provider record entry info
7227 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7228 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7229 r.info.processName+" from process "+localCpr.appInfo.processName);
7230 if(localCpr.appInfo.processName == r.info.processName) {
7231 //should not happen. taken care of as a local provider
7232 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7233 return;
7234 } else {
7235 localCpr.clients.remove(r);
7236 r.conProviders.remove(localCpr);
7237 }
7238 updateOomAdjLocked();
7239 }
7240 }
7241
7242 private void removeContentProviderExternal(String name) {
7243 synchronized (this) {
7244 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7245 if(cpr == null) {
7246 //remove from mProvidersByClass
7247 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7248 return;
7249 }
7250
7251 //update content provider record entry info
7252 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7253 localCpr.externals--;
7254 if (localCpr.externals < 0) {
7255 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7256 }
7257 updateOomAdjLocked();
7258 }
7259 }
7260
7261 public final void publishContentProviders(IApplicationThread caller,
7262 List<ContentProviderHolder> providers) {
7263 if (providers == null) {
7264 return;
7265 }
7266
7267 synchronized(this) {
7268 final ProcessRecord r = getRecordForAppLocked(caller);
7269 if (r == null) {
7270 throw new SecurityException(
7271 "Unable to find app for caller " + caller
7272 + " (pid=" + Binder.getCallingPid()
7273 + ") when publishing content providers");
7274 }
7275
7276 final long origId = Binder.clearCallingIdentity();
7277
7278 final int N = providers.size();
7279 for (int i=0; i<N; i++) {
7280 ContentProviderHolder src = providers.get(i);
7281 if (src == null || src.info == null || src.provider == null) {
7282 continue;
7283 }
7284 ContentProviderRecord dst =
7285 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7286 if (dst != null) {
7287 mProvidersByClass.put(dst.info.name, dst);
7288 String names[] = dst.info.authority.split(";");
7289 for (int j = 0; j < names.length; j++) {
7290 mProvidersByName.put(names[j], dst);
7291 }
7292
7293 int NL = mLaunchingProviders.size();
7294 int j;
7295 for (j=0; j<NL; j++) {
7296 if (mLaunchingProviders.get(j) == dst) {
7297 mLaunchingProviders.remove(j);
7298 j--;
7299 NL--;
7300 }
7301 }
7302 synchronized (dst) {
7303 dst.provider = src.provider;
7304 dst.app = r;
7305 dst.notifyAll();
7306 }
7307 updateOomAdjLocked(r);
7308 }
7309 }
7310
7311 Binder.restoreCallingIdentity(origId);
7312 }
7313 }
7314
7315 public static final void installSystemProviders() {
7316 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7317 List providers = mSelf.generateApplicationProvidersLocked(app);
7318 mSystemThread.installSystemProviders(providers);
7319 }
7320
7321 // =========================================================
7322 // GLOBAL MANAGEMENT
7323 // =========================================================
7324
7325 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7326 ApplicationInfo info, String customProcess) {
7327 String proc = customProcess != null ? customProcess : info.processName;
7328 BatteryStatsImpl.Uid.Proc ps = null;
7329 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7330 synchronized (stats) {
7331 ps = stats.getProcessStatsLocked(info.uid, proc);
7332 }
7333 return new ProcessRecord(ps, thread, info, proc);
7334 }
7335
7336 final ProcessRecord addAppLocked(ApplicationInfo info) {
7337 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7338
7339 if (app == null) {
7340 app = newProcessRecordLocked(null, info, null);
7341 mProcessNames.put(info.processName, info.uid, app);
7342 updateLRUListLocked(app, true);
7343 }
7344
7345 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7346 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7347 app.persistent = true;
7348 app.maxAdj = CORE_SERVER_ADJ;
7349 }
7350 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7351 mPersistentStartingProcesses.add(app);
7352 startProcessLocked(app, "added application", app.processName);
7353 }
7354
7355 return app;
7356 }
7357
7358 public void unhandledBack() {
7359 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7360 "unhandledBack()");
7361
7362 synchronized(this) {
7363 int count = mHistory.size();
7364 if (Config.LOGD) Log.d(
7365 TAG, "Performing unhandledBack(): stack size = " + count);
7366 if (count > 1) {
7367 final long origId = Binder.clearCallingIdentity();
7368 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7369 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7370 Binder.restoreCallingIdentity(origId);
7371 }
7372 }
7373 }
7374
7375 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7376 String name = uri.getAuthority();
7377 ContentProviderHolder cph = getContentProviderExternal(name);
7378 ParcelFileDescriptor pfd = null;
7379 if (cph != null) {
7380 // We record the binder invoker's uid in thread-local storage before
7381 // going to the content provider to open the file. Later, in the code
7382 // that handles all permissions checks, we look for this uid and use
7383 // that rather than the Activity Manager's own uid. The effect is that
7384 // we do the check against the caller's permissions even though it looks
7385 // to the content provider like the Activity Manager itself is making
7386 // the request.
7387 sCallerIdentity.set(new Identity(
7388 Binder.getCallingPid(), Binder.getCallingUid()));
7389 try {
7390 pfd = cph.provider.openFile(uri, "r");
7391 } catch (FileNotFoundException e) {
7392 // do nothing; pfd will be returned null
7393 } finally {
7394 // Ensure that whatever happens, we clean up the identity state
7395 sCallerIdentity.remove();
7396 }
7397
7398 // We've got the fd now, so we're done with the provider.
7399 removeContentProviderExternal(name);
7400 } else {
7401 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7402 }
7403 return pfd;
7404 }
7405
7406 public void goingToSleep() {
7407 synchronized(this) {
7408 mSleeping = true;
7409 mWindowManager.setEventDispatching(false);
7410
7411 if (mResumedActivity != null) {
7412 pauseIfSleepingLocked();
7413 } else {
7414 Log.w(TAG, "goingToSleep with no resumed activity!");
7415 }
7416 }
7417 }
7418
Dianne Hackborn55280a92009-05-07 15:53:46 -07007419 public boolean shutdown(int timeout) {
7420 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7421 != PackageManager.PERMISSION_GRANTED) {
7422 throw new SecurityException("Requires permission "
7423 + android.Manifest.permission.SHUTDOWN);
7424 }
7425
7426 boolean timedout = false;
7427
7428 synchronized(this) {
7429 mShuttingDown = true;
7430 mWindowManager.setEventDispatching(false);
7431
7432 if (mResumedActivity != null) {
7433 pauseIfSleepingLocked();
7434 final long endTime = System.currentTimeMillis() + timeout;
7435 while (mResumedActivity != null || mPausingActivity != null) {
7436 long delay = endTime - System.currentTimeMillis();
7437 if (delay <= 0) {
7438 Log.w(TAG, "Activity manager shutdown timed out");
7439 timedout = true;
7440 break;
7441 }
7442 try {
7443 this.wait();
7444 } catch (InterruptedException e) {
7445 }
7446 }
7447 }
7448 }
7449
7450 mUsageStatsService.shutdown();
7451 mBatteryStatsService.shutdown();
7452
7453 return timedout;
7454 }
7455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007456 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007457 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007458 if (!mGoingToSleep.isHeld()) {
7459 mGoingToSleep.acquire();
7460 if (mLaunchingActivity.isHeld()) {
7461 mLaunchingActivity.release();
7462 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7463 }
7464 }
7465
7466 // If we are not currently pausing an activity, get the current
7467 // one to pause. If we are pausing one, we will just let that stuff
7468 // run and release the wake lock when all done.
7469 if (mPausingActivity == null) {
7470 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7471 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7472 startPausingLocked(false, true);
7473 }
7474 }
7475 }
7476
7477 public void wakingUp() {
7478 synchronized(this) {
7479 if (mGoingToSleep.isHeld()) {
7480 mGoingToSleep.release();
7481 }
7482 mWindowManager.setEventDispatching(true);
7483 mSleeping = false;
7484 resumeTopActivityLocked(null);
7485 }
7486 }
7487
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007488 public void stopAppSwitches() {
7489 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7490 != PackageManager.PERMISSION_GRANTED) {
7491 throw new SecurityException("Requires permission "
7492 + android.Manifest.permission.STOP_APP_SWITCHES);
7493 }
7494
7495 synchronized(this) {
7496 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7497 + APP_SWITCH_DELAY_TIME;
7498 mDidAppSwitch = false;
7499 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7500 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7501 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7502 }
7503 }
7504
7505 public void resumeAppSwitches() {
7506 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7507 != PackageManager.PERMISSION_GRANTED) {
7508 throw new SecurityException("Requires permission "
7509 + android.Manifest.permission.STOP_APP_SWITCHES);
7510 }
7511
7512 synchronized(this) {
7513 // Note that we don't execute any pending app switches... we will
7514 // let those wait until either the timeout, or the next start
7515 // activity request.
7516 mAppSwitchesAllowedTime = 0;
7517 }
7518 }
7519
7520 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7521 String name) {
7522 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7523 return true;
7524 }
7525
7526 final int perm = checkComponentPermission(
7527 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7528 callingUid, -1);
7529 if (perm == PackageManager.PERMISSION_GRANTED) {
7530 return true;
7531 }
7532
7533 Log.w(TAG, name + " request from " + callingUid + " stopped");
7534 return false;
7535 }
7536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007537 public void setDebugApp(String packageName, boolean waitForDebugger,
7538 boolean persistent) {
7539 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7540 "setDebugApp()");
7541
7542 // Note that this is not really thread safe if there are multiple
7543 // callers into it at the same time, but that's not a situation we
7544 // care about.
7545 if (persistent) {
7546 final ContentResolver resolver = mContext.getContentResolver();
7547 Settings.System.putString(
7548 resolver, Settings.System.DEBUG_APP,
7549 packageName);
7550 Settings.System.putInt(
7551 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7552 waitForDebugger ? 1 : 0);
7553 }
7554
7555 synchronized (this) {
7556 if (!persistent) {
7557 mOrigDebugApp = mDebugApp;
7558 mOrigWaitForDebugger = mWaitForDebugger;
7559 }
7560 mDebugApp = packageName;
7561 mWaitForDebugger = waitForDebugger;
7562 mDebugTransient = !persistent;
7563 if (packageName != null) {
7564 final long origId = Binder.clearCallingIdentity();
7565 uninstallPackageLocked(packageName, -1, false);
7566 Binder.restoreCallingIdentity(origId);
7567 }
7568 }
7569 }
7570
7571 public void setAlwaysFinish(boolean enabled) {
7572 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7573 "setAlwaysFinish()");
7574
7575 Settings.System.putInt(
7576 mContext.getContentResolver(),
7577 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7578
7579 synchronized (this) {
7580 mAlwaysFinishActivities = enabled;
7581 }
7582 }
7583
7584 public void setActivityWatcher(IActivityWatcher watcher) {
7585 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7586 "setActivityWatcher()");
7587 synchronized (this) {
7588 mWatcher = watcher;
7589 }
7590 }
7591
7592 public final void enterSafeMode() {
7593 synchronized(this) {
7594 // It only makes sense to do this before the system is ready
7595 // and started launching other packages.
7596 if (!mSystemReady) {
7597 try {
7598 ActivityThread.getPackageManager().enterSafeMode();
7599 } catch (RemoteException e) {
7600 }
7601
7602 View v = LayoutInflater.from(mContext).inflate(
7603 com.android.internal.R.layout.safe_mode, null);
7604 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7605 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7606 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7607 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7608 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7609 lp.format = v.getBackground().getOpacity();
7610 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7611 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7612 ((WindowManager)mContext.getSystemService(
7613 Context.WINDOW_SERVICE)).addView(v, lp);
7614 }
7615 }
7616 }
7617
7618 public void noteWakeupAlarm(IIntentSender sender) {
7619 if (!(sender instanceof PendingIntentRecord)) {
7620 return;
7621 }
7622 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7623 synchronized (stats) {
7624 if (mBatteryStatsService.isOnBattery()) {
7625 mBatteryStatsService.enforceCallingPermission();
7626 PendingIntentRecord rec = (PendingIntentRecord)sender;
7627 int MY_UID = Binder.getCallingUid();
7628 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7629 BatteryStatsImpl.Uid.Pkg pkg =
7630 stats.getPackageStatsLocked(uid, rec.key.packageName);
7631 pkg.incWakeupsLocked();
7632 }
7633 }
7634 }
7635
7636 public boolean killPidsForMemory(int[] pids) {
7637 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7638 throw new SecurityException("killPidsForMemory only available to the system");
7639 }
7640
7641 // XXX Note: don't acquire main activity lock here, because the window
7642 // manager calls in with its locks held.
7643
7644 boolean killed = false;
7645 synchronized (mPidsSelfLocked) {
7646 int[] types = new int[pids.length];
7647 int worstType = 0;
7648 for (int i=0; i<pids.length; i++) {
7649 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7650 if (proc != null) {
7651 int type = proc.setAdj;
7652 types[i] = type;
7653 if (type > worstType) {
7654 worstType = type;
7655 }
7656 }
7657 }
7658
7659 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7660 // then constrain it so we will kill all hidden procs.
7661 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7662 worstType = HIDDEN_APP_MIN_ADJ;
7663 }
7664 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7665 for (int i=0; i<pids.length; i++) {
7666 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7667 if (proc == null) {
7668 continue;
7669 }
7670 int adj = proc.setAdj;
7671 if (adj >= worstType) {
7672 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7673 + adj + ")");
7674 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7675 proc.processName, adj);
7676 killed = true;
7677 Process.killProcess(pids[i]);
7678 }
7679 }
7680 }
7681 return killed;
7682 }
7683
7684 public void reportPss(IApplicationThread caller, int pss) {
7685 Watchdog.PssRequestor req;
7686 String name;
7687 ProcessRecord callerApp;
7688 synchronized (this) {
7689 if (caller == null) {
7690 return;
7691 }
7692 callerApp = getRecordForAppLocked(caller);
7693 if (callerApp == null) {
7694 return;
7695 }
7696 callerApp.lastPss = pss;
7697 req = callerApp;
7698 name = callerApp.processName;
7699 }
7700 Watchdog.getInstance().reportPss(req, name, pss);
7701 if (!callerApp.persistent) {
7702 removeRequestedPss(callerApp);
7703 }
7704 }
7705
7706 public void requestPss(Runnable completeCallback) {
7707 ArrayList<ProcessRecord> procs;
7708 synchronized (this) {
7709 mRequestPssCallback = completeCallback;
7710 mRequestPssList.clear();
7711 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7712 ProcessRecord proc = mLRUProcesses.get(i);
7713 if (!proc.persistent) {
7714 mRequestPssList.add(proc);
7715 }
7716 }
7717 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7718 }
7719
7720 int oldPri = Process.getThreadPriority(Process.myTid());
7721 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7722 for (int i=procs.size()-1; i>=0; i--) {
7723 ProcessRecord proc = procs.get(i);
7724 proc.lastPss = 0;
7725 proc.requestPss();
7726 }
7727 Process.setThreadPriority(oldPri);
7728 }
7729
7730 void removeRequestedPss(ProcessRecord proc) {
7731 Runnable callback = null;
7732 synchronized (this) {
7733 if (mRequestPssList.remove(proc)) {
7734 if (mRequestPssList.size() == 0) {
7735 callback = mRequestPssCallback;
7736 mRequestPssCallback = null;
7737 }
7738 }
7739 }
7740
7741 if (callback != null) {
7742 callback.run();
7743 }
7744 }
7745
7746 public void collectPss(Watchdog.PssStats stats) {
7747 stats.mEmptyPss = 0;
7748 stats.mEmptyCount = 0;
7749 stats.mBackgroundPss = 0;
7750 stats.mBackgroundCount = 0;
7751 stats.mServicePss = 0;
7752 stats.mServiceCount = 0;
7753 stats.mVisiblePss = 0;
7754 stats.mVisibleCount = 0;
7755 stats.mForegroundPss = 0;
7756 stats.mForegroundCount = 0;
7757 stats.mNoPssCount = 0;
7758 synchronized (this) {
7759 int i;
7760 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7761 ? mProcDeaths.length : stats.mProcDeaths.length;
7762 int aggr = 0;
7763 for (i=0; i<NPD; i++) {
7764 aggr += mProcDeaths[i];
7765 stats.mProcDeaths[i] = aggr;
7766 }
7767 while (i<stats.mProcDeaths.length) {
7768 stats.mProcDeaths[i] = 0;
7769 i++;
7770 }
7771
7772 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7773 ProcessRecord proc = mLRUProcesses.get(i);
7774 if (proc.persistent) {
7775 continue;
7776 }
7777 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7778 if (proc.lastPss == 0) {
7779 stats.mNoPssCount++;
7780 continue;
7781 }
7782 if (proc.setAdj == EMPTY_APP_ADJ) {
7783 stats.mEmptyPss += proc.lastPss;
7784 stats.mEmptyCount++;
7785 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7786 stats.mEmptyPss += proc.lastPss;
7787 stats.mEmptyCount++;
7788 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7789 stats.mBackgroundPss += proc.lastPss;
7790 stats.mBackgroundCount++;
7791 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7792 stats.mVisiblePss += proc.lastPss;
7793 stats.mVisibleCount++;
7794 } else {
7795 stats.mForegroundPss += proc.lastPss;
7796 stats.mForegroundCount++;
7797 }
7798 }
7799 }
7800 }
7801
7802 public final void startRunning(String pkg, String cls, String action,
7803 String data) {
7804 synchronized(this) {
7805 if (mStartRunning) {
7806 return;
7807 }
7808 mStartRunning = true;
7809 mTopComponent = pkg != null && cls != null
7810 ? new ComponentName(pkg, cls) : null;
7811 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7812 mTopData = data;
7813 if (!mSystemReady) {
7814 return;
7815 }
7816 }
7817
7818 systemReady();
7819 }
7820
7821 private void retrieveSettings() {
7822 final ContentResolver resolver = mContext.getContentResolver();
7823 String debugApp = Settings.System.getString(
7824 resolver, Settings.System.DEBUG_APP);
7825 boolean waitForDebugger = Settings.System.getInt(
7826 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7827 boolean alwaysFinishActivities = Settings.System.getInt(
7828 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7829
7830 Configuration configuration = new Configuration();
7831 Settings.System.getConfiguration(resolver, configuration);
7832
7833 synchronized (this) {
7834 mDebugApp = mOrigDebugApp = debugApp;
7835 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7836 mAlwaysFinishActivities = alwaysFinishActivities;
7837 // This happens before any activities are started, so we can
7838 // change mConfiguration in-place.
7839 mConfiguration.updateFrom(configuration);
7840 }
7841 }
7842
7843 public boolean testIsSystemReady() {
7844 // no need to synchronize(this) just to read & return the value
7845 return mSystemReady;
7846 }
7847
7848 public void systemReady() {
7849 // In the simulator, startRunning will never have been called, which
7850 // normally sets a few crucial variables. Do it here instead.
7851 if (!Process.supportsProcesses()) {
7852 mStartRunning = true;
7853 mTopAction = Intent.ACTION_MAIN;
7854 }
7855
7856 synchronized(this) {
7857 if (mSystemReady) {
7858 return;
7859 }
7860 mSystemReady = true;
7861 if (!mStartRunning) {
7862 return;
7863 }
7864 }
7865
7866 if (Config.LOGD) Log.d(TAG, "Start running!");
7867 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7868 SystemClock.uptimeMillis());
7869
7870 synchronized(this) {
7871 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7872 ResolveInfo ri = mContext.getPackageManager()
7873 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007874 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007875 CharSequence errorMsg = null;
7876 if (ri != null) {
7877 ActivityInfo ai = ri.activityInfo;
7878 ApplicationInfo app = ai.applicationInfo;
7879 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7880 mTopAction = Intent.ACTION_FACTORY_TEST;
7881 mTopData = null;
7882 mTopComponent = new ComponentName(app.packageName,
7883 ai.name);
7884 } else {
7885 errorMsg = mContext.getResources().getText(
7886 com.android.internal.R.string.factorytest_not_system);
7887 }
7888 } else {
7889 errorMsg = mContext.getResources().getText(
7890 com.android.internal.R.string.factorytest_no_action);
7891 }
7892 if (errorMsg != null) {
7893 mTopAction = null;
7894 mTopData = null;
7895 mTopComponent = null;
7896 Message msg = Message.obtain();
7897 msg.what = SHOW_FACTORY_ERROR_MSG;
7898 msg.getData().putCharSequence("msg", errorMsg);
7899 mHandler.sendMessage(msg);
7900 }
7901 }
7902 }
7903
7904 retrieveSettings();
7905
7906 synchronized (this) {
7907 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7908 try {
7909 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007910 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007911 if (apps != null) {
7912 int N = apps.size();
7913 int i;
7914 for (i=0; i<N; i++) {
7915 ApplicationInfo info
7916 = (ApplicationInfo)apps.get(i);
7917 if (info != null &&
7918 !info.packageName.equals("android")) {
7919 addAppLocked(info);
7920 }
7921 }
7922 }
7923 } catch (RemoteException ex) {
7924 // pm is in same process, this will never happen.
7925 }
7926 }
7927
7928 try {
7929 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7930 Message msg = Message.obtain();
7931 msg.what = SHOW_UID_ERROR_MSG;
7932 mHandler.sendMessage(msg);
7933 }
7934 } catch (RemoteException e) {
7935 }
7936
7937 // Start up initial activity.
7938 mBooting = true;
7939 resumeTopActivityLocked(null);
7940 }
7941 }
7942
7943 boolean makeAppCrashingLocked(ProcessRecord app,
7944 String tag, String shortMsg, String longMsg, byte[] crashData) {
7945 app.crashing = true;
7946 app.crashingReport = generateProcessError(app,
7947 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7948 startAppProblemLocked(app);
7949 app.stopFreezingAllLocked();
7950 return handleAppCrashLocked(app);
7951 }
7952
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007953 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7954 IPackageManager pm = ActivityThread.getPackageManager();
7955 try {
7956 // was an installer package name specified when this app was
7957 // installed?
7958 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7959 if (installerPackageName == null) {
7960 return null;
7961 }
7962
7963 // is there an Activity in this package that handles ACTION_APP_ERROR?
7964 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07007965 intent.setPackage(installerPackageName);
7966 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007967 if (info == null || info.activityInfo == null) {
7968 return null;
7969 }
7970
7971 return new ComponentName(installerPackageName, info.activityInfo.name);
7972 } catch (RemoteException e) {
7973 // will return null and no error report will be delivered
7974 }
7975 return null;
7976 }
7977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007978 void makeAppNotRespondingLocked(ProcessRecord app,
7979 String tag, String shortMsg, String longMsg, byte[] crashData) {
7980 app.notResponding = true;
7981 app.notRespondingReport = generateProcessError(app,
7982 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7983 crashData);
7984 startAppProblemLocked(app);
7985 app.stopFreezingAllLocked();
7986 }
7987
7988 /**
7989 * Generate a process error record, suitable for attachment to a ProcessRecord.
7990 *
7991 * @param app The ProcessRecord in which the error occurred.
7992 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7993 * ActivityManager.AppErrorStateInfo
7994 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7995 * @param shortMsg Short message describing the crash.
7996 * @param longMsg Long message describing the crash.
7997 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7998 *
7999 * @return Returns a fully-formed AppErrorStateInfo record.
8000 */
8001 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8002 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8003 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8004
8005 report.condition = condition;
8006 report.processName = app.processName;
8007 report.pid = app.pid;
8008 report.uid = app.info.uid;
8009 report.tag = tag;
8010 report.shortMsg = shortMsg;
8011 report.longMsg = longMsg;
8012 report.crashData = crashData;
8013
8014 return report;
8015 }
8016
8017 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8018 boolean crashed) {
8019 synchronized (this) {
8020 app.crashing = false;
8021 app.crashingReport = null;
8022 app.notResponding = false;
8023 app.notRespondingReport = null;
8024 if (app.anrDialog == fromDialog) {
8025 app.anrDialog = null;
8026 }
8027 if (app.waitDialog == fromDialog) {
8028 app.waitDialog = null;
8029 }
8030 if (app.pid > 0 && app.pid != MY_PID) {
8031 if (crashed) {
8032 handleAppCrashLocked(app);
8033 }
8034 Log.i(ActivityManagerService.TAG, "Killing process "
8035 + app.processName
8036 + " (pid=" + app.pid + ") at user's request");
8037 Process.killProcess(app.pid);
8038 }
8039
8040 }
8041 }
8042
8043 boolean handleAppCrashLocked(ProcessRecord app) {
8044 long now = SystemClock.uptimeMillis();
8045
8046 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8047 app.info.uid);
8048 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8049 // This process loses!
8050 Log.w(TAG, "Process " + app.info.processName
8051 + " has crashed too many times: killing!");
8052 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8053 app.info.processName, app.info.uid);
8054 killServicesLocked(app, false);
8055 for (int i=mHistory.size()-1; i>=0; i--) {
8056 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8057 if (r.app == app) {
8058 if (Config.LOGD) Log.d(
8059 TAG, " Force finishing activity "
8060 + r.intent.getComponent().flattenToShortString());
8061 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8062 }
8063 }
8064 if (!app.persistent) {
8065 // We don't want to start this process again until the user
8066 // explicitly does so... but for persistent process, we really
8067 // need to keep it running. If a persistent process is actually
8068 // repeatedly crashing, then badness for everyone.
8069 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8070 app.info.processName);
8071 mBadProcesses.put(app.info.processName, app.info.uid, now);
8072 app.bad = true;
8073 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8074 app.removed = true;
8075 removeProcessLocked(app, false);
8076 return false;
8077 }
8078 }
8079
8080 // Bump up the crash count of any services currently running in the proc.
8081 if (app.services.size() != 0) {
8082 // Any services running in the application need to be placed
8083 // back in the pending list.
8084 Iterator it = app.services.iterator();
8085 while (it.hasNext()) {
8086 ServiceRecord sr = (ServiceRecord)it.next();
8087 sr.crashCount++;
8088 }
8089 }
8090
8091 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8092 return true;
8093 }
8094
8095 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008096 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008097 skipCurrentReceiverLocked(app);
8098 }
8099
8100 void skipCurrentReceiverLocked(ProcessRecord app) {
8101 boolean reschedule = false;
8102 BroadcastRecord r = app.curReceiver;
8103 if (r != null) {
8104 // The current broadcast is waiting for this app's receiver
8105 // to be finished. Looks like that's not going to happen, so
8106 // let the broadcast continue.
8107 logBroadcastReceiverDiscard(r);
8108 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8109 r.resultExtras, r.resultAbort, true);
8110 reschedule = true;
8111 }
8112 r = mPendingBroadcast;
8113 if (r != null && r.curApp == app) {
8114 if (DEBUG_BROADCAST) Log.v(TAG,
8115 "skip & discard pending app " + r);
8116 logBroadcastReceiverDiscard(r);
8117 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8118 r.resultExtras, r.resultAbort, true);
8119 reschedule = true;
8120 }
8121 if (reschedule) {
8122 scheduleBroadcastsLocked();
8123 }
8124 }
8125
8126 public int handleApplicationError(IBinder app, int flags,
8127 String tag, String shortMsg, String longMsg, byte[] crashData) {
8128 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008129 ProcessRecord r = null;
8130 synchronized (this) {
8131 if (app != null) {
8132 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8133 final int NA = apps.size();
8134 for (int ia=0; ia<NA; ia++) {
8135 ProcessRecord p = apps.valueAt(ia);
8136 if (p.thread != null && p.thread.asBinder() == app) {
8137 r = p;
8138 break;
8139 }
8140 }
8141 }
8142 }
8143
8144 if (r != null) {
8145 // The application has crashed. Send the SIGQUIT to the process so
8146 // that it can dump its state.
8147 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8148 //Log.i(TAG, "Current system threads:");
8149 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8150 }
8151
8152 if (mWatcher != null) {
8153 try {
8154 String name = r != null ? r.processName : null;
8155 int pid = r != null ? r.pid : Binder.getCallingPid();
8156 if (!mWatcher.appCrashed(name, pid,
8157 shortMsg, longMsg, crashData)) {
8158 Log.w(TAG, "Force-killing crashed app " + name
8159 + " at watcher's request");
8160 Process.killProcess(pid);
8161 return 0;
8162 }
8163 } catch (RemoteException e) {
8164 mWatcher = null;
8165 }
8166 }
8167
8168 final long origId = Binder.clearCallingIdentity();
8169
8170 // If this process is running instrumentation, finish it.
8171 if (r != null && r.instrumentationClass != null) {
8172 Log.w(TAG, "Error in app " + r.processName
8173 + " running instrumentation " + r.instrumentationClass + ":");
8174 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8175 if (longMsg != null) Log.w(TAG, " " + longMsg);
8176 Bundle info = new Bundle();
8177 info.putString("shortMsg", shortMsg);
8178 info.putString("longMsg", longMsg);
8179 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8180 Binder.restoreCallingIdentity(origId);
8181 return 0;
8182 }
8183
8184 if (r != null) {
8185 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8186 return 0;
8187 }
8188 } else {
8189 Log.w(TAG, "Some application object " + app + " tag " + tag
8190 + " has crashed, but I don't know who it is.");
8191 Log.w(TAG, "ShortMsg:" + shortMsg);
8192 Log.w(TAG, "LongMsg:" + longMsg);
8193 Binder.restoreCallingIdentity(origId);
8194 return 0;
8195 }
8196
8197 Message msg = Message.obtain();
8198 msg.what = SHOW_ERROR_MSG;
8199 HashMap data = new HashMap();
8200 data.put("result", result);
8201 data.put("app", r);
8202 data.put("flags", flags);
8203 data.put("shortMsg", shortMsg);
8204 data.put("longMsg", longMsg);
8205 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8206 // For system processes, submit crash data to the server.
8207 data.put("crashData", crashData);
8208 }
8209 msg.obj = data;
8210 mHandler.sendMessage(msg);
8211
8212 Binder.restoreCallingIdentity(origId);
8213 }
8214
8215 int res = result.get();
8216
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008217 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008218 synchronized (this) {
8219 if (r != null) {
8220 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8221 SystemClock.uptimeMillis());
8222 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008223 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8224 appErrorIntent = createAppErrorIntentLocked(r);
8225 res = AppErrorDialog.FORCE_QUIT;
8226 }
8227 }
8228
8229 if (appErrorIntent != null) {
8230 try {
8231 mContext.startActivity(appErrorIntent);
8232 } catch (ActivityNotFoundException e) {
8233 Log.w(TAG, "bug report receiver dissappeared", e);
8234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008235 }
8236
8237 return res;
8238 }
8239
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008240 Intent createAppErrorIntentLocked(ProcessRecord r) {
8241 ApplicationErrorReport report = createAppErrorReportLocked(r);
8242 if (report == null) {
8243 return null;
8244 }
8245 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8246 result.setComponent(r.errorReportReceiver);
8247 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8248 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8249 return result;
8250 }
8251
8252 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8253 if (r.errorReportReceiver == null) {
8254 return null;
8255 }
8256
8257 if (!r.crashing && !r.notResponding) {
8258 return null;
8259 }
8260
8261 try {
8262 ApplicationErrorReport report = new ApplicationErrorReport();
8263 report.packageName = r.info.packageName;
8264 report.installerPackageName = r.errorReportReceiver.getPackageName();
8265 report.processName = r.processName;
8266
8267 if (r.crashing) {
8268 report.type = ApplicationErrorReport.TYPE_CRASH;
8269 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8270
8271 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8272 r.crashingReport.crashData);
8273 DataInputStream dataStream = new DataInputStream(byteStream);
8274 CrashData crashData = new CrashData(dataStream);
8275 ThrowableData throwData = crashData.getThrowableData();
8276
8277 report.time = crashData.getTime();
8278 report.crashInfo.stackTrace = throwData.toString();
8279
Jacek Surazskif829a782009-06-11 22:47:02 +02008280 // Extract the source of the exception, useful for report
8281 // clustering. Also extract the "deepest" non-null exception
8282 // message.
8283 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008284 while (throwData.getCause() != null) {
8285 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008286 String msg = throwData.getMessage();
8287 if (msg != null && msg.length() > 0) {
8288 exceptionMessage = msg;
8289 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008290 }
8291 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008292 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008293 report.crashInfo.exceptionClassName = throwData.getType();
8294 report.crashInfo.throwFileName = trace.getFileName();
8295 report.crashInfo.throwClassName = trace.getClassName();
8296 report.crashInfo.throwMethodName = trace.getMethodName();
8297 } else if (r.notResponding) {
8298 report.type = ApplicationErrorReport.TYPE_ANR;
8299 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8300
8301 report.anrInfo.activity = r.notRespondingReport.tag;
8302 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8303 report.anrInfo.info = r.notRespondingReport.longMsg;
8304 }
8305
8306 return report;
8307 } catch (IOException e) {
8308 // we don't send it
8309 }
8310
8311 return null;
8312 }
8313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008314 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8315 // assume our apps are happy - lazy create the list
8316 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8317
8318 synchronized (this) {
8319
8320 // iterate across all processes
8321 final int N = mLRUProcesses.size();
8322 for (int i = 0; i < N; i++) {
8323 ProcessRecord app = mLRUProcesses.get(i);
8324 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8325 // This one's in trouble, so we'll generate a report for it
8326 // crashes are higher priority (in case there's a crash *and* an anr)
8327 ActivityManager.ProcessErrorStateInfo report = null;
8328 if (app.crashing) {
8329 report = app.crashingReport;
8330 } else if (app.notResponding) {
8331 report = app.notRespondingReport;
8332 }
8333
8334 if (report != null) {
8335 if (errList == null) {
8336 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8337 }
8338 errList.add(report);
8339 } else {
8340 Log.w(TAG, "Missing app error report, app = " + app.processName +
8341 " crashing = " + app.crashing +
8342 " notResponding = " + app.notResponding);
8343 }
8344 }
8345 }
8346 }
8347
8348 return errList;
8349 }
8350
8351 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8352 // Lazy instantiation of list
8353 List<ActivityManager.RunningAppProcessInfo> runList = null;
8354 synchronized (this) {
8355 // Iterate across all processes
8356 final int N = mLRUProcesses.size();
8357 for (int i = 0; i < N; i++) {
8358 ProcessRecord app = mLRUProcesses.get(i);
8359 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8360 // Generate process state info for running application
8361 ActivityManager.RunningAppProcessInfo currApp =
8362 new ActivityManager.RunningAppProcessInfo(app.processName,
8363 app.pid, app.getPackageList());
8364 int adj = app.curAdj;
8365 if (adj >= CONTENT_PROVIDER_ADJ) {
8366 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8367 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8368 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008369 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8370 } else if (adj >= HOME_APP_ADJ) {
8371 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8372 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008373 } else if (adj >= SECONDARY_SERVER_ADJ) {
8374 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8375 } else if (adj >= VISIBLE_APP_ADJ) {
8376 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8377 } else {
8378 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8379 }
8380 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8381 // + " lru=" + currApp.lru);
8382 if (runList == null) {
8383 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8384 }
8385 runList.add(currApp);
8386 }
8387 }
8388 }
8389 return runList;
8390 }
8391
8392 @Override
8393 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8394 synchronized (this) {
8395 if (checkCallingPermission(android.Manifest.permission.DUMP)
8396 != PackageManager.PERMISSION_GRANTED) {
8397 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8398 + Binder.getCallingPid()
8399 + ", uid=" + Binder.getCallingUid()
8400 + " without permission "
8401 + android.Manifest.permission.DUMP);
8402 return;
8403 }
8404 if (args.length != 0 && "service".equals(args[0])) {
8405 dumpService(fd, pw, args);
8406 return;
8407 }
8408 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008409 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008410 pw.println(" ");
8411 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008412 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 if (mWaitingVisibleActivities.size() > 0) {
8414 pw.println(" ");
8415 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008416 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008417 }
8418 if (mStoppingActivities.size() > 0) {
8419 pw.println(" ");
8420 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008421 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008422 }
8423 if (mFinishingActivities.size() > 0) {
8424 pw.println(" ");
8425 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008426 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008427 }
8428
8429 pw.println(" ");
8430 pw.println(" mPausingActivity: " + mPausingActivity);
8431 pw.println(" mResumedActivity: " + mResumedActivity);
8432 pw.println(" mFocusedActivity: " + mFocusedActivity);
8433 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8434
8435 if (mRecentTasks.size() > 0) {
8436 pw.println(" ");
8437 pw.println("Recent tasks in Current Activity Manager State:");
8438
8439 final int N = mRecentTasks.size();
8440 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008441 TaskRecord tr = mRecentTasks.get(i);
8442 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8443 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008444 mRecentTasks.get(i).dump(pw, " ");
8445 }
8446 }
8447
8448 pw.println(" ");
8449 pw.println(" mCurTask: " + mCurTask);
8450
8451 pw.println(" ");
8452 pw.println("Processes in Current Activity Manager State:");
8453
8454 boolean needSep = false;
8455 int numPers = 0;
8456
8457 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8458 final int NA = procs.size();
8459 for (int ia=0; ia<NA; ia++) {
8460 if (!needSep) {
8461 pw.println(" All known processes:");
8462 needSep = true;
8463 }
8464 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008465 pw.print(r.persistent ? " *PERS*" : " *APP*");
8466 pw.print(" UID "); pw.print(procs.keyAt(ia));
8467 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008468 r.dump(pw, " ");
8469 if (r.persistent) {
8470 numPers++;
8471 }
8472 }
8473 }
8474
8475 if (mLRUProcesses.size() > 0) {
8476 if (needSep) pw.println(" ");
8477 needSep = true;
8478 pw.println(" Running processes (most recent first):");
8479 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008480 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008481 needSep = true;
8482 }
8483
8484 synchronized (mPidsSelfLocked) {
8485 if (mPidsSelfLocked.size() > 0) {
8486 if (needSep) pw.println(" ");
8487 needSep = true;
8488 pw.println(" PID mappings:");
8489 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008490 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8491 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008492 }
8493 }
8494 }
8495
8496 if (mForegroundProcesses.size() > 0) {
8497 if (needSep) pw.println(" ");
8498 needSep = true;
8499 pw.println(" Foreground Processes:");
8500 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008501 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8502 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 }
8504 }
8505
8506 if (mPersistentStartingProcesses.size() > 0) {
8507 if (needSep) pw.println(" ");
8508 needSep = true;
8509 pw.println(" Persisent processes that are starting:");
8510 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008511 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008512 }
8513
8514 if (mStartingProcesses.size() > 0) {
8515 if (needSep) pw.println(" ");
8516 needSep = true;
8517 pw.println(" Processes that are starting:");
8518 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008519 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 }
8521
8522 if (mRemovedProcesses.size() > 0) {
8523 if (needSep) pw.println(" ");
8524 needSep = true;
8525 pw.println(" Processes that are being removed:");
8526 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008527 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008528 }
8529
8530 if (mProcessesOnHold.size() > 0) {
8531 if (needSep) pw.println(" ");
8532 needSep = true;
8533 pw.println(" Processes that are on old until the system is ready:");
8534 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008535 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008536 }
8537
8538 if (mProcessCrashTimes.getMap().size() > 0) {
8539 if (needSep) pw.println(" ");
8540 needSep = true;
8541 pw.println(" Time since processes crashed:");
8542 long now = SystemClock.uptimeMillis();
8543 for (Map.Entry<String, SparseArray<Long>> procs
8544 : mProcessCrashTimes.getMap().entrySet()) {
8545 SparseArray<Long> uids = procs.getValue();
8546 final int N = uids.size();
8547 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008548 pw.print(" Process "); pw.print(procs.getKey());
8549 pw.print(" uid "); pw.print(uids.keyAt(i));
8550 pw.print(": last crashed ");
8551 pw.print((now-uids.valueAt(i)));
8552 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008553 }
8554 }
8555 }
8556
8557 if (mBadProcesses.getMap().size() > 0) {
8558 if (needSep) pw.println(" ");
8559 needSep = true;
8560 pw.println(" Bad processes:");
8561 for (Map.Entry<String, SparseArray<Long>> procs
8562 : mBadProcesses.getMap().entrySet()) {
8563 SparseArray<Long> uids = procs.getValue();
8564 final int N = uids.size();
8565 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008566 pw.print(" Bad process "); pw.print(procs.getKey());
8567 pw.print(" uid "); pw.print(uids.keyAt(i));
8568 pw.print(": crashed at time ");
8569 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008570 }
8571 }
8572 }
8573
8574 pw.println(" ");
8575 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008576 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008577 pw.println(" mConfiguration: " + mConfiguration);
8578 pw.println(" mStartRunning=" + mStartRunning
8579 + " mSystemReady=" + mSystemReady
8580 + " mBooting=" + mBooting
8581 + " mBooted=" + mBooted
8582 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008583 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008584 pw.println(" mGoingToSleep=" + mGoingToSleep);
8585 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8586 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8587 + " mDebugTransient=" + mDebugTransient
8588 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8589 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8590 + " mWatcher=" + mWatcher);
8591 }
8592 }
8593
8594 /**
8595 * There are three ways to call this:
8596 * - no service specified: dump all the services
8597 * - a flattened component name that matched an existing service was specified as the
8598 * first arg: dump that one service
8599 * - the first arg isn't the flattened component name of an existing service:
8600 * dump all services whose component contains the first arg as a substring
8601 */
8602 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8603 String[] newArgs;
8604 String componentNameString;
8605 ServiceRecord r;
8606 if (args.length == 1) {
8607 componentNameString = null;
8608 newArgs = EMPTY_STRING_ARRAY;
8609 r = null;
8610 } else {
8611 componentNameString = args[1];
8612 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8613 r = componentName != null ? mServices.get(componentName) : null;
8614 newArgs = new String[args.length - 2];
8615 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8616 }
8617
8618 if (r != null) {
8619 dumpService(fd, pw, r, newArgs);
8620 } else {
8621 for (ServiceRecord r1 : mServices.values()) {
8622 if (componentNameString == null
8623 || r1.name.flattenToString().contains(componentNameString)) {
8624 dumpService(fd, pw, r1, newArgs);
8625 }
8626 }
8627 }
8628 }
8629
8630 /**
8631 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8632 * there is a thread associated with the service.
8633 */
8634 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8635 pw.println(" Service " + r.name.flattenToString());
8636 if (r.app != null && r.app.thread != null) {
8637 try {
8638 // flush anything that is already in the PrintWriter since the thread is going
8639 // to write to the file descriptor directly
8640 pw.flush();
8641 r.app.thread.dumpService(fd, r, args);
8642 pw.print("\n");
8643 } catch (RemoteException e) {
8644 pw.println("got a RemoteException while dumping the service");
8645 }
8646 }
8647 }
8648
8649 void dumpBroadcasts(PrintWriter pw) {
8650 synchronized (this) {
8651 if (checkCallingPermission(android.Manifest.permission.DUMP)
8652 != PackageManager.PERMISSION_GRANTED) {
8653 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8654 + Binder.getCallingPid()
8655 + ", uid=" + Binder.getCallingUid()
8656 + " without permission "
8657 + android.Manifest.permission.DUMP);
8658 return;
8659 }
8660 pw.println("Broadcasts in Current Activity Manager State:");
8661
8662 if (mRegisteredReceivers.size() > 0) {
8663 pw.println(" ");
8664 pw.println(" Registered Receivers:");
8665 Iterator it = mRegisteredReceivers.values().iterator();
8666 while (it.hasNext()) {
8667 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008668 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008669 r.dump(pw, " ");
8670 }
8671 }
8672
8673 pw.println(" ");
8674 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008675 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008676
8677 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8678 || mPendingBroadcast != null) {
8679 if (mParallelBroadcasts.size() > 0) {
8680 pw.println(" ");
8681 pw.println(" Active broadcasts:");
8682 }
8683 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8684 pw.println(" Broadcast #" + i + ":");
8685 mParallelBroadcasts.get(i).dump(pw, " ");
8686 }
8687 if (mOrderedBroadcasts.size() > 0) {
8688 pw.println(" ");
8689 pw.println(" Active serialized broadcasts:");
8690 }
8691 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8692 pw.println(" Serialized Broadcast #" + i + ":");
8693 mOrderedBroadcasts.get(i).dump(pw, " ");
8694 }
8695 pw.println(" ");
8696 pw.println(" Pending broadcast:");
8697 if (mPendingBroadcast != null) {
8698 mPendingBroadcast.dump(pw, " ");
8699 } else {
8700 pw.println(" (null)");
8701 }
8702 }
8703
8704 pw.println(" ");
8705 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8706 if (mStickyBroadcasts != null) {
8707 pw.println(" ");
8708 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008709 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008710 for (Map.Entry<String, ArrayList<Intent>> ent
8711 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008712 pw.print(" * Sticky action "); pw.print(ent.getKey());
8713 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 ArrayList<Intent> intents = ent.getValue();
8715 final int N = intents.size();
8716 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008717 sb.setLength(0);
8718 sb.append(" Intent: ");
8719 intents.get(i).toShortString(sb, true, false);
8720 pw.println(sb.toString());
8721 Bundle bundle = intents.get(i).getExtras();
8722 if (bundle != null) {
8723 pw.print(" ");
8724 pw.println(bundle.toString());
8725 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008726 }
8727 }
8728 }
8729
8730 pw.println(" ");
8731 pw.println(" mHandler:");
8732 mHandler.dump(new PrintWriterPrinter(pw), " ");
8733 }
8734 }
8735
8736 void dumpServices(PrintWriter pw) {
8737 synchronized (this) {
8738 if (checkCallingPermission(android.Manifest.permission.DUMP)
8739 != PackageManager.PERMISSION_GRANTED) {
8740 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8741 + Binder.getCallingPid()
8742 + ", uid=" + Binder.getCallingUid()
8743 + " without permission "
8744 + android.Manifest.permission.DUMP);
8745 return;
8746 }
8747 pw.println("Services in Current Activity Manager State:");
8748
8749 boolean needSep = false;
8750
8751 if (mServices.size() > 0) {
8752 pw.println(" Active services:");
8753 Iterator<ServiceRecord> it = mServices.values().iterator();
8754 while (it.hasNext()) {
8755 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008756 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008757 r.dump(pw, " ");
8758 }
8759 needSep = true;
8760 }
8761
8762 if (mPendingServices.size() > 0) {
8763 if (needSep) pw.println(" ");
8764 pw.println(" Pending services:");
8765 for (int i=0; i<mPendingServices.size(); i++) {
8766 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008767 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008768 r.dump(pw, " ");
8769 }
8770 needSep = true;
8771 }
8772
8773 if (mRestartingServices.size() > 0) {
8774 if (needSep) pw.println(" ");
8775 pw.println(" Restarting services:");
8776 for (int i=0; i<mRestartingServices.size(); i++) {
8777 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008778 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008779 r.dump(pw, " ");
8780 }
8781 needSep = true;
8782 }
8783
8784 if (mStoppingServices.size() > 0) {
8785 if (needSep) pw.println(" ");
8786 pw.println(" Stopping services:");
8787 for (int i=0; i<mStoppingServices.size(); i++) {
8788 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008789 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008790 r.dump(pw, " ");
8791 }
8792 needSep = true;
8793 }
8794
8795 if (mServiceConnections.size() > 0) {
8796 if (needSep) pw.println(" ");
8797 pw.println(" Connection bindings to services:");
8798 Iterator<ConnectionRecord> it
8799 = mServiceConnections.values().iterator();
8800 while (it.hasNext()) {
8801 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008802 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008803 r.dump(pw, " ");
8804 }
8805 }
8806 }
8807 }
8808
8809 void dumpProviders(PrintWriter pw) {
8810 synchronized (this) {
8811 if (checkCallingPermission(android.Manifest.permission.DUMP)
8812 != PackageManager.PERMISSION_GRANTED) {
8813 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8814 + Binder.getCallingPid()
8815 + ", uid=" + Binder.getCallingUid()
8816 + " without permission "
8817 + android.Manifest.permission.DUMP);
8818 return;
8819 }
8820
8821 pw.println("Content Providers in Current Activity Manager State:");
8822
8823 boolean needSep = false;
8824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008825 if (mProvidersByClass.size() > 0) {
8826 if (needSep) pw.println(" ");
8827 pw.println(" Published content providers (by class):");
8828 Iterator it = mProvidersByClass.entrySet().iterator();
8829 while (it.hasNext()) {
8830 Map.Entry e = (Map.Entry)it.next();
8831 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008832 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008833 r.dump(pw, " ");
8834 }
8835 needSep = true;
8836 }
8837
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008838 if (mProvidersByName.size() > 0) {
8839 pw.println(" ");
8840 pw.println(" Authority to provider mappings:");
8841 Iterator it = mProvidersByName.entrySet().iterator();
8842 while (it.hasNext()) {
8843 Map.Entry e = (Map.Entry)it.next();
8844 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8845 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8846 pw.println(r);
8847 }
8848 needSep = true;
8849 }
8850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008851 if (mLaunchingProviders.size() > 0) {
8852 if (needSep) pw.println(" ");
8853 pw.println(" Launching content providers:");
8854 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008855 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8856 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008857 }
8858 needSep = true;
8859 }
8860
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008861 if (mGrantedUriPermissions.size() > 0) {
8862 pw.println();
8863 pw.println("Granted Uri Permissions:");
8864 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8865 int uid = mGrantedUriPermissions.keyAt(i);
8866 HashMap<Uri, UriPermission> perms
8867 = mGrantedUriPermissions.valueAt(i);
8868 pw.print(" * UID "); pw.print(uid);
8869 pw.println(" holds:");
8870 for (UriPermission perm : perms.values()) {
8871 pw.print(" "); pw.println(perm);
8872 perm.dump(pw, " ");
8873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008874 }
8875 }
8876 }
8877 }
8878
8879 void dumpSenders(PrintWriter pw) {
8880 synchronized (this) {
8881 if (checkCallingPermission(android.Manifest.permission.DUMP)
8882 != PackageManager.PERMISSION_GRANTED) {
8883 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8884 + Binder.getCallingPid()
8885 + ", uid=" + Binder.getCallingUid()
8886 + " without permission "
8887 + android.Manifest.permission.DUMP);
8888 return;
8889 }
8890
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008891 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008892
8893 if (this.mIntentSenderRecords.size() > 0) {
8894 Iterator<WeakReference<PendingIntentRecord>> it
8895 = mIntentSenderRecords.values().iterator();
8896 while (it.hasNext()) {
8897 WeakReference<PendingIntentRecord> ref = it.next();
8898 PendingIntentRecord rec = ref != null ? ref.get(): null;
8899 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008900 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008901 rec.dump(pw, " ");
8902 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008903 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008904 }
8905 }
8906 }
8907 }
8908 }
8909
8910 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008911 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008912 TaskRecord lastTask = null;
8913 for (int i=list.size()-1; i>=0; i--) {
8914 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008915 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008916 if (lastTask != r.task) {
8917 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008918 pw.print(prefix);
8919 pw.print(full ? "* " : " ");
8920 pw.println(lastTask);
8921 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008922 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008924 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008925 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8926 pw.print(" #"); pw.print(i); pw.print(": ");
8927 pw.println(r);
8928 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008929 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 }
8932 }
8933
8934 private static final int dumpProcessList(PrintWriter pw, List list,
8935 String prefix, String normalLabel, String persistentLabel,
8936 boolean inclOomAdj) {
8937 int numPers = 0;
8938 for (int i=list.size()-1; i>=0; i--) {
8939 ProcessRecord r = (ProcessRecord)list.get(i);
8940 if (false) {
8941 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8942 + " #" + i + ":");
8943 r.dump(pw, prefix + " ");
8944 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008945 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008946 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008947 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008948 } else {
8949 pw.println(String.format("%s%s #%2d: %s",
8950 prefix, (r.persistent ? persistentLabel : normalLabel),
8951 i, r.toString()));
8952 }
8953 if (r.persistent) {
8954 numPers++;
8955 }
8956 }
8957 return numPers;
8958 }
8959
8960 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8961 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008962 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008963 long uptime = SystemClock.uptimeMillis();
8964 long realtime = SystemClock.elapsedRealtime();
8965
8966 if (isCheckinRequest) {
8967 // short checkin version
8968 pw.println(uptime + "," + realtime);
8969 pw.flush();
8970 } else {
8971 pw.println("Applications Memory Usage (kB):");
8972 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8973 }
8974 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8975 ProcessRecord r = (ProcessRecord)list.get(i);
8976 if (r.thread != null) {
8977 if (!isCheckinRequest) {
8978 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8979 pw.flush();
8980 }
8981 try {
8982 r.thread.asBinder().dump(fd, args);
8983 } catch (RemoteException e) {
8984 if (!isCheckinRequest) {
8985 pw.println("Got RemoteException!");
8986 pw.flush();
8987 }
8988 }
8989 }
8990 }
8991 }
8992
8993 /**
8994 * Searches array of arguments for the specified string
8995 * @param args array of argument strings
8996 * @param value value to search for
8997 * @return true if the value is contained in the array
8998 */
8999 private static boolean scanArgs(String[] args, String value) {
9000 if (args != null) {
9001 for (String arg : args) {
9002 if (value.equals(arg)) {
9003 return true;
9004 }
9005 }
9006 }
9007 return false;
9008 }
9009
Dianne Hackborn75b03852009-06-12 15:43:26 -07009010 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009011 int count = mHistory.size();
9012
9013 // convert the token to an entry in the history.
9014 HistoryRecord r = null;
9015 int index = -1;
9016 for (int i=count-1; i>=0; i--) {
9017 Object o = mHistory.get(i);
9018 if (o == token) {
9019 r = (HistoryRecord)o;
9020 index = i;
9021 break;
9022 }
9023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024
9025 return index;
9026 }
9027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009028 private final void killServicesLocked(ProcessRecord app,
9029 boolean allowRestart) {
9030 // Report disconnected services.
9031 if (false) {
9032 // XXX we are letting the client link to the service for
9033 // death notifications.
9034 if (app.services.size() > 0) {
9035 Iterator it = app.services.iterator();
9036 while (it.hasNext()) {
9037 ServiceRecord r = (ServiceRecord)it.next();
9038 if (r.connections.size() > 0) {
9039 Iterator<ConnectionRecord> jt
9040 = r.connections.values().iterator();
9041 while (jt.hasNext()) {
9042 ConnectionRecord c = jt.next();
9043 if (c.binding.client != app) {
9044 try {
9045 //c.conn.connected(r.className, null);
9046 } catch (Exception e) {
9047 // todo: this should be asynchronous!
9048 Log.w(TAG, "Exception thrown disconnected servce "
9049 + r.shortName
9050 + " from app " + app.processName, e);
9051 }
9052 }
9053 }
9054 }
9055 }
9056 }
9057 }
9058
9059 // Clean up any connections this application has to other services.
9060 if (app.connections.size() > 0) {
9061 Iterator<ConnectionRecord> it = app.connections.iterator();
9062 while (it.hasNext()) {
9063 ConnectionRecord r = it.next();
9064 removeConnectionLocked(r, app, null);
9065 }
9066 }
9067 app.connections.clear();
9068
9069 if (app.services.size() != 0) {
9070 // Any services running in the application need to be placed
9071 // back in the pending list.
9072 Iterator it = app.services.iterator();
9073 while (it.hasNext()) {
9074 ServiceRecord sr = (ServiceRecord)it.next();
9075 synchronized (sr.stats.getBatteryStats()) {
9076 sr.stats.stopLaunchedLocked();
9077 }
9078 sr.app = null;
9079 sr.executeNesting = 0;
9080 mStoppingServices.remove(sr);
9081 if (sr.bindings.size() > 0) {
9082 Iterator<IntentBindRecord> bindings
9083 = sr.bindings.values().iterator();
9084 while (bindings.hasNext()) {
9085 IntentBindRecord b = bindings.next();
9086 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9087 + ": shouldUnbind=" + b.hasBound);
9088 b.binder = null;
9089 b.requested = b.received = b.hasBound = false;
9090 }
9091 }
9092
9093 if (sr.crashCount >= 2) {
9094 Log.w(TAG, "Service crashed " + sr.crashCount
9095 + " times, stopping: " + sr);
9096 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9097 sr.crashCount, sr.shortName, app.pid);
9098 bringDownServiceLocked(sr, true);
9099 } else if (!allowRestart) {
9100 bringDownServiceLocked(sr, true);
9101 } else {
9102 scheduleServiceRestartLocked(sr);
9103 }
9104 }
9105
9106 if (!allowRestart) {
9107 app.services.clear();
9108 }
9109 }
9110
9111 app.executingServices.clear();
9112 }
9113
9114 private final void removeDyingProviderLocked(ProcessRecord proc,
9115 ContentProviderRecord cpr) {
9116 synchronized (cpr) {
9117 cpr.launchingApp = null;
9118 cpr.notifyAll();
9119 }
9120
9121 mProvidersByClass.remove(cpr.info.name);
9122 String names[] = cpr.info.authority.split(";");
9123 for (int j = 0; j < names.length; j++) {
9124 mProvidersByName.remove(names[j]);
9125 }
9126
9127 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9128 while (cit.hasNext()) {
9129 ProcessRecord capp = cit.next();
9130 if (!capp.persistent && capp.thread != null
9131 && capp.pid != 0
9132 && capp.pid != MY_PID) {
9133 Log.i(TAG, "Killing app " + capp.processName
9134 + " (pid " + capp.pid
9135 + ") because provider " + cpr.info.name
9136 + " is in dying process " + proc.processName);
9137 Process.killProcess(capp.pid);
9138 }
9139 }
9140
9141 mLaunchingProviders.remove(cpr);
9142 }
9143
9144 /**
9145 * Main code for cleaning up a process when it has gone away. This is
9146 * called both as a result of the process dying, or directly when stopping
9147 * a process when running in single process mode.
9148 */
9149 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9150 boolean restarting, int index) {
9151 if (index >= 0) {
9152 mLRUProcesses.remove(index);
9153 }
9154
9155 // Dismiss any open dialogs.
9156 if (app.crashDialog != null) {
9157 app.crashDialog.dismiss();
9158 app.crashDialog = null;
9159 }
9160 if (app.anrDialog != null) {
9161 app.anrDialog.dismiss();
9162 app.anrDialog = null;
9163 }
9164 if (app.waitDialog != null) {
9165 app.waitDialog.dismiss();
9166 app.waitDialog = null;
9167 }
9168
9169 app.crashing = false;
9170 app.notResponding = false;
9171
9172 app.resetPackageList();
9173 app.thread = null;
9174 app.forcingToForeground = null;
9175 app.foregroundServices = false;
9176
9177 killServicesLocked(app, true);
9178
9179 boolean restart = false;
9180
9181 int NL = mLaunchingProviders.size();
9182
9183 // Remove published content providers.
9184 if (!app.pubProviders.isEmpty()) {
9185 Iterator it = app.pubProviders.values().iterator();
9186 while (it.hasNext()) {
9187 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9188 cpr.provider = null;
9189 cpr.app = null;
9190
9191 // See if someone is waiting for this provider... in which
9192 // case we don't remove it, but just let it restart.
9193 int i = 0;
9194 if (!app.bad) {
9195 for (; i<NL; i++) {
9196 if (mLaunchingProviders.get(i) == cpr) {
9197 restart = true;
9198 break;
9199 }
9200 }
9201 } else {
9202 i = NL;
9203 }
9204
9205 if (i >= NL) {
9206 removeDyingProviderLocked(app, cpr);
9207 NL = mLaunchingProviders.size();
9208 }
9209 }
9210 app.pubProviders.clear();
9211 }
9212
9213 // Look through the content providers we are waiting to have launched,
9214 // and if any run in this process then either schedule a restart of
9215 // the process or kill the client waiting for it if this process has
9216 // gone bad.
9217 for (int i=0; i<NL; i++) {
9218 ContentProviderRecord cpr = (ContentProviderRecord)
9219 mLaunchingProviders.get(i);
9220 if (cpr.launchingApp == app) {
9221 if (!app.bad) {
9222 restart = true;
9223 } else {
9224 removeDyingProviderLocked(app, cpr);
9225 NL = mLaunchingProviders.size();
9226 }
9227 }
9228 }
9229
9230 // Unregister from connected content providers.
9231 if (!app.conProviders.isEmpty()) {
9232 Iterator it = app.conProviders.iterator();
9233 while (it.hasNext()) {
9234 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9235 cpr.clients.remove(app);
9236 }
9237 app.conProviders.clear();
9238 }
9239
9240 skipCurrentReceiverLocked(app);
9241
9242 // Unregister any receivers.
9243 if (app.receivers.size() > 0) {
9244 Iterator<ReceiverList> it = app.receivers.iterator();
9245 while (it.hasNext()) {
9246 removeReceiverLocked(it.next());
9247 }
9248 app.receivers.clear();
9249 }
9250
Christopher Tate181fafa2009-05-14 11:12:14 -07009251 // If the app is undergoing backup, tell the backup manager about it
9252 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9253 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9254 try {
9255 IBackupManager bm = IBackupManager.Stub.asInterface(
9256 ServiceManager.getService(Context.BACKUP_SERVICE));
9257 bm.agentDisconnected(app.info.packageName);
9258 } catch (RemoteException e) {
9259 // can't happen; backup manager is local
9260 }
9261 }
9262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009263 // If the caller is restarting this app, then leave it in its
9264 // current lists and let the caller take care of it.
9265 if (restarting) {
9266 return;
9267 }
9268
9269 if (!app.persistent) {
9270 if (DEBUG_PROCESSES) Log.v(TAG,
9271 "Removing non-persistent process during cleanup: " + app);
9272 mProcessNames.remove(app.processName, app.info.uid);
9273 } else if (!app.removed) {
9274 // This app is persistent, so we need to keep its record around.
9275 // If it is not already on the pending app list, add it there
9276 // and start a new process for it.
9277 app.thread = null;
9278 app.forcingToForeground = null;
9279 app.foregroundServices = false;
9280 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9281 mPersistentStartingProcesses.add(app);
9282 restart = true;
9283 }
9284 }
9285 mProcessesOnHold.remove(app);
9286
The Android Open Source Project4df24232009-03-05 14:34:35 -08009287 if (app == mHomeProcess) {
9288 mHomeProcess = null;
9289 }
9290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009291 if (restart) {
9292 // We have components that still need to be running in the
9293 // process, so re-launch it.
9294 mProcessNames.put(app.processName, app.info.uid, app);
9295 startProcessLocked(app, "restart", app.processName);
9296 } else if (app.pid > 0 && app.pid != MY_PID) {
9297 // Goodbye!
9298 synchronized (mPidsSelfLocked) {
9299 mPidsSelfLocked.remove(app.pid);
9300 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9301 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009302 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009303 }
9304 }
9305
9306 // =========================================================
9307 // SERVICES
9308 // =========================================================
9309
9310 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9311 ActivityManager.RunningServiceInfo info =
9312 new ActivityManager.RunningServiceInfo();
9313 info.service = r.name;
9314 if (r.app != null) {
9315 info.pid = r.app.pid;
9316 }
9317 info.process = r.processName;
9318 info.foreground = r.isForeground;
9319 info.activeSince = r.createTime;
9320 info.started = r.startRequested;
9321 info.clientCount = r.connections.size();
9322 info.crashCount = r.crashCount;
9323 info.lastActivityTime = r.lastActivity;
9324 return info;
9325 }
9326
9327 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9328 int flags) {
9329 synchronized (this) {
9330 ArrayList<ActivityManager.RunningServiceInfo> res
9331 = new ArrayList<ActivityManager.RunningServiceInfo>();
9332
9333 if (mServices.size() > 0) {
9334 Iterator<ServiceRecord> it = mServices.values().iterator();
9335 while (it.hasNext() && res.size() < maxNum) {
9336 res.add(makeRunningServiceInfoLocked(it.next()));
9337 }
9338 }
9339
9340 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9341 ServiceRecord r = mRestartingServices.get(i);
9342 ActivityManager.RunningServiceInfo info =
9343 makeRunningServiceInfoLocked(r);
9344 info.restarting = r.nextRestartTime;
9345 res.add(info);
9346 }
9347
9348 return res;
9349 }
9350 }
9351
9352 private final ServiceRecord findServiceLocked(ComponentName name,
9353 IBinder token) {
9354 ServiceRecord r = mServices.get(name);
9355 return r == token ? r : null;
9356 }
9357
9358 private final class ServiceLookupResult {
9359 final ServiceRecord record;
9360 final String permission;
9361
9362 ServiceLookupResult(ServiceRecord _record, String _permission) {
9363 record = _record;
9364 permission = _permission;
9365 }
9366 };
9367
9368 private ServiceLookupResult findServiceLocked(Intent service,
9369 String resolvedType) {
9370 ServiceRecord r = null;
9371 if (service.getComponent() != null) {
9372 r = mServices.get(service.getComponent());
9373 }
9374 if (r == null) {
9375 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9376 r = mServicesByIntent.get(filter);
9377 }
9378
9379 if (r == null) {
9380 try {
9381 ResolveInfo rInfo =
9382 ActivityThread.getPackageManager().resolveService(
9383 service, resolvedType, 0);
9384 ServiceInfo sInfo =
9385 rInfo != null ? rInfo.serviceInfo : null;
9386 if (sInfo == null) {
9387 return null;
9388 }
9389
9390 ComponentName name = new ComponentName(
9391 sInfo.applicationInfo.packageName, sInfo.name);
9392 r = mServices.get(name);
9393 } catch (RemoteException ex) {
9394 // pm is in same process, this will never happen.
9395 }
9396 }
9397 if (r != null) {
9398 int callingPid = Binder.getCallingPid();
9399 int callingUid = Binder.getCallingUid();
9400 if (checkComponentPermission(r.permission,
9401 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9402 != PackageManager.PERMISSION_GRANTED) {
9403 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9404 + " from pid=" + callingPid
9405 + ", uid=" + callingUid
9406 + " requires " + r.permission);
9407 return new ServiceLookupResult(null, r.permission);
9408 }
9409 return new ServiceLookupResult(r, null);
9410 }
9411 return null;
9412 }
9413
9414 private class ServiceRestarter implements Runnable {
9415 private ServiceRecord mService;
9416
9417 void setService(ServiceRecord service) {
9418 mService = service;
9419 }
9420
9421 public void run() {
9422 synchronized(ActivityManagerService.this) {
9423 performServiceRestartLocked(mService);
9424 }
9425 }
9426 }
9427
9428 private ServiceLookupResult retrieveServiceLocked(Intent service,
9429 String resolvedType, int callingPid, int callingUid) {
9430 ServiceRecord r = null;
9431 if (service.getComponent() != null) {
9432 r = mServices.get(service.getComponent());
9433 }
9434 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9435 r = mServicesByIntent.get(filter);
9436 if (r == null) {
9437 try {
9438 ResolveInfo rInfo =
9439 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009440 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009441 ServiceInfo sInfo =
9442 rInfo != null ? rInfo.serviceInfo : null;
9443 if (sInfo == null) {
9444 Log.w(TAG, "Unable to start service " + service +
9445 ": not found");
9446 return null;
9447 }
9448
9449 ComponentName name = new ComponentName(
9450 sInfo.applicationInfo.packageName, sInfo.name);
9451 r = mServices.get(name);
9452 if (r == null) {
9453 filter = new Intent.FilterComparison(service.cloneFilter());
9454 ServiceRestarter res = new ServiceRestarter();
9455 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9456 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9457 synchronized (stats) {
9458 ss = stats.getServiceStatsLocked(
9459 sInfo.applicationInfo.uid, sInfo.packageName,
9460 sInfo.name);
9461 }
9462 r = new ServiceRecord(ss, name, filter, sInfo, res);
9463 res.setService(r);
9464 mServices.put(name, r);
9465 mServicesByIntent.put(filter, r);
9466
9467 // Make sure this component isn't in the pending list.
9468 int N = mPendingServices.size();
9469 for (int i=0; i<N; i++) {
9470 ServiceRecord pr = mPendingServices.get(i);
9471 if (pr.name.equals(name)) {
9472 mPendingServices.remove(i);
9473 i--;
9474 N--;
9475 }
9476 }
9477 }
9478 } catch (RemoteException ex) {
9479 // pm is in same process, this will never happen.
9480 }
9481 }
9482 if (r != null) {
9483 if (checkComponentPermission(r.permission,
9484 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9485 != PackageManager.PERMISSION_GRANTED) {
9486 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9487 + " from pid=" + Binder.getCallingPid()
9488 + ", uid=" + Binder.getCallingUid()
9489 + " requires " + r.permission);
9490 return new ServiceLookupResult(null, r.permission);
9491 }
9492 return new ServiceLookupResult(r, null);
9493 }
9494 return null;
9495 }
9496
9497 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9498 long now = SystemClock.uptimeMillis();
9499 if (r.executeNesting == 0 && r.app != null) {
9500 if (r.app.executingServices.size() == 0) {
9501 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9502 msg.obj = r.app;
9503 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9504 }
9505 r.app.executingServices.add(r);
9506 }
9507 r.executeNesting++;
9508 r.executingStart = now;
9509 }
9510
9511 private final void sendServiceArgsLocked(ServiceRecord r,
9512 boolean oomAdjusted) {
9513 final int N = r.startArgs.size();
9514 if (N == 0) {
9515 return;
9516 }
9517
9518 final int BASEID = r.lastStartId - N + 1;
9519 int i = 0;
9520 while (i < N) {
9521 try {
9522 Intent args = r.startArgs.get(i);
9523 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9524 + r.name + " " + r.intent + " args=" + args);
9525 bumpServiceExecutingLocked(r);
9526 if (!oomAdjusted) {
9527 oomAdjusted = true;
9528 updateOomAdjLocked(r.app);
9529 }
9530 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9531 i++;
9532 } catch (Exception e) {
9533 break;
9534 }
9535 }
9536 if (i == N) {
9537 r.startArgs.clear();
9538 } else {
9539 while (i > 0) {
9540 r.startArgs.remove(0);
9541 i--;
9542 }
9543 }
9544 }
9545
9546 private final boolean requestServiceBindingLocked(ServiceRecord r,
9547 IntentBindRecord i, boolean rebind) {
9548 if (r.app == null || r.app.thread == null) {
9549 // If service is not currently running, can't yet bind.
9550 return false;
9551 }
9552 if ((!i.requested || rebind) && i.apps.size() > 0) {
9553 try {
9554 bumpServiceExecutingLocked(r);
9555 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9556 + ": shouldUnbind=" + i.hasBound);
9557 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9558 if (!rebind) {
9559 i.requested = true;
9560 }
9561 i.hasBound = true;
9562 i.doRebind = false;
9563 } catch (RemoteException e) {
9564 return false;
9565 }
9566 }
9567 return true;
9568 }
9569
9570 private final void requestServiceBindingsLocked(ServiceRecord r) {
9571 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9572 while (bindings.hasNext()) {
9573 IntentBindRecord i = bindings.next();
9574 if (!requestServiceBindingLocked(r, i, false)) {
9575 break;
9576 }
9577 }
9578 }
9579
9580 private final void realStartServiceLocked(ServiceRecord r,
9581 ProcessRecord app) throws RemoteException {
9582 if (app.thread == null) {
9583 throw new RemoteException();
9584 }
9585
9586 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009587 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009588
9589 app.services.add(r);
9590 bumpServiceExecutingLocked(r);
9591 updateLRUListLocked(app, true);
9592
9593 boolean created = false;
9594 try {
9595 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9596 + r.name + " " + r.intent);
9597 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9598 System.identityHashCode(r), r.shortName,
9599 r.intent.getIntent().toString(), r.app.pid);
9600 synchronized (r.stats.getBatteryStats()) {
9601 r.stats.startLaunchedLocked();
9602 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009603 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009604 app.thread.scheduleCreateService(r, r.serviceInfo);
9605 created = true;
9606 } finally {
9607 if (!created) {
9608 app.services.remove(r);
9609 scheduleServiceRestartLocked(r);
9610 }
9611 }
9612
9613 requestServiceBindingsLocked(r);
9614 sendServiceArgsLocked(r, true);
9615 }
9616
9617 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9618 r.totalRestartCount++;
9619 if (r.restartDelay == 0) {
9620 r.restartCount++;
9621 r.restartDelay = SERVICE_RESTART_DURATION;
9622 } else {
9623 // If it has been a "reasonably long time" since the service
9624 // was started, then reset our restart duration back to
9625 // the beginning, so we don't infinitely increase the duration
9626 // on a service that just occasionally gets killed (which is
9627 // a normal case, due to process being killed to reclaim memory).
9628 long now = SystemClock.uptimeMillis();
9629 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9630 r.restartCount = 1;
9631 r.restartDelay = SERVICE_RESTART_DURATION;
9632 } else {
9633 r.restartDelay *= 2;
9634 }
9635 }
9636 if (!mRestartingServices.contains(r)) {
9637 mRestartingServices.add(r);
9638 }
9639 mHandler.removeCallbacks(r.restarter);
9640 mHandler.postDelayed(r.restarter, r.restartDelay);
9641 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9642 Log.w(TAG, "Scheduling restart of crashed service "
9643 + r.shortName + " in " + r.restartDelay + "ms");
9644 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9645 r.shortName, r.restartDelay);
9646
9647 Message msg = Message.obtain();
9648 msg.what = SERVICE_ERROR_MSG;
9649 msg.obj = r;
9650 mHandler.sendMessage(msg);
9651 }
9652
9653 final void performServiceRestartLocked(ServiceRecord r) {
9654 if (!mRestartingServices.contains(r)) {
9655 return;
9656 }
9657 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9658 }
9659
9660 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9661 if (r.restartDelay == 0) {
9662 return false;
9663 }
9664 r.resetRestartCounter();
9665 mRestartingServices.remove(r);
9666 mHandler.removeCallbacks(r.restarter);
9667 return true;
9668 }
9669
9670 private final boolean bringUpServiceLocked(ServiceRecord r,
9671 int intentFlags, boolean whileRestarting) {
9672 //Log.i(TAG, "Bring up service:");
9673 //r.dump(" ");
9674
9675 if (r.app != null) {
9676 sendServiceArgsLocked(r, false);
9677 return true;
9678 }
9679
9680 if (!whileRestarting && r.restartDelay > 0) {
9681 // If waiting for a restart, then do nothing.
9682 return true;
9683 }
9684
9685 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9686 + " " + r.intent);
9687
9688 final String appName = r.processName;
9689 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9690 if (app != null && app.thread != null) {
9691 try {
9692 realStartServiceLocked(r, app);
9693 return true;
9694 } catch (RemoteException e) {
9695 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9696 }
9697
9698 // If a dead object exception was thrown -- fall through to
9699 // restart the application.
9700 }
9701
9702 if (!mPendingServices.contains(r)) {
9703 // Not running -- get it started, and enqueue this service record
9704 // to be executed when the app comes up.
9705 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9706 "service", r.name) == null) {
9707 Log.w(TAG, "Unable to launch app "
9708 + r.appInfo.packageName + "/"
9709 + r.appInfo.uid + " for service "
9710 + r.intent.getIntent() + ": process is bad");
9711 bringDownServiceLocked(r, true);
9712 return false;
9713 }
9714 mPendingServices.add(r);
9715 }
9716 return true;
9717 }
9718
9719 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9720 //Log.i(TAG, "Bring down service:");
9721 //r.dump(" ");
9722
9723 // Does it still need to run?
9724 if (!force && r.startRequested) {
9725 return;
9726 }
9727 if (r.connections.size() > 0) {
9728 if (!force) {
9729 // XXX should probably keep a count of the number of auto-create
9730 // connections directly in the service.
9731 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9732 while (it.hasNext()) {
9733 ConnectionRecord cr = it.next();
9734 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9735 return;
9736 }
9737 }
9738 }
9739
9740 // Report to all of the connections that the service is no longer
9741 // available.
9742 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9743 while (it.hasNext()) {
9744 ConnectionRecord c = it.next();
9745 try {
9746 // todo: shouldn't be a synchronous call!
9747 c.conn.connected(r.name, null);
9748 } catch (Exception e) {
9749 Log.w(TAG, "Failure disconnecting service " + r.name +
9750 " to connection " + c.conn.asBinder() +
9751 " (in " + c.binding.client.processName + ")", e);
9752 }
9753 }
9754 }
9755
9756 // Tell the service that it has been unbound.
9757 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9758 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9759 while (it.hasNext()) {
9760 IntentBindRecord ibr = it.next();
9761 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9762 + ": hasBound=" + ibr.hasBound);
9763 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9764 try {
9765 bumpServiceExecutingLocked(r);
9766 updateOomAdjLocked(r.app);
9767 ibr.hasBound = false;
9768 r.app.thread.scheduleUnbindService(r,
9769 ibr.intent.getIntent());
9770 } catch (Exception e) {
9771 Log.w(TAG, "Exception when unbinding service "
9772 + r.shortName, e);
9773 serviceDoneExecutingLocked(r, true);
9774 }
9775 }
9776 }
9777 }
9778
9779 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9780 + " " + r.intent);
9781 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9782 System.identityHashCode(r), r.shortName,
9783 (r.app != null) ? r.app.pid : -1);
9784
9785 mServices.remove(r.name);
9786 mServicesByIntent.remove(r.intent);
9787 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9788 r.totalRestartCount = 0;
9789 unscheduleServiceRestartLocked(r);
9790
9791 // Also make sure it is not on the pending list.
9792 int N = mPendingServices.size();
9793 for (int i=0; i<N; i++) {
9794 if (mPendingServices.get(i) == r) {
9795 mPendingServices.remove(i);
9796 if (DEBUG_SERVICE) Log.v(
9797 TAG, "Removed pending service: " + r.shortName);
9798 i--;
9799 N--;
9800 }
9801 }
9802
9803 if (r.app != null) {
9804 synchronized (r.stats.getBatteryStats()) {
9805 r.stats.stopLaunchedLocked();
9806 }
9807 r.app.services.remove(r);
9808 if (r.app.thread != null) {
9809 updateServiceForegroundLocked(r.app, false);
9810 try {
9811 Log.i(TAG, "Stopping service: " + r.shortName);
9812 bumpServiceExecutingLocked(r);
9813 mStoppingServices.add(r);
9814 updateOomAdjLocked(r.app);
9815 r.app.thread.scheduleStopService(r);
9816 } catch (Exception e) {
9817 Log.w(TAG, "Exception when stopping service "
9818 + r.shortName, e);
9819 serviceDoneExecutingLocked(r, true);
9820 }
9821 } else {
9822 if (DEBUG_SERVICE) Log.v(
9823 TAG, "Removed service that has no process: " + r.shortName);
9824 }
9825 } else {
9826 if (DEBUG_SERVICE) Log.v(
9827 TAG, "Removed service that is not running: " + r.shortName);
9828 }
9829 }
9830
9831 ComponentName startServiceLocked(IApplicationThread caller,
9832 Intent service, String resolvedType,
9833 int callingPid, int callingUid) {
9834 synchronized(this) {
9835 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9836 + " type=" + resolvedType + " args=" + service.getExtras());
9837
9838 if (caller != null) {
9839 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9840 if (callerApp == null) {
9841 throw new SecurityException(
9842 "Unable to find app for caller " + caller
9843 + " (pid=" + Binder.getCallingPid()
9844 + ") when starting service " + service);
9845 }
9846 }
9847
9848 ServiceLookupResult res =
9849 retrieveServiceLocked(service, resolvedType,
9850 callingPid, callingUid);
9851 if (res == null) {
9852 return null;
9853 }
9854 if (res.record == null) {
9855 return new ComponentName("!", res.permission != null
9856 ? res.permission : "private to package");
9857 }
9858 ServiceRecord r = res.record;
9859 if (unscheduleServiceRestartLocked(r)) {
9860 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9861 + r.shortName);
9862 }
9863 r.startRequested = true;
9864 r.startArgs.add(service);
9865 r.lastStartId++;
9866 if (r.lastStartId < 1) {
9867 r.lastStartId = 1;
9868 }
9869 r.lastActivity = SystemClock.uptimeMillis();
9870 synchronized (r.stats.getBatteryStats()) {
9871 r.stats.startRunningLocked();
9872 }
9873 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9874 return new ComponentName("!", "Service process is bad");
9875 }
9876 return r.name;
9877 }
9878 }
9879
9880 public ComponentName startService(IApplicationThread caller, Intent service,
9881 String resolvedType) {
9882 // Refuse possible leaked file descriptors
9883 if (service != null && service.hasFileDescriptors() == true) {
9884 throw new IllegalArgumentException("File descriptors passed in Intent");
9885 }
9886
9887 synchronized(this) {
9888 final int callingPid = Binder.getCallingPid();
9889 final int callingUid = Binder.getCallingUid();
9890 final long origId = Binder.clearCallingIdentity();
9891 ComponentName res = startServiceLocked(caller, service,
9892 resolvedType, callingPid, callingUid);
9893 Binder.restoreCallingIdentity(origId);
9894 return res;
9895 }
9896 }
9897
9898 ComponentName startServiceInPackage(int uid,
9899 Intent service, String resolvedType) {
9900 synchronized(this) {
9901 final long origId = Binder.clearCallingIdentity();
9902 ComponentName res = startServiceLocked(null, service,
9903 resolvedType, -1, uid);
9904 Binder.restoreCallingIdentity(origId);
9905 return res;
9906 }
9907 }
9908
9909 public int stopService(IApplicationThread caller, Intent service,
9910 String resolvedType) {
9911 // Refuse possible leaked file descriptors
9912 if (service != null && service.hasFileDescriptors() == true) {
9913 throw new IllegalArgumentException("File descriptors passed in Intent");
9914 }
9915
9916 synchronized(this) {
9917 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9918 + " type=" + resolvedType);
9919
9920 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9921 if (caller != null && callerApp == null) {
9922 throw new SecurityException(
9923 "Unable to find app for caller " + caller
9924 + " (pid=" + Binder.getCallingPid()
9925 + ") when stopping service " + service);
9926 }
9927
9928 // If this service is active, make sure it is stopped.
9929 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9930 if (r != null) {
9931 if (r.record != null) {
9932 synchronized (r.record.stats.getBatteryStats()) {
9933 r.record.stats.stopRunningLocked();
9934 }
9935 r.record.startRequested = false;
9936 final long origId = Binder.clearCallingIdentity();
9937 bringDownServiceLocked(r.record, false);
9938 Binder.restoreCallingIdentity(origId);
9939 return 1;
9940 }
9941 return -1;
9942 }
9943 }
9944
9945 return 0;
9946 }
9947
9948 public IBinder peekService(Intent service, String resolvedType) {
9949 // Refuse possible leaked file descriptors
9950 if (service != null && service.hasFileDescriptors() == true) {
9951 throw new IllegalArgumentException("File descriptors passed in Intent");
9952 }
9953
9954 IBinder ret = null;
9955
9956 synchronized(this) {
9957 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9958
9959 if (r != null) {
9960 // r.record is null if findServiceLocked() failed the caller permission check
9961 if (r.record == null) {
9962 throw new SecurityException(
9963 "Permission Denial: Accessing service " + r.record.name
9964 + " from pid=" + Binder.getCallingPid()
9965 + ", uid=" + Binder.getCallingUid()
9966 + " requires " + r.permission);
9967 }
9968 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9969 if (ib != null) {
9970 ret = ib.binder;
9971 }
9972 }
9973 }
9974
9975 return ret;
9976 }
9977
9978 public boolean stopServiceToken(ComponentName className, IBinder token,
9979 int startId) {
9980 synchronized(this) {
9981 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9982 + " " + token + " startId=" + startId);
9983 ServiceRecord r = findServiceLocked(className, token);
9984 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9985 synchronized (r.stats.getBatteryStats()) {
9986 r.stats.stopRunningLocked();
9987 r.startRequested = false;
9988 }
9989 final long origId = Binder.clearCallingIdentity();
9990 bringDownServiceLocked(r, false);
9991 Binder.restoreCallingIdentity(origId);
9992 return true;
9993 }
9994 }
9995 return false;
9996 }
9997
9998 public void setServiceForeground(ComponentName className, IBinder token,
9999 boolean isForeground) {
10000 synchronized(this) {
10001 ServiceRecord r = findServiceLocked(className, token);
10002 if (r != null) {
10003 if (r.isForeground != isForeground) {
10004 final long origId = Binder.clearCallingIdentity();
10005 r.isForeground = isForeground;
10006 if (r.app != null) {
10007 updateServiceForegroundLocked(r.app, true);
10008 }
10009 Binder.restoreCallingIdentity(origId);
10010 }
10011 }
10012 }
10013 }
10014
10015 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10016 boolean anyForeground = false;
10017 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10018 if (sr.isForeground) {
10019 anyForeground = true;
10020 break;
10021 }
10022 }
10023 if (anyForeground != proc.foregroundServices) {
10024 proc.foregroundServices = anyForeground;
10025 if (oomAdj) {
10026 updateOomAdjLocked();
10027 }
10028 }
10029 }
10030
10031 public int bindService(IApplicationThread caller, IBinder token,
10032 Intent service, String resolvedType,
10033 IServiceConnection connection, int flags) {
10034 // Refuse possible leaked file descriptors
10035 if (service != null && service.hasFileDescriptors() == true) {
10036 throw new IllegalArgumentException("File descriptors passed in Intent");
10037 }
10038
10039 synchronized(this) {
10040 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10041 + " type=" + resolvedType + " conn=" + connection.asBinder()
10042 + " flags=0x" + Integer.toHexString(flags));
10043 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10044 if (callerApp == null) {
10045 throw new SecurityException(
10046 "Unable to find app for caller " + caller
10047 + " (pid=" + Binder.getCallingPid()
10048 + ") when binding service " + service);
10049 }
10050
10051 HistoryRecord activity = null;
10052 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010053 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010054 if (aindex < 0) {
10055 Log.w(TAG, "Binding with unknown activity: " + token);
10056 return 0;
10057 }
10058 activity = (HistoryRecord)mHistory.get(aindex);
10059 }
10060
10061 ServiceLookupResult res =
10062 retrieveServiceLocked(service, resolvedType,
10063 Binder.getCallingPid(), Binder.getCallingUid());
10064 if (res == null) {
10065 return 0;
10066 }
10067 if (res.record == null) {
10068 return -1;
10069 }
10070 ServiceRecord s = res.record;
10071
10072 final long origId = Binder.clearCallingIdentity();
10073
10074 if (unscheduleServiceRestartLocked(s)) {
10075 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10076 + s.shortName);
10077 }
10078
10079 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10080 ConnectionRecord c = new ConnectionRecord(b, activity,
10081 connection, flags);
10082
10083 IBinder binder = connection.asBinder();
10084 s.connections.put(binder, c);
10085 b.connections.add(c);
10086 if (activity != null) {
10087 if (activity.connections == null) {
10088 activity.connections = new HashSet<ConnectionRecord>();
10089 }
10090 activity.connections.add(c);
10091 }
10092 b.client.connections.add(c);
10093 mServiceConnections.put(binder, c);
10094
10095 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10096 s.lastActivity = SystemClock.uptimeMillis();
10097 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10098 return 0;
10099 }
10100 }
10101
10102 if (s.app != null) {
10103 // This could have made the service more important.
10104 updateOomAdjLocked(s.app);
10105 }
10106
10107 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10108 + ": received=" + b.intent.received
10109 + " apps=" + b.intent.apps.size()
10110 + " doRebind=" + b.intent.doRebind);
10111
10112 if (s.app != null && b.intent.received) {
10113 // Service is already running, so we can immediately
10114 // publish the connection.
10115 try {
10116 c.conn.connected(s.name, b.intent.binder);
10117 } catch (Exception e) {
10118 Log.w(TAG, "Failure sending service " + s.shortName
10119 + " to connection " + c.conn.asBinder()
10120 + " (in " + c.binding.client.processName + ")", e);
10121 }
10122
10123 // If this is the first app connected back to this binding,
10124 // and the service had previously asked to be told when
10125 // rebound, then do so.
10126 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10127 requestServiceBindingLocked(s, b.intent, true);
10128 }
10129 } else if (!b.intent.requested) {
10130 requestServiceBindingLocked(s, b.intent, false);
10131 }
10132
10133 Binder.restoreCallingIdentity(origId);
10134 }
10135
10136 return 1;
10137 }
10138
10139 private void removeConnectionLocked(
10140 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10141 IBinder binder = c.conn.asBinder();
10142 AppBindRecord b = c.binding;
10143 ServiceRecord s = b.service;
10144 s.connections.remove(binder);
10145 b.connections.remove(c);
10146 if (c.activity != null && c.activity != skipAct) {
10147 if (c.activity.connections != null) {
10148 c.activity.connections.remove(c);
10149 }
10150 }
10151 if (b.client != skipApp) {
10152 b.client.connections.remove(c);
10153 }
10154 mServiceConnections.remove(binder);
10155
10156 if (b.connections.size() == 0) {
10157 b.intent.apps.remove(b.client);
10158 }
10159
10160 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10161 + ": shouldUnbind=" + b.intent.hasBound);
10162 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10163 && b.intent.hasBound) {
10164 try {
10165 bumpServiceExecutingLocked(s);
10166 updateOomAdjLocked(s.app);
10167 b.intent.hasBound = false;
10168 // Assume the client doesn't want to know about a rebind;
10169 // we will deal with that later if it asks for one.
10170 b.intent.doRebind = false;
10171 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10172 } catch (Exception e) {
10173 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10174 serviceDoneExecutingLocked(s, true);
10175 }
10176 }
10177
10178 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10179 bringDownServiceLocked(s, false);
10180 }
10181 }
10182
10183 public boolean unbindService(IServiceConnection connection) {
10184 synchronized (this) {
10185 IBinder binder = connection.asBinder();
10186 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10187 ConnectionRecord r = mServiceConnections.get(binder);
10188 if (r == null) {
10189 Log.w(TAG, "Unbind failed: could not find connection for "
10190 + connection.asBinder());
10191 return false;
10192 }
10193
10194 final long origId = Binder.clearCallingIdentity();
10195
10196 removeConnectionLocked(r, null, null);
10197
10198 if (r.binding.service.app != null) {
10199 // This could have made the service less important.
10200 updateOomAdjLocked(r.binding.service.app);
10201 }
10202
10203 Binder.restoreCallingIdentity(origId);
10204 }
10205
10206 return true;
10207 }
10208
10209 public void publishService(IBinder token, Intent intent, IBinder service) {
10210 // Refuse possible leaked file descriptors
10211 if (intent != null && intent.hasFileDescriptors() == true) {
10212 throw new IllegalArgumentException("File descriptors passed in Intent");
10213 }
10214
10215 synchronized(this) {
10216 if (!(token instanceof ServiceRecord)) {
10217 throw new IllegalArgumentException("Invalid service token");
10218 }
10219 ServiceRecord r = (ServiceRecord)token;
10220
10221 final long origId = Binder.clearCallingIdentity();
10222
10223 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10224 + " " + intent + ": " + service);
10225 if (r != null) {
10226 Intent.FilterComparison filter
10227 = new Intent.FilterComparison(intent);
10228 IntentBindRecord b = r.bindings.get(filter);
10229 if (b != null && !b.received) {
10230 b.binder = service;
10231 b.requested = true;
10232 b.received = true;
10233 if (r.connections.size() > 0) {
10234 Iterator<ConnectionRecord> it
10235 = r.connections.values().iterator();
10236 while (it.hasNext()) {
10237 ConnectionRecord c = it.next();
10238 if (!filter.equals(c.binding.intent.intent)) {
10239 if (DEBUG_SERVICE) Log.v(
10240 TAG, "Not publishing to: " + c);
10241 if (DEBUG_SERVICE) Log.v(
10242 TAG, "Bound intent: " + c.binding.intent.intent);
10243 if (DEBUG_SERVICE) Log.v(
10244 TAG, "Published intent: " + intent);
10245 continue;
10246 }
10247 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10248 try {
10249 c.conn.connected(r.name, service);
10250 } catch (Exception e) {
10251 Log.w(TAG, "Failure sending service " + r.name +
10252 " to connection " + c.conn.asBinder() +
10253 " (in " + c.binding.client.processName + ")", e);
10254 }
10255 }
10256 }
10257 }
10258
10259 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10260
10261 Binder.restoreCallingIdentity(origId);
10262 }
10263 }
10264 }
10265
10266 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10267 // Refuse possible leaked file descriptors
10268 if (intent != null && intent.hasFileDescriptors() == true) {
10269 throw new IllegalArgumentException("File descriptors passed in Intent");
10270 }
10271
10272 synchronized(this) {
10273 if (!(token instanceof ServiceRecord)) {
10274 throw new IllegalArgumentException("Invalid service token");
10275 }
10276 ServiceRecord r = (ServiceRecord)token;
10277
10278 final long origId = Binder.clearCallingIdentity();
10279
10280 if (r != null) {
10281 Intent.FilterComparison filter
10282 = new Intent.FilterComparison(intent);
10283 IntentBindRecord b = r.bindings.get(filter);
10284 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10285 + " at " + b + ": apps="
10286 + (b != null ? b.apps.size() : 0));
10287 if (b != null) {
10288 if (b.apps.size() > 0) {
10289 // Applications have already bound since the last
10290 // unbind, so just rebind right here.
10291 requestServiceBindingLocked(r, b, true);
10292 } else {
10293 // Note to tell the service the next time there is
10294 // a new client.
10295 b.doRebind = true;
10296 }
10297 }
10298
10299 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10300
10301 Binder.restoreCallingIdentity(origId);
10302 }
10303 }
10304 }
10305
10306 public void serviceDoneExecuting(IBinder token) {
10307 synchronized(this) {
10308 if (!(token instanceof ServiceRecord)) {
10309 throw new IllegalArgumentException("Invalid service token");
10310 }
10311 ServiceRecord r = (ServiceRecord)token;
10312 boolean inStopping = mStoppingServices.contains(token);
10313 if (r != null) {
10314 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10315 + ": nesting=" + r.executeNesting
10316 + ", inStopping=" + inStopping);
10317 if (r != token) {
10318 Log.w(TAG, "Done executing service " + r.name
10319 + " with incorrect token: given " + token
10320 + ", expected " + r);
10321 return;
10322 }
10323
10324 final long origId = Binder.clearCallingIdentity();
10325 serviceDoneExecutingLocked(r, inStopping);
10326 Binder.restoreCallingIdentity(origId);
10327 } else {
10328 Log.w(TAG, "Done executing unknown service " + r.name
10329 + " with token " + token);
10330 }
10331 }
10332 }
10333
10334 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10335 r.executeNesting--;
10336 if (r.executeNesting <= 0 && r.app != null) {
10337 r.app.executingServices.remove(r);
10338 if (r.app.executingServices.size() == 0) {
10339 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10340 }
10341 if (inStopping) {
10342 mStoppingServices.remove(r);
10343 }
10344 updateOomAdjLocked(r.app);
10345 }
10346 }
10347
10348 void serviceTimeout(ProcessRecord proc) {
10349 synchronized(this) {
10350 if (proc.executingServices.size() == 0 || proc.thread == null) {
10351 return;
10352 }
10353 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10354 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10355 ServiceRecord timeout = null;
10356 long nextTime = 0;
10357 while (it.hasNext()) {
10358 ServiceRecord sr = it.next();
10359 if (sr.executingStart < maxTime) {
10360 timeout = sr;
10361 break;
10362 }
10363 if (sr.executingStart > nextTime) {
10364 nextTime = sr.executingStart;
10365 }
10366 }
10367 if (timeout != null && mLRUProcesses.contains(proc)) {
10368 Log.w(TAG, "Timeout executing service: " + timeout);
10369 appNotRespondingLocked(proc, null, "Executing service "
10370 + timeout.name);
10371 } else {
10372 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10373 msg.obj = proc;
10374 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10375 }
10376 }
10377 }
10378
10379 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010380 // BACKUP AND RESTORE
10381 // =========================================================
10382
10383 // Cause the target app to be launched if necessary and its backup agent
10384 // instantiated. The backup agent will invoke backupAgentCreated() on the
10385 // activity manager to announce its creation.
10386 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10387 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10388 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10389
10390 synchronized(this) {
10391 // !!! TODO: currently no check here that we're already bound
10392 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10393 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10394 synchronized (stats) {
10395 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10396 }
10397
10398 BackupRecord r = new BackupRecord(ss, app, backupMode);
10399 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10400 // startProcessLocked() returns existing proc's record if it's already running
10401 ProcessRecord proc = startProcessLocked(app.processName, app,
10402 false, 0, "backup", hostingName);
10403 if (proc == null) {
10404 Log.e(TAG, "Unable to start backup agent process " + r);
10405 return false;
10406 }
10407
10408 r.app = proc;
10409 mBackupTarget = r;
10410 mBackupAppName = app.packageName;
10411
Christopher Tate6fa95972009-06-05 18:43:55 -070010412 // Try not to kill the process during backup
10413 updateOomAdjLocked(proc);
10414
Christopher Tate181fafa2009-05-14 11:12:14 -070010415 // If the process is already attached, schedule the creation of the backup agent now.
10416 // If it is not yet live, this will be done when it attaches to the framework.
10417 if (proc.thread != null) {
10418 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10419 try {
10420 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10421 } catch (RemoteException e) {
10422 // !!! TODO: notify the backup manager that we crashed, or rely on
10423 // death notices, or...?
10424 }
10425 } else {
10426 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10427 }
10428 // Invariants: at this point, the target app process exists and the application
10429 // is either already running or in the process of coming up. mBackupTarget and
10430 // mBackupAppName describe the app, so that when it binds back to the AM we
10431 // know that it's scheduled for a backup-agent operation.
10432 }
10433
10434 return true;
10435 }
10436
10437 // A backup agent has just come up
10438 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10439 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10440 + " = " + agent);
10441
10442 synchronized(this) {
10443 if (!agentPackageName.equals(mBackupAppName)) {
10444 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10445 return;
10446 }
10447
Christopher Tate043dadc2009-06-02 16:11:00 -070010448 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010449 try {
10450 IBackupManager bm = IBackupManager.Stub.asInterface(
10451 ServiceManager.getService(Context.BACKUP_SERVICE));
10452 bm.agentConnected(agentPackageName, agent);
10453 } catch (RemoteException e) {
10454 // can't happen; the backup manager service is local
10455 } catch (Exception e) {
10456 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10457 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010458 } finally {
10459 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010460 }
10461 }
10462 }
10463
10464 // done with this agent
10465 public void unbindBackupAgent(ApplicationInfo appInfo) {
10466 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10467
10468 synchronized(this) {
10469 if (!mBackupAppName.equals(appInfo.packageName)) {
10470 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10471 return;
10472 }
10473
Christopher Tate6fa95972009-06-05 18:43:55 -070010474 ProcessRecord proc = mBackupTarget.app;
10475 mBackupTarget = null;
10476 mBackupAppName = null;
10477
10478 // Not backing this app up any more; reset its OOM adjustment
10479 updateOomAdjLocked(proc);
10480
Christopher Tatec7b31e32009-06-10 15:49:30 -070010481 // If the app crashed during backup, 'thread' will be null here
10482 if (proc.thread != null) {
10483 try {
10484 proc.thread.scheduleDestroyBackupAgent(appInfo);
10485 } catch (Exception e) {
10486 Log.e(TAG, "Exception when unbinding backup agent:");
10487 e.printStackTrace();
10488 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010489 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010490 }
10491 }
10492 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010493 // BROADCASTS
10494 // =========================================================
10495
10496 private final List getStickies(String action, IntentFilter filter,
10497 List cur) {
10498 final ContentResolver resolver = mContext.getContentResolver();
10499 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10500 if (list == null) {
10501 return cur;
10502 }
10503 int N = list.size();
10504 for (int i=0; i<N; i++) {
10505 Intent intent = list.get(i);
10506 if (filter.match(resolver, intent, true, TAG) >= 0) {
10507 if (cur == null) {
10508 cur = new ArrayList<Intent>();
10509 }
10510 cur.add(intent);
10511 }
10512 }
10513 return cur;
10514 }
10515
10516 private final void scheduleBroadcastsLocked() {
10517 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10518 + mBroadcastsScheduled);
10519
10520 if (mBroadcastsScheduled) {
10521 return;
10522 }
10523 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10524 mBroadcastsScheduled = true;
10525 }
10526
10527 public Intent registerReceiver(IApplicationThread caller,
10528 IIntentReceiver receiver, IntentFilter filter, String permission) {
10529 synchronized(this) {
10530 ProcessRecord callerApp = null;
10531 if (caller != null) {
10532 callerApp = getRecordForAppLocked(caller);
10533 if (callerApp == null) {
10534 throw new SecurityException(
10535 "Unable to find app for caller " + caller
10536 + " (pid=" + Binder.getCallingPid()
10537 + ") when registering receiver " + receiver);
10538 }
10539 }
10540
10541 List allSticky = null;
10542
10543 // Look for any matching sticky broadcasts...
10544 Iterator actions = filter.actionsIterator();
10545 if (actions != null) {
10546 while (actions.hasNext()) {
10547 String action = (String)actions.next();
10548 allSticky = getStickies(action, filter, allSticky);
10549 }
10550 } else {
10551 allSticky = getStickies(null, filter, allSticky);
10552 }
10553
10554 // The first sticky in the list is returned directly back to
10555 // the client.
10556 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10557
10558 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10559 + ": " + sticky);
10560
10561 if (receiver == null) {
10562 return sticky;
10563 }
10564
10565 ReceiverList rl
10566 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10567 if (rl == null) {
10568 rl = new ReceiverList(this, callerApp,
10569 Binder.getCallingPid(),
10570 Binder.getCallingUid(), receiver);
10571 if (rl.app != null) {
10572 rl.app.receivers.add(rl);
10573 } else {
10574 try {
10575 receiver.asBinder().linkToDeath(rl, 0);
10576 } catch (RemoteException e) {
10577 return sticky;
10578 }
10579 rl.linkedToDeath = true;
10580 }
10581 mRegisteredReceivers.put(receiver.asBinder(), rl);
10582 }
10583 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10584 rl.add(bf);
10585 if (!bf.debugCheck()) {
10586 Log.w(TAG, "==> For Dynamic broadast");
10587 }
10588 mReceiverResolver.addFilter(bf);
10589
10590 // Enqueue broadcasts for all existing stickies that match
10591 // this filter.
10592 if (allSticky != null) {
10593 ArrayList receivers = new ArrayList();
10594 receivers.add(bf);
10595
10596 int N = allSticky.size();
10597 for (int i=0; i<N; i++) {
10598 Intent intent = (Intent)allSticky.get(i);
10599 BroadcastRecord r = new BroadcastRecord(intent, null,
10600 null, -1, -1, null, receivers, null, 0, null, null,
10601 false);
10602 if (mParallelBroadcasts.size() == 0) {
10603 scheduleBroadcastsLocked();
10604 }
10605 mParallelBroadcasts.add(r);
10606 }
10607 }
10608
10609 return sticky;
10610 }
10611 }
10612
10613 public void unregisterReceiver(IIntentReceiver receiver) {
10614 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10615
10616 boolean doNext = false;
10617
10618 synchronized(this) {
10619 ReceiverList rl
10620 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10621 if (rl != null) {
10622 if (rl.curBroadcast != null) {
10623 BroadcastRecord r = rl.curBroadcast;
10624 doNext = finishReceiverLocked(
10625 receiver.asBinder(), r.resultCode, r.resultData,
10626 r.resultExtras, r.resultAbort, true);
10627 }
10628
10629 if (rl.app != null) {
10630 rl.app.receivers.remove(rl);
10631 }
10632 removeReceiverLocked(rl);
10633 if (rl.linkedToDeath) {
10634 rl.linkedToDeath = false;
10635 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10636 }
10637 }
10638 }
10639
10640 if (!doNext) {
10641 return;
10642 }
10643
10644 final long origId = Binder.clearCallingIdentity();
10645 processNextBroadcast(false);
10646 trimApplications();
10647 Binder.restoreCallingIdentity(origId);
10648 }
10649
10650 void removeReceiverLocked(ReceiverList rl) {
10651 mRegisteredReceivers.remove(rl.receiver.asBinder());
10652 int N = rl.size();
10653 for (int i=0; i<N; i++) {
10654 mReceiverResolver.removeFilter(rl.get(i));
10655 }
10656 }
10657
10658 private final int broadcastIntentLocked(ProcessRecord callerApp,
10659 String callerPackage, Intent intent, String resolvedType,
10660 IIntentReceiver resultTo, int resultCode, String resultData,
10661 Bundle map, String requiredPermission,
10662 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10663 intent = new Intent(intent);
10664
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010665 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010666 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10667 + " ordered=" + ordered);
10668 if ((resultTo != null) && !ordered) {
10669 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10670 }
10671
10672 // Handle special intents: if this broadcast is from the package
10673 // manager about a package being removed, we need to remove all of
10674 // its activities from the history stack.
10675 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10676 intent.getAction());
10677 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10678 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10679 || uidRemoved) {
10680 if (checkComponentPermission(
10681 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10682 callingPid, callingUid, -1)
10683 == PackageManager.PERMISSION_GRANTED) {
10684 if (uidRemoved) {
10685 final Bundle intentExtras = intent.getExtras();
10686 final int uid = intentExtras != null
10687 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10688 if (uid >= 0) {
10689 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10690 synchronized (bs) {
10691 bs.removeUidStatsLocked(uid);
10692 }
10693 }
10694 } else {
10695 Uri data = intent.getData();
10696 String ssp;
10697 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10698 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10699 uninstallPackageLocked(ssp,
10700 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10701 }
10702 }
10703 }
10704 } else {
10705 String msg = "Permission Denial: " + intent.getAction()
10706 + " broadcast from " + callerPackage + " (pid=" + callingPid
10707 + ", uid=" + callingUid + ")"
10708 + " requires "
10709 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10710 Log.w(TAG, msg);
10711 throw new SecurityException(msg);
10712 }
10713 }
10714
10715 /*
10716 * If this is the time zone changed action, queue up a message that will reset the timezone
10717 * of all currently running processes. This message will get queued up before the broadcast
10718 * happens.
10719 */
10720 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10721 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10722 }
10723
10724 // Add to the sticky list if requested.
10725 if (sticky) {
10726 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10727 callingPid, callingUid)
10728 != PackageManager.PERMISSION_GRANTED) {
10729 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10730 + callingPid + ", uid=" + callingUid
10731 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10732 Log.w(TAG, msg);
10733 throw new SecurityException(msg);
10734 }
10735 if (requiredPermission != null) {
10736 Log.w(TAG, "Can't broadcast sticky intent " + intent
10737 + " and enforce permission " + requiredPermission);
10738 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10739 }
10740 if (intent.getComponent() != null) {
10741 throw new SecurityException(
10742 "Sticky broadcasts can't target a specific component");
10743 }
10744 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10745 if (list == null) {
10746 list = new ArrayList<Intent>();
10747 mStickyBroadcasts.put(intent.getAction(), list);
10748 }
10749 int N = list.size();
10750 int i;
10751 for (i=0; i<N; i++) {
10752 if (intent.filterEquals(list.get(i))) {
10753 // This sticky already exists, replace it.
10754 list.set(i, new Intent(intent));
10755 break;
10756 }
10757 }
10758 if (i >= N) {
10759 list.add(new Intent(intent));
10760 }
10761 }
10762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010763 // Figure out who all will receive this broadcast.
10764 List receivers = null;
10765 List<BroadcastFilter> registeredReceivers = null;
10766 try {
10767 if (intent.getComponent() != null) {
10768 // Broadcast is going to one specific receiver class...
10769 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010770 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010771 if (ai != null) {
10772 receivers = new ArrayList();
10773 ResolveInfo ri = new ResolveInfo();
10774 ri.activityInfo = ai;
10775 receivers.add(ri);
10776 }
10777 } else {
10778 // Need to resolve the intent to interested receivers...
10779 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10780 == 0) {
10781 receivers =
10782 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010783 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010784 }
Mihai Preda074edef2009-05-18 17:13:31 +020010785 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010786 }
10787 } catch (RemoteException ex) {
10788 // pm is in same process, this will never happen.
10789 }
10790
10791 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10792 if (!ordered && NR > 0) {
10793 // If we are not serializing this broadcast, then send the
10794 // registered receivers separately so they don't wait for the
10795 // components to be launched.
10796 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10797 callerPackage, callingPid, callingUid, requiredPermission,
10798 registeredReceivers, resultTo, resultCode, resultData, map,
10799 ordered);
10800 if (DEBUG_BROADCAST) Log.v(
10801 TAG, "Enqueueing parallel broadcast " + r
10802 + ": prev had " + mParallelBroadcasts.size());
10803 mParallelBroadcasts.add(r);
10804 scheduleBroadcastsLocked();
10805 registeredReceivers = null;
10806 NR = 0;
10807 }
10808
10809 // Merge into one list.
10810 int ir = 0;
10811 if (receivers != null) {
10812 // A special case for PACKAGE_ADDED: do not allow the package
10813 // being added to see this broadcast. This prevents them from
10814 // using this as a back door to get run as soon as they are
10815 // installed. Maybe in the future we want to have a special install
10816 // broadcast or such for apps, but we'd like to deliberately make
10817 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010818 boolean skip = false;
10819 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010820 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010821 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10822 skip = true;
10823 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10824 skip = true;
10825 }
10826 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010827 ? intent.getData().getSchemeSpecificPart()
10828 : null;
10829 if (skipPackage != null && receivers != null) {
10830 int NT = receivers.size();
10831 for (int it=0; it<NT; it++) {
10832 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10833 if (curt.activityInfo.packageName.equals(skipPackage)) {
10834 receivers.remove(it);
10835 it--;
10836 NT--;
10837 }
10838 }
10839 }
10840
10841 int NT = receivers != null ? receivers.size() : 0;
10842 int it = 0;
10843 ResolveInfo curt = null;
10844 BroadcastFilter curr = null;
10845 while (it < NT && ir < NR) {
10846 if (curt == null) {
10847 curt = (ResolveInfo)receivers.get(it);
10848 }
10849 if (curr == null) {
10850 curr = registeredReceivers.get(ir);
10851 }
10852 if (curr.getPriority() >= curt.priority) {
10853 // Insert this broadcast record into the final list.
10854 receivers.add(it, curr);
10855 ir++;
10856 curr = null;
10857 it++;
10858 NT++;
10859 } else {
10860 // Skip to the next ResolveInfo in the final list.
10861 it++;
10862 curt = null;
10863 }
10864 }
10865 }
10866 while (ir < NR) {
10867 if (receivers == null) {
10868 receivers = new ArrayList();
10869 }
10870 receivers.add(registeredReceivers.get(ir));
10871 ir++;
10872 }
10873
10874 if ((receivers != null && receivers.size() > 0)
10875 || resultTo != null) {
10876 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10877 callerPackage, callingPid, callingUid, requiredPermission,
10878 receivers, resultTo, resultCode, resultData, map, ordered);
10879 if (DEBUG_BROADCAST) Log.v(
10880 TAG, "Enqueueing ordered broadcast " + r
10881 + ": prev had " + mOrderedBroadcasts.size());
10882 if (DEBUG_BROADCAST) {
10883 int seq = r.intent.getIntExtra("seq", -1);
10884 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10885 }
10886 mOrderedBroadcasts.add(r);
10887 scheduleBroadcastsLocked();
10888 }
10889
10890 return BROADCAST_SUCCESS;
10891 }
10892
10893 public final int broadcastIntent(IApplicationThread caller,
10894 Intent intent, String resolvedType, IIntentReceiver resultTo,
10895 int resultCode, String resultData, Bundle map,
10896 String requiredPermission, boolean serialized, boolean sticky) {
10897 // Refuse possible leaked file descriptors
10898 if (intent != null && intent.hasFileDescriptors() == true) {
10899 throw new IllegalArgumentException("File descriptors passed in Intent");
10900 }
10901
10902 synchronized(this) {
10903 if (!mSystemReady) {
10904 // if the caller really truly claims to know what they're doing, go
10905 // ahead and allow the broadcast without launching any receivers
10906 int flags = intent.getFlags();
10907 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10908 intent = new Intent(intent);
10909 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10910 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10911 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10912 + " before boot completion");
10913 throw new IllegalStateException("Cannot broadcast before boot completed");
10914 }
10915 }
10916
10917 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10918 final int callingPid = Binder.getCallingPid();
10919 final int callingUid = Binder.getCallingUid();
10920 final long origId = Binder.clearCallingIdentity();
10921 int res = broadcastIntentLocked(callerApp,
10922 callerApp != null ? callerApp.info.packageName : null,
10923 intent, resolvedType, resultTo,
10924 resultCode, resultData, map, requiredPermission, serialized,
10925 sticky, callingPid, callingUid);
10926 Binder.restoreCallingIdentity(origId);
10927 return res;
10928 }
10929 }
10930
10931 int broadcastIntentInPackage(String packageName, int uid,
10932 Intent intent, String resolvedType, IIntentReceiver resultTo,
10933 int resultCode, String resultData, Bundle map,
10934 String requiredPermission, boolean serialized, boolean sticky) {
10935 synchronized(this) {
10936 final long origId = Binder.clearCallingIdentity();
10937 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10938 resultTo, resultCode, resultData, map, requiredPermission,
10939 serialized, sticky, -1, uid);
10940 Binder.restoreCallingIdentity(origId);
10941 return res;
10942 }
10943 }
10944
10945 public final void unbroadcastIntent(IApplicationThread caller,
10946 Intent intent) {
10947 // Refuse possible leaked file descriptors
10948 if (intent != null && intent.hasFileDescriptors() == true) {
10949 throw new IllegalArgumentException("File descriptors passed in Intent");
10950 }
10951
10952 synchronized(this) {
10953 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10954 != PackageManager.PERMISSION_GRANTED) {
10955 String msg = "Permission Denial: unbroadcastIntent() from pid="
10956 + Binder.getCallingPid()
10957 + ", uid=" + Binder.getCallingUid()
10958 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10959 Log.w(TAG, msg);
10960 throw new SecurityException(msg);
10961 }
10962 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10963 if (list != null) {
10964 int N = list.size();
10965 int i;
10966 for (i=0; i<N; i++) {
10967 if (intent.filterEquals(list.get(i))) {
10968 list.remove(i);
10969 break;
10970 }
10971 }
10972 }
10973 }
10974 }
10975
10976 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10977 String resultData, Bundle resultExtras, boolean resultAbort,
10978 boolean explicit) {
10979 if (mOrderedBroadcasts.size() == 0) {
10980 if (explicit) {
10981 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10982 }
10983 return false;
10984 }
10985 BroadcastRecord r = mOrderedBroadcasts.get(0);
10986 if (r.receiver == null) {
10987 if (explicit) {
10988 Log.w(TAG, "finishReceiver called but none active");
10989 }
10990 return false;
10991 }
10992 if (r.receiver != receiver) {
10993 Log.w(TAG, "finishReceiver called but active receiver is different");
10994 return false;
10995 }
10996 int state = r.state;
10997 r.state = r.IDLE;
10998 if (state == r.IDLE) {
10999 if (explicit) {
11000 Log.w(TAG, "finishReceiver called but state is IDLE");
11001 }
11002 }
11003 r.receiver = null;
11004 r.intent.setComponent(null);
11005 if (r.curApp != null) {
11006 r.curApp.curReceiver = null;
11007 }
11008 if (r.curFilter != null) {
11009 r.curFilter.receiverList.curBroadcast = null;
11010 }
11011 r.curFilter = null;
11012 r.curApp = null;
11013 r.curComponent = null;
11014 r.curReceiver = null;
11015 mPendingBroadcast = null;
11016
11017 r.resultCode = resultCode;
11018 r.resultData = resultData;
11019 r.resultExtras = resultExtras;
11020 r.resultAbort = resultAbort;
11021
11022 // We will process the next receiver right now if this is finishing
11023 // an app receiver (which is always asynchronous) or after we have
11024 // come back from calling a receiver.
11025 return state == BroadcastRecord.APP_RECEIVE
11026 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11027 }
11028
11029 public void finishReceiver(IBinder who, int resultCode, String resultData,
11030 Bundle resultExtras, boolean resultAbort) {
11031 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11032
11033 // Refuse possible leaked file descriptors
11034 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11035 throw new IllegalArgumentException("File descriptors passed in Bundle");
11036 }
11037
11038 boolean doNext;
11039
11040 final long origId = Binder.clearCallingIdentity();
11041
11042 synchronized(this) {
11043 doNext = finishReceiverLocked(
11044 who, resultCode, resultData, resultExtras, resultAbort, true);
11045 }
11046
11047 if (doNext) {
11048 processNextBroadcast(false);
11049 }
11050 trimApplications();
11051
11052 Binder.restoreCallingIdentity(origId);
11053 }
11054
11055 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11056 if (r.nextReceiver > 0) {
11057 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11058 if (curReceiver instanceof BroadcastFilter) {
11059 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11060 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11061 System.identityHashCode(r),
11062 r.intent.getAction(),
11063 r.nextReceiver - 1,
11064 System.identityHashCode(bf));
11065 } else {
11066 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11067 System.identityHashCode(r),
11068 r.intent.getAction(),
11069 r.nextReceiver - 1,
11070 ((ResolveInfo)curReceiver).toString());
11071 }
11072 } else {
11073 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11074 + r);
11075 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11076 System.identityHashCode(r),
11077 r.intent.getAction(),
11078 r.nextReceiver,
11079 "NONE");
11080 }
11081 }
11082
11083 private final void broadcastTimeout() {
11084 synchronized (this) {
11085 if (mOrderedBroadcasts.size() == 0) {
11086 return;
11087 }
11088 long now = SystemClock.uptimeMillis();
11089 BroadcastRecord r = mOrderedBroadcasts.get(0);
11090 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11091 if (DEBUG_BROADCAST) Log.v(TAG,
11092 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11093 + (r.startTime + BROADCAST_TIMEOUT));
11094 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11095 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11096 return;
11097 }
11098
11099 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11100 r.startTime = now;
11101 r.anrCount++;
11102
11103 // Current receiver has passed its expiration date.
11104 if (r.nextReceiver <= 0) {
11105 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11106 return;
11107 }
11108
11109 ProcessRecord app = null;
11110
11111 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11112 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11113 logBroadcastReceiverDiscard(r);
11114 if (curReceiver instanceof BroadcastFilter) {
11115 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11116 if (bf.receiverList.pid != 0
11117 && bf.receiverList.pid != MY_PID) {
11118 synchronized (this.mPidsSelfLocked) {
11119 app = this.mPidsSelfLocked.get(
11120 bf.receiverList.pid);
11121 }
11122 }
11123 } else {
11124 app = r.curApp;
11125 }
11126
11127 if (app != null) {
11128 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11129 }
11130
11131 if (mPendingBroadcast == r) {
11132 mPendingBroadcast = null;
11133 }
11134
11135 // Move on to the next receiver.
11136 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11137 r.resultExtras, r.resultAbort, true);
11138 scheduleBroadcastsLocked();
11139 }
11140 }
11141
11142 private final void processCurBroadcastLocked(BroadcastRecord r,
11143 ProcessRecord app) throws RemoteException {
11144 if (app.thread == null) {
11145 throw new RemoteException();
11146 }
11147 r.receiver = app.thread.asBinder();
11148 r.curApp = app;
11149 app.curReceiver = r;
11150 updateLRUListLocked(app, true);
11151
11152 // Tell the application to launch this receiver.
11153 r.intent.setComponent(r.curComponent);
11154
11155 boolean started = false;
11156 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011157 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011158 "Delivering to component " + r.curComponent
11159 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011160 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011161 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11162 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11163 started = true;
11164 } finally {
11165 if (!started) {
11166 r.receiver = null;
11167 r.curApp = null;
11168 app.curReceiver = null;
11169 }
11170 }
11171
11172 }
11173
11174 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11175 Intent intent, int resultCode, String data,
11176 Bundle extras, boolean ordered) throws RemoteException {
11177 if (app != null && app.thread != null) {
11178 // If we have an app thread, do the call through that so it is
11179 // correctly ordered with other one-way calls.
11180 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11181 data, extras, ordered);
11182 } else {
11183 receiver.performReceive(intent, resultCode, data, extras, ordered);
11184 }
11185 }
11186
11187 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11188 BroadcastFilter filter, boolean ordered) {
11189 boolean skip = false;
11190 if (filter.requiredPermission != null) {
11191 int perm = checkComponentPermission(filter.requiredPermission,
11192 r.callingPid, r.callingUid, -1);
11193 if (perm != PackageManager.PERMISSION_GRANTED) {
11194 Log.w(TAG, "Permission Denial: broadcasting "
11195 + r.intent.toString()
11196 + " from " + r.callerPackage + " (pid="
11197 + r.callingPid + ", uid=" + r.callingUid + ")"
11198 + " requires " + filter.requiredPermission
11199 + " due to registered receiver " + filter);
11200 skip = true;
11201 }
11202 }
11203 if (r.requiredPermission != null) {
11204 int perm = checkComponentPermission(r.requiredPermission,
11205 filter.receiverList.pid, filter.receiverList.uid, -1);
11206 if (perm != PackageManager.PERMISSION_GRANTED) {
11207 Log.w(TAG, "Permission Denial: receiving "
11208 + r.intent.toString()
11209 + " to " + filter.receiverList.app
11210 + " (pid=" + filter.receiverList.pid
11211 + ", uid=" + filter.receiverList.uid + ")"
11212 + " requires " + r.requiredPermission
11213 + " due to sender " + r.callerPackage
11214 + " (uid " + r.callingUid + ")");
11215 skip = true;
11216 }
11217 }
11218
11219 if (!skip) {
11220 // If this is not being sent as an ordered broadcast, then we
11221 // don't want to touch the fields that keep track of the current
11222 // state of ordered broadcasts.
11223 if (ordered) {
11224 r.receiver = filter.receiverList.receiver.asBinder();
11225 r.curFilter = filter;
11226 filter.receiverList.curBroadcast = r;
11227 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011228 if (filter.receiverList.app != null) {
11229 // Bump hosting application to no longer be in background
11230 // scheduling class. Note that we can't do that if there
11231 // isn't an app... but we can only be in that case for
11232 // things that directly call the IActivityManager API, which
11233 // are already core system stuff so don't matter for this.
11234 r.curApp = filter.receiverList.app;
11235 filter.receiverList.app.curReceiver = r;
11236 updateOomAdjLocked();
11237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011238 }
11239 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011240 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011241 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011242 Log.i(TAG, "Delivering to " + filter.receiverList.app
11243 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011244 }
11245 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11246 new Intent(r.intent), r.resultCode,
11247 r.resultData, r.resultExtras, r.ordered);
11248 if (ordered) {
11249 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11250 }
11251 } catch (RemoteException e) {
11252 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11253 if (ordered) {
11254 r.receiver = null;
11255 r.curFilter = null;
11256 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011257 if (filter.receiverList.app != null) {
11258 filter.receiverList.app.curReceiver = null;
11259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011260 }
11261 }
11262 }
11263 }
11264
11265 private final void processNextBroadcast(boolean fromMsg) {
11266 synchronized(this) {
11267 BroadcastRecord r;
11268
11269 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11270 + mParallelBroadcasts.size() + " broadcasts, "
11271 + mOrderedBroadcasts.size() + " serialized broadcasts");
11272
11273 updateCpuStats();
11274
11275 if (fromMsg) {
11276 mBroadcastsScheduled = false;
11277 }
11278
11279 // First, deliver any non-serialized broadcasts right away.
11280 while (mParallelBroadcasts.size() > 0) {
11281 r = mParallelBroadcasts.remove(0);
11282 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011283 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11284 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011285 for (int i=0; i<N; i++) {
11286 Object target = r.receivers.get(i);
11287 if (DEBUG_BROADCAST) Log.v(TAG,
11288 "Delivering non-serialized to registered "
11289 + target + ": " + r);
11290 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11291 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011292 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11293 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011294 }
11295
11296 // Now take care of the next serialized one...
11297
11298 // If we are waiting for a process to come up to handle the next
11299 // broadcast, then do nothing at this point. Just in case, we
11300 // check that the process we're waiting for still exists.
11301 if (mPendingBroadcast != null) {
11302 Log.i(TAG, "processNextBroadcast: waiting for "
11303 + mPendingBroadcast.curApp);
11304
11305 boolean isDead;
11306 synchronized (mPidsSelfLocked) {
11307 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11308 }
11309 if (!isDead) {
11310 // It's still alive, so keep waiting
11311 return;
11312 } else {
11313 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11314 + " died before responding to broadcast");
11315 mPendingBroadcast = null;
11316 }
11317 }
11318
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011319 boolean looped = false;
11320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011321 do {
11322 if (mOrderedBroadcasts.size() == 0) {
11323 // No more broadcasts pending, so all done!
11324 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011325 if (looped) {
11326 // If we had finished the last ordered broadcast, then
11327 // make sure all processes have correct oom and sched
11328 // adjustments.
11329 updateOomAdjLocked();
11330 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011331 return;
11332 }
11333 r = mOrderedBroadcasts.get(0);
11334 boolean forceReceive = false;
11335
11336 // Ensure that even if something goes awry with the timeout
11337 // detection, we catch "hung" broadcasts here, discard them,
11338 // and continue to make progress.
11339 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11340 long now = SystemClock.uptimeMillis();
11341 if (r.dispatchTime > 0) {
11342 if ((numReceivers > 0) &&
11343 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11344 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11345 + " now=" + now
11346 + " dispatchTime=" + r.dispatchTime
11347 + " startTime=" + r.startTime
11348 + " intent=" + r.intent
11349 + " numReceivers=" + numReceivers
11350 + " nextReceiver=" + r.nextReceiver
11351 + " state=" + r.state);
11352 broadcastTimeout(); // forcibly finish this broadcast
11353 forceReceive = true;
11354 r.state = BroadcastRecord.IDLE;
11355 }
11356 }
11357
11358 if (r.state != BroadcastRecord.IDLE) {
11359 if (DEBUG_BROADCAST) Log.d(TAG,
11360 "processNextBroadcast() called when not idle (state="
11361 + r.state + ")");
11362 return;
11363 }
11364
11365 if (r.receivers == null || r.nextReceiver >= numReceivers
11366 || r.resultAbort || forceReceive) {
11367 // No more receivers for this broadcast! Send the final
11368 // result if requested...
11369 if (r.resultTo != null) {
11370 try {
11371 if (DEBUG_BROADCAST) {
11372 int seq = r.intent.getIntExtra("seq", -1);
11373 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11374 + " seq=" + seq + " app=" + r.callerApp);
11375 }
11376 performReceive(r.callerApp, r.resultTo,
11377 new Intent(r.intent), r.resultCode,
11378 r.resultData, r.resultExtras, false);
11379 } catch (RemoteException e) {
11380 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11381 }
11382 }
11383
11384 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11385 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11386
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011387 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11388 + r);
11389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011390 // ... and on to the next...
11391 mOrderedBroadcasts.remove(0);
11392 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011393 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011394 continue;
11395 }
11396 } while (r == null);
11397
11398 // Get the next receiver...
11399 int recIdx = r.nextReceiver++;
11400
11401 // Keep track of when this receiver started, and make sure there
11402 // is a timeout message pending to kill it if need be.
11403 r.startTime = SystemClock.uptimeMillis();
11404 if (recIdx == 0) {
11405 r.dispatchTime = r.startTime;
11406
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011407 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11408 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011409 if (DEBUG_BROADCAST) Log.v(TAG,
11410 "Submitting BROADCAST_TIMEOUT_MSG for "
11411 + (r.startTime + BROADCAST_TIMEOUT));
11412 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11413 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11414 }
11415
11416 Object nextReceiver = r.receivers.get(recIdx);
11417 if (nextReceiver instanceof BroadcastFilter) {
11418 // Simple case: this is a registered receiver who gets
11419 // a direct call.
11420 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11421 if (DEBUG_BROADCAST) Log.v(TAG,
11422 "Delivering serialized to registered "
11423 + filter + ": " + r);
11424 deliverToRegisteredReceiver(r, filter, r.ordered);
11425 if (r.receiver == null || !r.ordered) {
11426 // The receiver has already finished, so schedule to
11427 // process the next one.
11428 r.state = BroadcastRecord.IDLE;
11429 scheduleBroadcastsLocked();
11430 }
11431 return;
11432 }
11433
11434 // Hard case: need to instantiate the receiver, possibly
11435 // starting its application process to host it.
11436
11437 ResolveInfo info =
11438 (ResolveInfo)nextReceiver;
11439
11440 boolean skip = false;
11441 int perm = checkComponentPermission(info.activityInfo.permission,
11442 r.callingPid, r.callingUid,
11443 info.activityInfo.exported
11444 ? -1 : info.activityInfo.applicationInfo.uid);
11445 if (perm != PackageManager.PERMISSION_GRANTED) {
11446 Log.w(TAG, "Permission Denial: broadcasting "
11447 + r.intent.toString()
11448 + " from " + r.callerPackage + " (pid=" + r.callingPid
11449 + ", uid=" + r.callingUid + ")"
11450 + " requires " + info.activityInfo.permission
11451 + " due to receiver " + info.activityInfo.packageName
11452 + "/" + info.activityInfo.name);
11453 skip = true;
11454 }
11455 if (r.callingUid != Process.SYSTEM_UID &&
11456 r.requiredPermission != null) {
11457 try {
11458 perm = ActivityThread.getPackageManager().
11459 checkPermission(r.requiredPermission,
11460 info.activityInfo.applicationInfo.packageName);
11461 } catch (RemoteException e) {
11462 perm = PackageManager.PERMISSION_DENIED;
11463 }
11464 if (perm != PackageManager.PERMISSION_GRANTED) {
11465 Log.w(TAG, "Permission Denial: receiving "
11466 + r.intent + " to "
11467 + info.activityInfo.applicationInfo.packageName
11468 + " requires " + r.requiredPermission
11469 + " due to sender " + r.callerPackage
11470 + " (uid " + r.callingUid + ")");
11471 skip = true;
11472 }
11473 }
11474 if (r.curApp != null && r.curApp.crashing) {
11475 // If the target process is crashing, just skip it.
11476 skip = true;
11477 }
11478
11479 if (skip) {
11480 r.receiver = null;
11481 r.curFilter = null;
11482 r.state = BroadcastRecord.IDLE;
11483 scheduleBroadcastsLocked();
11484 return;
11485 }
11486
11487 r.state = BroadcastRecord.APP_RECEIVE;
11488 String targetProcess = info.activityInfo.processName;
11489 r.curComponent = new ComponentName(
11490 info.activityInfo.applicationInfo.packageName,
11491 info.activityInfo.name);
11492 r.curReceiver = info.activityInfo;
11493
11494 // Is this receiver's application already running?
11495 ProcessRecord app = getProcessRecordLocked(targetProcess,
11496 info.activityInfo.applicationInfo.uid);
11497 if (app != null && app.thread != null) {
11498 try {
11499 processCurBroadcastLocked(r, app);
11500 return;
11501 } catch (RemoteException e) {
11502 Log.w(TAG, "Exception when sending broadcast to "
11503 + r.curComponent, e);
11504 }
11505
11506 // If a dead object exception was thrown -- fall through to
11507 // restart the application.
11508 }
11509
11510 // Not running -- get it started, and enqueue this history record
11511 // to be executed when the app comes up.
11512 if ((r.curApp=startProcessLocked(targetProcess,
11513 info.activityInfo.applicationInfo, true,
11514 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11515 "broadcast", r.curComponent)) == null) {
11516 // Ah, this recipient is unavailable. Finish it if necessary,
11517 // and mark the broadcast record as ready for the next.
11518 Log.w(TAG, "Unable to launch app "
11519 + info.activityInfo.applicationInfo.packageName + "/"
11520 + info.activityInfo.applicationInfo.uid + " for broadcast "
11521 + r.intent + ": process is bad");
11522 logBroadcastReceiverDiscard(r);
11523 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11524 r.resultExtras, r.resultAbort, true);
11525 scheduleBroadcastsLocked();
11526 r.state = BroadcastRecord.IDLE;
11527 return;
11528 }
11529
11530 mPendingBroadcast = r;
11531 }
11532 }
11533
11534 // =========================================================
11535 // INSTRUMENTATION
11536 // =========================================================
11537
11538 public boolean startInstrumentation(ComponentName className,
11539 String profileFile, int flags, Bundle arguments,
11540 IInstrumentationWatcher watcher) {
11541 // Refuse possible leaked file descriptors
11542 if (arguments != null && arguments.hasFileDescriptors()) {
11543 throw new IllegalArgumentException("File descriptors passed in Bundle");
11544 }
11545
11546 synchronized(this) {
11547 InstrumentationInfo ii = null;
11548 ApplicationInfo ai = null;
11549 try {
11550 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011551 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011552 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011553 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011554 } catch (PackageManager.NameNotFoundException e) {
11555 }
11556 if (ii == null) {
11557 reportStartInstrumentationFailure(watcher, className,
11558 "Unable to find instrumentation info for: " + className);
11559 return false;
11560 }
11561 if (ai == null) {
11562 reportStartInstrumentationFailure(watcher, className,
11563 "Unable to find instrumentation target package: " + ii.targetPackage);
11564 return false;
11565 }
11566
11567 int match = mContext.getPackageManager().checkSignatures(
11568 ii.targetPackage, ii.packageName);
11569 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11570 String msg = "Permission Denial: starting instrumentation "
11571 + className + " from pid="
11572 + Binder.getCallingPid()
11573 + ", uid=" + Binder.getCallingPid()
11574 + " not allowed because package " + ii.packageName
11575 + " does not have a signature matching the target "
11576 + ii.targetPackage;
11577 reportStartInstrumentationFailure(watcher, className, msg);
11578 throw new SecurityException(msg);
11579 }
11580
11581 final long origId = Binder.clearCallingIdentity();
11582 uninstallPackageLocked(ii.targetPackage, -1, true);
11583 ProcessRecord app = addAppLocked(ai);
11584 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011585 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011586 app.instrumentationProfileFile = profileFile;
11587 app.instrumentationArguments = arguments;
11588 app.instrumentationWatcher = watcher;
11589 app.instrumentationResultClass = className;
11590 Binder.restoreCallingIdentity(origId);
11591 }
11592
11593 return true;
11594 }
11595
11596 /**
11597 * Report errors that occur while attempting to start Instrumentation. Always writes the
11598 * error to the logs, but if somebody is watching, send the report there too. This enables
11599 * the "am" command to report errors with more information.
11600 *
11601 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11602 * @param cn The component name of the instrumentation.
11603 * @param report The error report.
11604 */
11605 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11606 ComponentName cn, String report) {
11607 Log.w(TAG, report);
11608 try {
11609 if (watcher != null) {
11610 Bundle results = new Bundle();
11611 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11612 results.putString("Error", report);
11613 watcher.instrumentationStatus(cn, -1, results);
11614 }
11615 } catch (RemoteException e) {
11616 Log.w(TAG, e);
11617 }
11618 }
11619
11620 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11621 if (app.instrumentationWatcher != null) {
11622 try {
11623 // NOTE: IInstrumentationWatcher *must* be oneway here
11624 app.instrumentationWatcher.instrumentationFinished(
11625 app.instrumentationClass,
11626 resultCode,
11627 results);
11628 } catch (RemoteException e) {
11629 }
11630 }
11631 app.instrumentationWatcher = null;
11632 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011633 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011634 app.instrumentationProfileFile = null;
11635 app.instrumentationArguments = null;
11636
11637 uninstallPackageLocked(app.processName, -1, false);
11638 }
11639
11640 public void finishInstrumentation(IApplicationThread target,
11641 int resultCode, Bundle results) {
11642 // Refuse possible leaked file descriptors
11643 if (results != null && results.hasFileDescriptors()) {
11644 throw new IllegalArgumentException("File descriptors passed in Intent");
11645 }
11646
11647 synchronized(this) {
11648 ProcessRecord app = getRecordForAppLocked(target);
11649 if (app == null) {
11650 Log.w(TAG, "finishInstrumentation: no app for " + target);
11651 return;
11652 }
11653 final long origId = Binder.clearCallingIdentity();
11654 finishInstrumentationLocked(app, resultCode, results);
11655 Binder.restoreCallingIdentity(origId);
11656 }
11657 }
11658
11659 // =========================================================
11660 // CONFIGURATION
11661 // =========================================================
11662
11663 public ConfigurationInfo getDeviceConfigurationInfo() {
11664 ConfigurationInfo config = new ConfigurationInfo();
11665 synchronized (this) {
11666 config.reqTouchScreen = mConfiguration.touchscreen;
11667 config.reqKeyboardType = mConfiguration.keyboard;
11668 config.reqNavigation = mConfiguration.navigation;
11669 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11670 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11671 }
11672 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11673 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11674 }
11675 }
11676 return config;
11677 }
11678
11679 public Configuration getConfiguration() {
11680 Configuration ci;
11681 synchronized(this) {
11682 ci = new Configuration(mConfiguration);
11683 }
11684 return ci;
11685 }
11686
11687 public void updateConfiguration(Configuration values) {
11688 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11689 "updateConfiguration()");
11690
11691 synchronized(this) {
11692 if (values == null && mWindowManager != null) {
11693 // sentinel: fetch the current configuration from the window manager
11694 values = mWindowManager.computeNewConfiguration();
11695 }
11696
11697 final long origId = Binder.clearCallingIdentity();
11698 updateConfigurationLocked(values, null);
11699 Binder.restoreCallingIdentity(origId);
11700 }
11701 }
11702
11703 /**
11704 * Do either or both things: (1) change the current configuration, and (2)
11705 * make sure the given activity is running with the (now) current
11706 * configuration. Returns true if the activity has been left running, or
11707 * false if <var>starting</var> is being destroyed to match the new
11708 * configuration.
11709 */
11710 public boolean updateConfigurationLocked(Configuration values,
11711 HistoryRecord starting) {
11712 int changes = 0;
11713
11714 boolean kept = true;
11715
11716 if (values != null) {
11717 Configuration newConfig = new Configuration(mConfiguration);
11718 changes = newConfig.updateFrom(values);
11719 if (changes != 0) {
11720 if (DEBUG_SWITCH) {
11721 Log.i(TAG, "Updating configuration to: " + values);
11722 }
11723
11724 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11725
11726 if (values.locale != null) {
11727 saveLocaleLocked(values.locale,
11728 !values.locale.equals(mConfiguration.locale),
11729 values.userSetLocale);
11730 }
11731
11732 mConfiguration = newConfig;
11733
11734 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11735 msg.obj = new Configuration(mConfiguration);
11736 mHandler.sendMessage(msg);
11737
11738 final int N = mLRUProcesses.size();
11739 for (int i=0; i<N; i++) {
11740 ProcessRecord app = mLRUProcesses.get(i);
11741 try {
11742 if (app.thread != null) {
11743 app.thread.scheduleConfigurationChanged(mConfiguration);
11744 }
11745 } catch (Exception e) {
11746 }
11747 }
11748 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11749 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11750 null, false, false, MY_PID, Process.SYSTEM_UID);
11751 }
11752 }
11753
11754 if (changes != 0 && starting == null) {
11755 // If the configuration changed, and the caller is not already
11756 // in the process of starting an activity, then find the top
11757 // activity to check if its configuration needs to change.
11758 starting = topRunningActivityLocked(null);
11759 }
11760
11761 if (starting != null) {
11762 kept = ensureActivityConfigurationLocked(starting, changes);
11763 if (kept) {
11764 // If this didn't result in the starting activity being
11765 // destroyed, then we need to make sure at this point that all
11766 // other activities are made visible.
11767 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11768 + ", ensuring others are correct.");
11769 ensureActivitiesVisibleLocked(starting, changes);
11770 }
11771 }
11772
11773 return kept;
11774 }
11775
11776 private final boolean relaunchActivityLocked(HistoryRecord r,
11777 int changes, boolean andResume) {
11778 List<ResultInfo> results = null;
11779 List<Intent> newIntents = null;
11780 if (andResume) {
11781 results = r.results;
11782 newIntents = r.newIntents;
11783 }
11784 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11785 + " with results=" + results + " newIntents=" + newIntents
11786 + " andResume=" + andResume);
11787 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11788 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11789 r.task.taskId, r.shortComponentName);
11790
11791 r.startFreezingScreenLocked(r.app, 0);
11792
11793 try {
11794 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11795 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11796 changes, !andResume);
11797 // Note: don't need to call pauseIfSleepingLocked() here, because
11798 // the caller will only pass in 'andResume' if this activity is
11799 // currently resumed, which implies we aren't sleeping.
11800 } catch (RemoteException e) {
11801 return false;
11802 }
11803
11804 if (andResume) {
11805 r.results = null;
11806 r.newIntents = null;
11807 }
11808
11809 return true;
11810 }
11811
11812 /**
11813 * Make sure the given activity matches the current configuration. Returns
11814 * false if the activity had to be destroyed. Returns true if the
11815 * configuration is the same, or the activity will remain running as-is
11816 * for whatever reason. Ensures the HistoryRecord is updated with the
11817 * correct configuration and all other bookkeeping is handled.
11818 */
11819 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11820 int globalChanges) {
11821 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11822
11823 // Short circuit: if the two configurations are the exact same
11824 // object (the common case), then there is nothing to do.
11825 Configuration newConfig = mConfiguration;
11826 if (r.configuration == newConfig) {
11827 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11828 return true;
11829 }
11830
11831 // We don't worry about activities that are finishing.
11832 if (r.finishing) {
11833 if (DEBUG_SWITCH) Log.i(TAG,
11834 "Configuration doesn't matter in finishing " + r);
11835 r.stopFreezingScreenLocked(false);
11836 return true;
11837 }
11838
11839 // Okay we now are going to make this activity have the new config.
11840 // But then we need to figure out how it needs to deal with that.
11841 Configuration oldConfig = r.configuration;
11842 r.configuration = newConfig;
11843
11844 // If the activity isn't currently running, just leave the new
11845 // configuration and it will pick that up next time it starts.
11846 if (r.app == null || r.app.thread == null) {
11847 if (DEBUG_SWITCH) Log.i(TAG,
11848 "Configuration doesn't matter not running " + r);
11849 r.stopFreezingScreenLocked(false);
11850 return true;
11851 }
11852
11853 // If the activity isn't persistent, there is a chance we will
11854 // need to restart it.
11855 if (!r.persistent) {
11856
11857 // Figure out what has changed between the two configurations.
11858 int changes = oldConfig.diff(newConfig);
11859 if (DEBUG_SWITCH) {
11860 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11861 + Integer.toHexString(changes) + ", handles=0x"
11862 + Integer.toHexString(r.info.configChanges));
11863 }
11864 if ((changes&(~r.info.configChanges)) != 0) {
11865 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11866 r.configChangeFlags |= changes;
11867 r.startFreezingScreenLocked(r.app, globalChanges);
11868 if (r.app == null || r.app.thread == null) {
11869 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11870 destroyActivityLocked(r, true);
11871 } else if (r.state == ActivityState.PAUSING) {
11872 // A little annoying: we are waiting for this activity to
11873 // finish pausing. Let's not do anything now, but just
11874 // flag that it needs to be restarted when done pausing.
11875 r.configDestroy = true;
11876 return true;
11877 } else if (r.state == ActivityState.RESUMED) {
11878 // Try to optimize this case: the configuration is changing
11879 // and we need to restart the top, resumed activity.
11880 // Instead of doing the normal handshaking, just say
11881 // "restart!".
11882 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11883 relaunchActivityLocked(r, r.configChangeFlags, true);
11884 r.configChangeFlags = 0;
11885 } else {
11886 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11887 relaunchActivityLocked(r, r.configChangeFlags, false);
11888 r.configChangeFlags = 0;
11889 }
11890
11891 // All done... tell the caller we weren't able to keep this
11892 // activity around.
11893 return false;
11894 }
11895 }
11896
11897 // Default case: the activity can handle this new configuration, so
11898 // hand it over. Note that we don't need to give it the new
11899 // configuration, since we always send configuration changes to all
11900 // process when they happen so it can just use whatever configuration
11901 // it last got.
11902 if (r.app != null && r.app.thread != null) {
11903 try {
11904 r.app.thread.scheduleActivityConfigurationChanged(r);
11905 } catch (RemoteException e) {
11906 // If process died, whatever.
11907 }
11908 }
11909 r.stopFreezingScreenLocked(false);
11910
11911 return true;
11912 }
11913
11914 /**
11915 * Save the locale. You must be inside a synchronized (this) block.
11916 */
11917 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11918 if(isDiff) {
11919 SystemProperties.set("user.language", l.getLanguage());
11920 SystemProperties.set("user.region", l.getCountry());
11921 }
11922
11923 if(isPersist) {
11924 SystemProperties.set("persist.sys.language", l.getLanguage());
11925 SystemProperties.set("persist.sys.country", l.getCountry());
11926 SystemProperties.set("persist.sys.localevar", l.getVariant());
11927 }
11928 }
11929
11930 // =========================================================
11931 // LIFETIME MANAGEMENT
11932 // =========================================================
11933
11934 private final int computeOomAdjLocked(
11935 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11936 if (mAdjSeq == app.adjSeq) {
11937 // This adjustment has already been computed.
11938 return app.curAdj;
11939 }
11940
11941 if (app.thread == null) {
11942 app.adjSeq = mAdjSeq;
11943 return (app.curAdj=EMPTY_APP_ADJ);
11944 }
11945
11946 app.isForeground = false;
11947
The Android Open Source Project4df24232009-03-05 14:34:35 -080011948 // Determine the importance of the process, starting with most
11949 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011950 int adj;
11951 int N;
11952 if (app == TOP_APP || app.instrumentationClass != null
11953 || app.persistentActivities > 0) {
11954 // The last app on the list is the foreground app.
11955 adj = FOREGROUND_APP_ADJ;
11956 app.isForeground = true;
11957 } else if (app.curReceiver != null ||
11958 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11959 // An app that is currently receiving a broadcast also
11960 // counts as being in the foreground.
11961 adj = FOREGROUND_APP_ADJ;
11962 } else if (app.executingServices.size() > 0) {
11963 // An app that is currently executing a service callback also
11964 // counts as being in the foreground.
11965 adj = FOREGROUND_APP_ADJ;
11966 } else if (app.foregroundServices || app.forcingToForeground != null) {
11967 // The user is aware of this app, so make it visible.
11968 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011969 } else if (app == mHomeProcess) {
11970 // This process is hosting what we currently consider to be the
11971 // home app, so we don't want to let it go into the background.
11972 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011973 } else if ((N=app.activities.size()) != 0) {
11974 // This app is in the background with paused activities.
11975 adj = hiddenAdj;
11976 for (int j=0; j<N; j++) {
11977 if (((HistoryRecord)app.activities.get(j)).visible) {
11978 // This app has a visible activity!
11979 adj = VISIBLE_APP_ADJ;
11980 break;
11981 }
11982 }
11983 } else {
11984 // A very not-needed process.
11985 adj = EMPTY_APP_ADJ;
11986 }
11987
The Android Open Source Project4df24232009-03-05 14:34:35 -080011988 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011989 // there are applications dependent on our services or providers, but
11990 // this gives us a baseline and makes sure we don't get into an
11991 // infinite recursion.
11992 app.adjSeq = mAdjSeq;
11993 app.curRawAdj = adj;
11994 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11995
Christopher Tate6fa95972009-06-05 18:43:55 -070011996 if (mBackupTarget != null && app == mBackupTarget.app) {
11997 // If possible we want to avoid killing apps while they're being backed up
11998 if (adj > BACKUP_APP_ADJ) {
11999 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12000 adj = BACKUP_APP_ADJ;
12001 }
12002 }
12003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012004 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12005 // If this process has active services running in it, we would
12006 // like to avoid killing it unless it would prevent the current
12007 // application from running.
12008 if (adj > hiddenAdj) {
12009 adj = hiddenAdj;
12010 }
12011 final long now = SystemClock.uptimeMillis();
12012 // This process is more important if the top activity is
12013 // bound to the service.
12014 Iterator jt = app.services.iterator();
12015 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12016 ServiceRecord s = (ServiceRecord)jt.next();
12017 if (s.startRequested) {
12018 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12019 // This service has seen some activity within
12020 // recent memory, so we will keep its process ahead
12021 // of the background processes.
12022 if (adj > SECONDARY_SERVER_ADJ) {
12023 adj = SECONDARY_SERVER_ADJ;
12024 }
12025 } else {
12026 // This service has been inactive for too long, just
12027 // put it with the rest of the background processes.
12028 if (adj > hiddenAdj) {
12029 adj = hiddenAdj;
12030 }
12031 }
12032 }
12033 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12034 Iterator<ConnectionRecord> kt
12035 = s.connections.values().iterator();
12036 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12037 // XXX should compute this based on the max of
12038 // all connected clients.
12039 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012040 if (cr.binding.client == app) {
12041 // Binding to ourself is not interesting.
12042 continue;
12043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012044 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12045 ProcessRecord client = cr.binding.client;
12046 int myHiddenAdj = hiddenAdj;
12047 if (myHiddenAdj > client.hiddenAdj) {
12048 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12049 myHiddenAdj = client.hiddenAdj;
12050 } else {
12051 myHiddenAdj = VISIBLE_APP_ADJ;
12052 }
12053 }
12054 int clientAdj = computeOomAdjLocked(
12055 client, myHiddenAdj, TOP_APP);
12056 if (adj > clientAdj) {
12057 adj = clientAdj > VISIBLE_APP_ADJ
12058 ? clientAdj : VISIBLE_APP_ADJ;
12059 }
12060 }
12061 HistoryRecord a = cr.activity;
12062 //if (a != null) {
12063 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12064 //}
12065 if (a != null && adj > FOREGROUND_APP_ADJ &&
12066 (a.state == ActivityState.RESUMED
12067 || a.state == ActivityState.PAUSING)) {
12068 adj = FOREGROUND_APP_ADJ;
12069 }
12070 }
12071 }
12072 }
12073 }
12074
12075 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12076 // If this process has published any content providers, then
12077 // its adjustment makes it at least as important as any of the
12078 // processes using those providers, and no less important than
12079 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12080 if (adj > CONTENT_PROVIDER_ADJ) {
12081 adj = CONTENT_PROVIDER_ADJ;
12082 }
12083 Iterator jt = app.pubProviders.values().iterator();
12084 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12085 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12086 if (cpr.clients.size() != 0) {
12087 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12088 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12089 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012090 if (client == app) {
12091 // Being our own client is not interesting.
12092 continue;
12093 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012094 int myHiddenAdj = hiddenAdj;
12095 if (myHiddenAdj > client.hiddenAdj) {
12096 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12097 myHiddenAdj = client.hiddenAdj;
12098 } else {
12099 myHiddenAdj = FOREGROUND_APP_ADJ;
12100 }
12101 }
12102 int clientAdj = computeOomAdjLocked(
12103 client, myHiddenAdj, TOP_APP);
12104 if (adj > clientAdj) {
12105 adj = clientAdj > FOREGROUND_APP_ADJ
12106 ? clientAdj : FOREGROUND_APP_ADJ;
12107 }
12108 }
12109 }
12110 // If the provider has external (non-framework) process
12111 // dependencies, ensure that its adjustment is at least
12112 // FOREGROUND_APP_ADJ.
12113 if (cpr.externals != 0) {
12114 if (adj > FOREGROUND_APP_ADJ) {
12115 adj = FOREGROUND_APP_ADJ;
12116 }
12117 }
12118 }
12119 }
12120
12121 app.curRawAdj = adj;
12122
12123 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12124 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12125 if (adj > app.maxAdj) {
12126 adj = app.maxAdj;
12127 }
12128
12129 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012130 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12131 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12132 : Process.THREAD_GROUP_DEFAULT;
12133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012134 return adj;
12135 }
12136
12137 /**
12138 * Ask a given process to GC right now.
12139 */
12140 final void performAppGcLocked(ProcessRecord app) {
12141 try {
12142 app.lastRequestedGc = SystemClock.uptimeMillis();
12143 if (app.thread != null) {
12144 app.thread.processInBackground();
12145 }
12146 } catch (Exception e) {
12147 // whatever.
12148 }
12149 }
12150
12151 /**
12152 * Returns true if things are idle enough to perform GCs.
12153 */
12154 private final boolean canGcNow() {
12155 return mParallelBroadcasts.size() == 0
12156 && mOrderedBroadcasts.size() == 0
12157 && (mSleeping || (mResumedActivity != null &&
12158 mResumedActivity.idle));
12159 }
12160
12161 /**
12162 * Perform GCs on all processes that are waiting for it, but only
12163 * if things are idle.
12164 */
12165 final void performAppGcsLocked() {
12166 final int N = mProcessesToGc.size();
12167 if (N <= 0) {
12168 return;
12169 }
12170 if (canGcNow()) {
12171 while (mProcessesToGc.size() > 0) {
12172 ProcessRecord proc = mProcessesToGc.remove(0);
12173 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12174 // To avoid spamming the system, we will GC processes one
12175 // at a time, waiting a few seconds between each.
12176 performAppGcLocked(proc);
12177 scheduleAppGcsLocked();
12178 return;
12179 }
12180 }
12181 }
12182 }
12183
12184 /**
12185 * If all looks good, perform GCs on all processes waiting for them.
12186 */
12187 final void performAppGcsIfAppropriateLocked() {
12188 if (canGcNow()) {
12189 performAppGcsLocked();
12190 return;
12191 }
12192 // Still not idle, wait some more.
12193 scheduleAppGcsLocked();
12194 }
12195
12196 /**
12197 * Schedule the execution of all pending app GCs.
12198 */
12199 final void scheduleAppGcsLocked() {
12200 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12201 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12202 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12203 }
12204
12205 /**
12206 * Set up to ask a process to GC itself. This will either do it
12207 * immediately, or put it on the list of processes to gc the next
12208 * time things are idle.
12209 */
12210 final void scheduleAppGcLocked(ProcessRecord app) {
12211 long now = SystemClock.uptimeMillis();
12212 if ((app.lastRequestedGc+5000) > now) {
12213 return;
12214 }
12215 if (!mProcessesToGc.contains(app)) {
12216 mProcessesToGc.add(app);
12217 scheduleAppGcsLocked();
12218 }
12219 }
12220
12221 private final boolean updateOomAdjLocked(
12222 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12223 app.hiddenAdj = hiddenAdj;
12224
12225 if (app.thread == null) {
12226 return true;
12227 }
12228
12229 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12230
12231 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12232 //Thread priority adjustment is disabled out to see
12233 //how the kernel scheduler performs.
12234 if (false) {
12235 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12236 app.setIsForeground = app.isForeground;
12237 if (app.pid != MY_PID) {
12238 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12239 + " to " + (app.isForeground
12240 ? Process.THREAD_PRIORITY_FOREGROUND
12241 : Process.THREAD_PRIORITY_DEFAULT));
12242 try {
12243 Process.setThreadPriority(app.pid, app.isForeground
12244 ? Process.THREAD_PRIORITY_FOREGROUND
12245 : Process.THREAD_PRIORITY_DEFAULT);
12246 } catch (RuntimeException e) {
12247 Log.w(TAG, "Exception trying to set priority of application thread "
12248 + app.pid, e);
12249 }
12250 }
12251 }
12252 }
12253 if (app.pid != 0 && app.pid != MY_PID) {
12254 if (app.curRawAdj != app.setRawAdj) {
12255 if (app.curRawAdj > FOREGROUND_APP_ADJ
12256 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12257 // If this app is transitioning from foreground to
12258 // non-foreground, have it do a gc.
12259 scheduleAppGcLocked(app);
12260 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12261 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12262 // Likewise do a gc when an app is moving in to the
12263 // background (such as a service stopping).
12264 scheduleAppGcLocked(app);
12265 }
12266 app.setRawAdj = app.curRawAdj;
12267 }
12268 if (adj != app.setAdj) {
12269 if (Process.setOomAdj(app.pid, adj)) {
12270 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12271 TAG, "Set app " + app.processName +
12272 " oom adj to " + adj);
12273 app.setAdj = adj;
12274 } else {
12275 return false;
12276 }
12277 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012278 if (app.setSchedGroup != app.curSchedGroup) {
12279 app.setSchedGroup = app.curSchedGroup;
12280 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12281 "Setting process group of " + app.processName
12282 + " to " + app.curSchedGroup);
12283 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012284 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012285 try {
12286 Process.setProcessGroup(app.pid, app.curSchedGroup);
12287 } catch (Exception e) {
12288 Log.w(TAG, "Failed setting process group of " + app.pid
12289 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012290 e.printStackTrace();
12291 } finally {
12292 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012293 }
12294 }
12295 if (false) {
12296 if (app.thread != null) {
12297 try {
12298 app.thread.setSchedulingGroup(app.curSchedGroup);
12299 } catch (RemoteException e) {
12300 }
12301 }
12302 }
12303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012304 }
12305
12306 return true;
12307 }
12308
12309 private final HistoryRecord resumedAppLocked() {
12310 HistoryRecord resumedActivity = mResumedActivity;
12311 if (resumedActivity == null || resumedActivity.app == null) {
12312 resumedActivity = mPausingActivity;
12313 if (resumedActivity == null || resumedActivity.app == null) {
12314 resumedActivity = topRunningActivityLocked(null);
12315 }
12316 }
12317 return resumedActivity;
12318 }
12319
12320 private final boolean updateOomAdjLocked(ProcessRecord app) {
12321 final HistoryRecord TOP_ACT = resumedAppLocked();
12322 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12323 int curAdj = app.curAdj;
12324 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12325 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12326
12327 mAdjSeq++;
12328
12329 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12330 if (res) {
12331 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12332 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12333 if (nowHidden != wasHidden) {
12334 // Changed to/from hidden state, so apps after it in the LRU
12335 // list may also be changed.
12336 updateOomAdjLocked();
12337 }
12338 }
12339 return res;
12340 }
12341
12342 private final boolean updateOomAdjLocked() {
12343 boolean didOomAdj = true;
12344 final HistoryRecord TOP_ACT = resumedAppLocked();
12345 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12346
12347 if (false) {
12348 RuntimeException e = new RuntimeException();
12349 e.fillInStackTrace();
12350 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12351 }
12352
12353 mAdjSeq++;
12354
12355 // First try updating the OOM adjustment for each of the
12356 // application processes based on their current state.
12357 int i = mLRUProcesses.size();
12358 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12359 while (i > 0) {
12360 i--;
12361 ProcessRecord app = mLRUProcesses.get(i);
12362 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12363 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12364 && app.curAdj == curHiddenAdj) {
12365 curHiddenAdj++;
12366 }
12367 } else {
12368 didOomAdj = false;
12369 }
12370 }
12371
12372 // todo: for now pretend like OOM ADJ didn't work, because things
12373 // aren't behaving as expected on Linux -- it's not killing processes.
12374 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12375 }
12376
12377 private final void trimApplications() {
12378 synchronized (this) {
12379 int i;
12380
12381 // First remove any unused application processes whose package
12382 // has been removed.
12383 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12384 final ProcessRecord app = mRemovedProcesses.get(i);
12385 if (app.activities.size() == 0
12386 && app.curReceiver == null && app.services.size() == 0) {
12387 Log.i(
12388 TAG, "Exiting empty application process "
12389 + app.processName + " ("
12390 + (app.thread != null ? app.thread.asBinder() : null)
12391 + ")\n");
12392 if (app.pid > 0 && app.pid != MY_PID) {
12393 Process.killProcess(app.pid);
12394 } else {
12395 try {
12396 app.thread.scheduleExit();
12397 } catch (Exception e) {
12398 // Ignore exceptions.
12399 }
12400 }
12401 cleanUpApplicationRecordLocked(app, false, -1);
12402 mRemovedProcesses.remove(i);
12403
12404 if (app.persistent) {
12405 if (app.persistent) {
12406 addAppLocked(app.info);
12407 }
12408 }
12409 }
12410 }
12411
12412 // Now try updating the OOM adjustment for each of the
12413 // application processes based on their current state.
12414 // If the setOomAdj() API is not supported, then go with our
12415 // back-up plan...
12416 if (!updateOomAdjLocked()) {
12417
12418 // Count how many processes are running services.
12419 int numServiceProcs = 0;
12420 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12421 final ProcessRecord app = mLRUProcesses.get(i);
12422
12423 if (app.persistent || app.services.size() != 0
12424 || app.curReceiver != null
12425 || app.persistentActivities > 0) {
12426 // Don't count processes holding services against our
12427 // maximum process count.
12428 if (localLOGV) Log.v(
12429 TAG, "Not trimming app " + app + " with services: "
12430 + app.services);
12431 numServiceProcs++;
12432 }
12433 }
12434
12435 int curMaxProcs = mProcessLimit;
12436 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12437 if (mAlwaysFinishActivities) {
12438 curMaxProcs = 1;
12439 }
12440 curMaxProcs += numServiceProcs;
12441
12442 // Quit as many processes as we can to get down to the desired
12443 // process count. First remove any processes that no longer
12444 // have activites running in them.
12445 for ( i=0;
12446 i<mLRUProcesses.size()
12447 && mLRUProcesses.size() > curMaxProcs;
12448 i++) {
12449 final ProcessRecord app = mLRUProcesses.get(i);
12450 // Quit an application only if it is not currently
12451 // running any activities.
12452 if (!app.persistent && app.activities.size() == 0
12453 && app.curReceiver == null && app.services.size() == 0) {
12454 Log.i(
12455 TAG, "Exiting empty application process "
12456 + app.processName + " ("
12457 + (app.thread != null ? app.thread.asBinder() : null)
12458 + ")\n");
12459 if (app.pid > 0 && app.pid != MY_PID) {
12460 Process.killProcess(app.pid);
12461 } else {
12462 try {
12463 app.thread.scheduleExit();
12464 } catch (Exception e) {
12465 // Ignore exceptions.
12466 }
12467 }
12468 // todo: For now we assume the application is not buggy
12469 // or evil, and will quit as a result of our request.
12470 // Eventually we need to drive this off of the death
12471 // notification, and kill the process if it takes too long.
12472 cleanUpApplicationRecordLocked(app, false, i);
12473 i--;
12474 }
12475 }
12476
12477 // If we still have too many processes, now from the least
12478 // recently used process we start finishing activities.
12479 if (Config.LOGV) Log.v(
12480 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12481 " of " + curMaxProcs + " processes");
12482 for ( i=0;
12483 i<mLRUProcesses.size()
12484 && mLRUProcesses.size() > curMaxProcs;
12485 i++) {
12486 final ProcessRecord app = mLRUProcesses.get(i);
12487 // Quit the application only if we have a state saved for
12488 // all of its activities.
12489 boolean canQuit = !app.persistent && app.curReceiver == null
12490 && app.services.size() == 0
12491 && app.persistentActivities == 0;
12492 int NUMA = app.activities.size();
12493 int j;
12494 if (Config.LOGV) Log.v(
12495 TAG, "Looking to quit " + app.processName);
12496 for (j=0; j<NUMA && canQuit; j++) {
12497 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12498 if (Config.LOGV) Log.v(
12499 TAG, " " + r.intent.getComponent().flattenToShortString()
12500 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12501 canQuit = (r.haveState || !r.stateNotNeeded)
12502 && !r.visible && r.stopped;
12503 }
12504 if (canQuit) {
12505 // Finish all of the activities, and then the app itself.
12506 for (j=0; j<NUMA; j++) {
12507 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12508 if (!r.finishing) {
12509 destroyActivityLocked(r, false);
12510 }
12511 r.resultTo = null;
12512 }
12513 Log.i(TAG, "Exiting application process "
12514 + app.processName + " ("
12515 + (app.thread != null ? app.thread.asBinder() : null)
12516 + ")\n");
12517 if (app.pid > 0 && app.pid != MY_PID) {
12518 Process.killProcess(app.pid);
12519 } else {
12520 try {
12521 app.thread.scheduleExit();
12522 } catch (Exception e) {
12523 // Ignore exceptions.
12524 }
12525 }
12526 // todo: For now we assume the application is not buggy
12527 // or evil, and will quit as a result of our request.
12528 // Eventually we need to drive this off of the death
12529 // notification, and kill the process if it takes too long.
12530 cleanUpApplicationRecordLocked(app, false, i);
12531 i--;
12532 //dump();
12533 }
12534 }
12535
12536 }
12537
12538 int curMaxActivities = MAX_ACTIVITIES;
12539 if (mAlwaysFinishActivities) {
12540 curMaxActivities = 1;
12541 }
12542
12543 // Finally, if there are too many activities now running, try to
12544 // finish as many as we can to get back down to the limit.
12545 for ( i=0;
12546 i<mLRUActivities.size()
12547 && mLRUActivities.size() > curMaxActivities;
12548 i++) {
12549 final HistoryRecord r
12550 = (HistoryRecord)mLRUActivities.get(i);
12551
12552 // We can finish this one if we have its icicle saved and
12553 // it is not persistent.
12554 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12555 && r.stopped && !r.persistent && !r.finishing) {
12556 final int origSize = mLRUActivities.size();
12557 destroyActivityLocked(r, true);
12558
12559 // This will remove it from the LRU list, so keep
12560 // our index at the same value. Note that this check to
12561 // see if the size changes is just paranoia -- if
12562 // something unexpected happens, we don't want to end up
12563 // in an infinite loop.
12564 if (origSize > mLRUActivities.size()) {
12565 i--;
12566 }
12567 }
12568 }
12569 }
12570 }
12571
12572 /** This method sends the specified signal to each of the persistent apps */
12573 public void signalPersistentProcesses(int sig) throws RemoteException {
12574 if (sig != Process.SIGNAL_USR1) {
12575 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12576 }
12577
12578 synchronized (this) {
12579 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12580 != PackageManager.PERMISSION_GRANTED) {
12581 throw new SecurityException("Requires permission "
12582 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12583 }
12584
12585 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12586 ProcessRecord r = mLRUProcesses.get(i);
12587 if (r.thread != null && r.persistent) {
12588 Process.sendSignal(r.pid, sig);
12589 }
12590 }
12591 }
12592 }
12593
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012594 public boolean profileControl(String process, boolean start,
12595 String path) throws RemoteException {
12596
12597 synchronized (this) {
12598 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12599 // its own permission.
12600 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12601 != PackageManager.PERMISSION_GRANTED) {
12602 throw new SecurityException("Requires permission "
12603 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12604 }
12605
12606 ProcessRecord proc = null;
12607 try {
12608 int pid = Integer.parseInt(process);
12609 synchronized (mPidsSelfLocked) {
12610 proc = mPidsSelfLocked.get(pid);
12611 }
12612 } catch (NumberFormatException e) {
12613 }
12614
12615 if (proc == null) {
12616 HashMap<String, SparseArray<ProcessRecord>> all
12617 = mProcessNames.getMap();
12618 SparseArray<ProcessRecord> procs = all.get(process);
12619 if (procs != null && procs.size() > 0) {
12620 proc = procs.valueAt(0);
12621 }
12622 }
12623
12624 if (proc == null || proc.thread == null) {
12625 throw new IllegalArgumentException("Unknown process: " + process);
12626 }
12627
12628 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12629 if (isSecure) {
12630 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12631 throw new SecurityException("Process not debuggable: " + proc);
12632 }
12633 }
12634
12635 try {
12636 proc.thread.profilerControl(start, path);
12637 return true;
12638 } catch (RemoteException e) {
12639 throw new IllegalStateException("Process disappeared");
12640 }
12641 }
12642 }
12643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012644 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12645 public void monitor() {
12646 synchronized (this) { }
12647 }
12648}