blob: fd37cc2f4fd093238b0c553012ccc3e16b19c325 [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;
20import com.android.internal.os.RuntimeInit;
21import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
33import android.app.Dialog;
34import android.app.IActivityWatcher;
35import android.app.IApplicationThread;
36import android.app.IInstrumentationWatcher;
37import android.app.IIntentReceiver;
38import android.app.IIntentSender;
39import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
44import android.content.ComponentName;
45import android.content.ContentResolver;
46import android.content.Context;
47import android.content.Intent;
48import android.content.IntentFilter;
49import android.content.pm.ActivityInfo;
50import android.content.pm.ApplicationInfo;
51import android.content.pm.ConfigurationInfo;
52import android.content.pm.IPackageDataObserver;
53import android.content.pm.IPackageManager;
54import android.content.pm.InstrumentationInfo;
55import android.content.pm.PackageManager;
56import android.content.pm.ProviderInfo;
57import android.content.pm.ResolveInfo;
58import android.content.pm.ServiceInfo;
59import android.content.res.Configuration;
60import android.graphics.Bitmap;
61import android.net.Uri;
62import android.os.Binder;
63import android.os.Bundle;
64import android.os.Environment;
65import android.os.FileUtils;
66import android.os.Handler;
67import android.os.IBinder;
68import android.os.IPermissionController;
69import android.os.Looper;
70import android.os.Message;
71import android.os.Parcel;
72import android.os.ParcelFileDescriptor;
73import android.os.PowerManager;
74import android.os.Process;
75import android.os.RemoteException;
76import android.os.ServiceManager;
77import android.os.SystemClock;
78import android.os.SystemProperties;
79import android.provider.Checkin;
80import android.provider.Settings;
81import android.text.TextUtils;
82import android.util.Config;
83import android.util.EventLog;
84import android.util.Log;
85import android.util.PrintWriterPrinter;
86import android.util.SparseArray;
87import android.view.Gravity;
88import android.view.LayoutInflater;
89import android.view.View;
90import android.view.WindowManager;
91import android.view.WindowManagerPolicy;
92
93import dalvik.system.Zygote;
94
95import java.io.File;
96import java.io.FileDescriptor;
97import java.io.FileInputStream;
98import java.io.FileNotFoundException;
99import java.io.PrintWriter;
100import java.lang.IllegalStateException;
101import java.lang.ref.WeakReference;
102import java.util.ArrayList;
103import java.util.HashMap;
104import java.util.HashSet;
105import java.util.Iterator;
106import java.util.List;
107import java.util.Locale;
108import java.util.Map;
109
110public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
111 static final String TAG = "ActivityManager";
112 static final boolean DEBUG = false;
113 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
114 static final boolean DEBUG_SWITCH = localLOGV || false;
115 static final boolean DEBUG_TASKS = localLOGV || false;
116 static final boolean DEBUG_PAUSE = localLOGV || false;
117 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
118 static final boolean DEBUG_TRANSITION = localLOGV || false;
119 static final boolean DEBUG_BROADCAST = localLOGV || false;
120 static final boolean DEBUG_SERVICE = localLOGV || false;
121 static final boolean DEBUG_VISBILITY = localLOGV || false;
122 static final boolean DEBUG_PROCESSES = localLOGV || false;
123 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700124 static final boolean DEBUG_RESULTS = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 static final boolean VALIDATE_TOKENS = false;
126 static final boolean SHOW_ACTIVITY_START_TIME = true;
127
128 // Control over CPU and battery monitoring.
129 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
130 static final boolean MONITOR_CPU_USAGE = true;
131 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
132 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
133 static final boolean MONITOR_THREAD_CPU_USAGE = false;
134
135 // Event log tags
136 static final int LOG_CONFIGURATION_CHANGED = 2719;
137 static final int LOG_CPU = 2721;
138 static final int LOG_AM_FINISH_ACTIVITY = 30001;
139 static final int LOG_TASK_TO_FRONT = 30002;
140 static final int LOG_AM_NEW_INTENT = 30003;
141 static final int LOG_AM_CREATE_TASK = 30004;
142 static final int LOG_AM_CREATE_ACTIVITY = 30005;
143 static final int LOG_AM_RESTART_ACTIVITY = 30006;
144 static final int LOG_AM_RESUME_ACTIVITY = 30007;
145 static final int LOG_ANR = 30008;
146 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
147 static final int LOG_AM_PROCESS_BOUND = 30010;
148 static final int LOG_AM_PROCESS_DIED = 30011;
149 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
150 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
151 static final int LOG_AM_PROCESS_START = 30014;
152 static final int LOG_AM_PROCESS_BAD = 30015;
153 static final int LOG_AM_PROCESS_GOOD = 30016;
154 static final int LOG_AM_LOW_MEMORY = 30017;
155 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
156 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
157 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
158 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
159 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
160 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
161 static final int LOG_AM_CREATE_SERVICE = 30030;
162 static final int LOG_AM_DESTROY_SERVICE = 30031;
163 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
164 static final int LOG_AM_DROP_PROCESS = 30033;
165 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
166 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
167 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
168
169 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
170 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
171
Dianne Hackborn1655be42009-05-08 14:29:01 -0700172 // The flags that are set for all calls we make to the package manager.
173 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
174 | PackageManager.GET_SUPPORTS_DENSITIES;
175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 private static final String SYSTEM_SECURE = "ro.secure";
177
178 // This is the maximum number of application processes we would like
179 // to have running. Due to the asynchronous nature of things, we can
180 // temporarily go beyond this limit.
181 static final int MAX_PROCESSES = 2;
182
183 // Set to false to leave processes running indefinitely, relying on
184 // the kernel killing them as resources are required.
185 static final boolean ENFORCE_PROCESS_LIMIT = false;
186
187 // This is the maximum number of activities that we would like to have
188 // running at a given time.
189 static final int MAX_ACTIVITIES = 20;
190
191 // Maximum number of recent tasks that we can remember.
192 static final int MAX_RECENT_TASKS = 20;
193
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700194 // Amount of time after a call to stopAppSwitches() during which we will
195 // prevent further untrusted switches from happening.
196 static final long APP_SWITCH_DELAY_TIME = 5*1000;
197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 // How long until we reset a task when the user returns to it. Currently
199 // 30 minutes.
200 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
201
202 // Set to true to disable the icon that is shown while a new activity
203 // is being started.
204 static final boolean SHOW_APP_STARTING_ICON = true;
205
206 // How long we wait until giving up on the last activity to pause. This
207 // is short because it directly impacts the responsiveness of starting the
208 // next activity.
209 static final int PAUSE_TIMEOUT = 500;
210
211 /**
212 * How long we can hold the launch wake lock before giving up.
213 */
214 static final int LAUNCH_TIMEOUT = 10*1000;
215
216 // How long we wait for a launched process to attach to the activity manager
217 // before we decide it's never going to come up for real.
218 static final int PROC_START_TIMEOUT = 10*1000;
219
220 // How long we wait until giving up on the last activity telling us it
221 // is idle.
222 static final int IDLE_TIMEOUT = 10*1000;
223
224 // How long to wait after going idle before forcing apps to GC.
225 static final int GC_TIMEOUT = 5*1000;
226
227 // How long we wait until giving up on an activity telling us it has
228 // finished destroying itself.
229 static final int DESTROY_TIMEOUT = 10*1000;
230
231 // How long we allow a receiver to run before giving up on it.
232 static final int BROADCAST_TIMEOUT = 10*1000;
233
234 // How long we wait for a service to finish executing.
235 static final int SERVICE_TIMEOUT = 20*1000;
236
237 // How long a service needs to be running until restarting its process
238 // is no longer considered to be a relaunch of the service.
239 static final int SERVICE_RESTART_DURATION = 5*1000;
240
241 // Maximum amount of time for there to be no activity on a service before
242 // we consider it non-essential and allow its process to go on the
243 // LRU background list.
244 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
245
246 // How long we wait until we timeout on key dispatching.
247 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
248
249 // The minimum time we allow between crashes, for us to consider this
250 // application to be bad and stop and its services and reject broadcasts.
251 static final int MIN_CRASH_INTERVAL = 60*1000;
252
253 // How long we wait until we timeout on key dispatching during instrumentation.
254 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
255
256 // OOM adjustments for processes in various states:
257
258 // This is a process without anything currently running in it. Definitely
259 // the first to go! Value set in system/rootdir/init.rc on startup.
260 // This value is initalized in the constructor, careful when refering to
261 // this static variable externally.
262 static int EMPTY_APP_ADJ;
263
264 // This is a process with a content provider that does not have any clients
265 // attached to it. If it did have any clients, its adjustment would be the
266 // one for the highest-priority of those processes.
267 static int CONTENT_PROVIDER_ADJ;
268
269 // This is a process only hosting activities that are not visible,
270 // so it can be killed without any disruption. Value set in
271 // system/rootdir/init.rc on startup.
272 final int HIDDEN_APP_MAX_ADJ;
273 static int HIDDEN_APP_MIN_ADJ;
274
The Android Open Source Project4df24232009-03-05 14:34:35 -0800275 // This is a process holding the home application -- we want to try
276 // avoiding killing it, even if it would normally be in the background,
277 // because the user interacts with it so much.
278 final int HOME_APP_ADJ;
279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 // This is a process holding a secondary server -- killing it will not
281 // have much of an impact as far as the user is concerned. Value set in
282 // system/rootdir/init.rc on startup.
283 final int SECONDARY_SERVER_ADJ;
284
285 // This is a process only hosting activities that are visible to the
286 // user, so we'd prefer they don't disappear. Value set in
287 // system/rootdir/init.rc on startup.
288 final int VISIBLE_APP_ADJ;
289
290 // This is the process running the current foreground app. We'd really
291 // rather not kill it! Value set in system/rootdir/init.rc on startup.
292 final int FOREGROUND_APP_ADJ;
293
294 // This is a process running a core server, such as telephony. Definitely
295 // don't want to kill it, but doing so is not completely fatal.
296 static final int CORE_SERVER_ADJ = -12;
297
298 // The system process runs at the default adjustment.
299 static final int SYSTEM_ADJ = -16;
300
301 // Memory pages are 4K.
302 static final int PAGE_SIZE = 4*1024;
303
304 // Corresponding memory levels for above adjustments.
305 final int EMPTY_APP_MEM;
306 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800307 final int HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 final int SECONDARY_SERVER_MEM;
309 final int VISIBLE_APP_MEM;
310 final int FOREGROUND_APP_MEM;
311
312 final int MY_PID;
313
314 static final String[] EMPTY_STRING_ARRAY = new String[0];
315
316 enum ActivityState {
317 INITIALIZING,
318 RESUMED,
319 PAUSING,
320 PAUSED,
321 STOPPING,
322 STOPPED,
323 FINISHING,
324 DESTROYING,
325 DESTROYED
326 }
327
328 /**
329 * The back history of all previous (and possibly still
330 * running) activities. It contains HistoryRecord objects.
331 */
332 final ArrayList mHistory = new ArrayList();
333
334 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700335 * Description of a request to start a new activity, which has been held
336 * due to app switches being disabled.
337 */
338 class PendingActivityLaunch {
339 HistoryRecord r;
340 HistoryRecord sourceRecord;
341 Uri[] grantedUriPermissions;
342 int grantedMode;
343 boolean onlyIfNeeded;
344 }
345
346 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
347 = new ArrayList<PendingActivityLaunch>();
348
349 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 * List of all active broadcasts that are to be executed immediately
351 * (without waiting for another broadcast to finish). Currently this only
352 * contains broadcasts to registered receivers, to avoid spinning up
353 * a bunch of processes to execute IntentReceiver components.
354 */
355 final ArrayList<BroadcastRecord> mParallelBroadcasts
356 = new ArrayList<BroadcastRecord>();
357
358 /**
359 * List of all active broadcasts that are to be executed one at a time.
360 * The object at the top of the list is the currently activity broadcasts;
361 * those after it are waiting for the top to finish..
362 */
363 final ArrayList<BroadcastRecord> mOrderedBroadcasts
364 = new ArrayList<BroadcastRecord>();
365
366 /**
367 * Set when we current have a BROADCAST_INTENT_MSG in flight.
368 */
369 boolean mBroadcastsScheduled = false;
370
371 /**
372 * Set to indicate whether to issue an onUserLeaving callback when a
373 * newly launched activity is being brought in front of us.
374 */
375 boolean mUserLeaving = false;
376
377 /**
378 * When we are in the process of pausing an activity, before starting the
379 * next one, this variable holds the activity that is currently being paused.
380 */
381 HistoryRecord mPausingActivity = null;
382
383 /**
384 * Current activity that is resumed, or null if there is none.
385 */
386 HistoryRecord mResumedActivity = null;
387
388 /**
389 * Activity we have told the window manager to have key focus.
390 */
391 HistoryRecord mFocusedActivity = null;
392
393 /**
394 * This is the last activity that we put into the paused state. This is
395 * used to determine if we need to do an activity transition while sleeping,
396 * when we normally hold the top activity paused.
397 */
398 HistoryRecord mLastPausedActivity = null;
399
400 /**
401 * List of activities that are waiting for a new activity
402 * to become visible before completing whatever operation they are
403 * supposed to do.
404 */
405 final ArrayList mWaitingVisibleActivities = new ArrayList();
406
407 /**
408 * List of activities that are ready to be stopped, but waiting
409 * for the next activity to settle down before doing so. It contains
410 * HistoryRecord objects.
411 */
412 final ArrayList<HistoryRecord> mStoppingActivities
413 = new ArrayList<HistoryRecord>();
414
415 /**
416 * List of intents that were used to start the most recent tasks.
417 */
418 final ArrayList<TaskRecord> mRecentTasks
419 = new ArrayList<TaskRecord>();
420
421 /**
422 * List of activities that are ready to be finished, but waiting
423 * for the previous activity to settle down before doing so. It contains
424 * HistoryRecord objects.
425 */
426 final ArrayList mFinishingActivities = new ArrayList();
427
428 /**
429 * All of the applications we currently have running organized by name.
430 * The keys are strings of the application package name (as
431 * returned by the package manager), and the keys are ApplicationRecord
432 * objects.
433 */
434 final ProcessMap<ProcessRecord> mProcessNames
435 = new ProcessMap<ProcessRecord>();
436
437 /**
438 * The last time that various processes have crashed.
439 */
440 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
441
442 /**
443 * Set of applications that we consider to be bad, and will reject
444 * incoming broadcasts from (which the user has no control over).
445 * Processes are added to this set when they have crashed twice within
446 * a minimum amount of time; they are removed from it when they are
447 * later restarted (hopefully due to some user action). The value is the
448 * time it was added to the list.
449 */
450 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
451
452 /**
453 * All of the processes we currently have running organized by pid.
454 * The keys are the pid running the application.
455 *
456 * <p>NOTE: This object is protected by its own lock, NOT the global
457 * activity manager lock!
458 */
459 final SparseArray<ProcessRecord> mPidsSelfLocked
460 = new SparseArray<ProcessRecord>();
461
462 /**
463 * All of the processes that have been forced to be foreground. The key
464 * is the pid of the caller who requested it (we hold a death
465 * link on it).
466 */
467 abstract class ForegroundToken implements IBinder.DeathRecipient {
468 int pid;
469 IBinder token;
470 }
471 final SparseArray<ForegroundToken> mForegroundProcesses
472 = new SparseArray<ForegroundToken>();
473
474 /**
475 * List of records for processes that someone had tried to start before the
476 * system was ready. We don't start them at that point, but ensure they
477 * are started by the time booting is complete.
478 */
479 final ArrayList<ProcessRecord> mProcessesOnHold
480 = new ArrayList<ProcessRecord>();
481
482 /**
483 * List of records for processes that we have started and are waiting
484 * for them to call back. This is really only needed when running in
485 * single processes mode, in which case we do not have a unique pid for
486 * each process.
487 */
488 final ArrayList<ProcessRecord> mStartingProcesses
489 = new ArrayList<ProcessRecord>();
490
491 /**
492 * List of persistent applications that are in the process
493 * of being started.
494 */
495 final ArrayList<ProcessRecord> mPersistentStartingProcesses
496 = new ArrayList<ProcessRecord>();
497
498 /**
499 * Processes that are being forcibly torn down.
500 */
501 final ArrayList<ProcessRecord> mRemovedProcesses
502 = new ArrayList<ProcessRecord>();
503
504 /**
505 * List of running applications, sorted by recent usage.
506 * The first entry in the list is the least recently used.
507 * It contains ApplicationRecord objects. This list does NOT include
508 * any persistent application records (since we never want to exit them).
509 */
510 final ArrayList<ProcessRecord> mLRUProcesses
511 = new ArrayList<ProcessRecord>();
512
513 /**
514 * List of processes that should gc as soon as things are idle.
515 */
516 final ArrayList<ProcessRecord> mProcessesToGc
517 = new ArrayList<ProcessRecord>();
518
519 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800520 * This is the process holding what we currently consider to be
521 * the "home" activity.
522 */
523 private ProcessRecord mHomeProcess;
524
525 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 * List of running activities, sorted by recent usage.
527 * The first entry in the list is the least recently used.
528 * It contains HistoryRecord objects.
529 */
530 private final ArrayList mLRUActivities = new ArrayList();
531
532 /**
533 * Set of PendingResultRecord objects that are currently active.
534 */
535 final HashSet mPendingResultRecords = new HashSet();
536
537 /**
538 * Set of IntentSenderRecord objects that are currently active.
539 */
540 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
541 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
542
543 /**
544 * Intent broadcast that we have tried to start, but are
545 * waiting for its application's process to be created. We only
546 * need one (instead of a list) because we always process broadcasts
547 * one at a time, so no others can be started while waiting for this
548 * one.
549 */
550 BroadcastRecord mPendingBroadcast = null;
551
552 /**
553 * Keeps track of all IIntentReceivers that have been registered for
554 * broadcasts. Hash keys are the receiver IBinder, hash value is
555 * a ReceiverList.
556 */
557 final HashMap mRegisteredReceivers = new HashMap();
558
559 /**
560 * Resolver for broadcast intents to registered receivers.
561 * Holds BroadcastFilter (subclass of IntentFilter).
562 */
563 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
564 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
565 @Override
566 protected boolean allowFilterResult(
567 BroadcastFilter filter, List<BroadcastFilter> dest) {
568 IBinder target = filter.receiverList.receiver.asBinder();
569 for (int i=dest.size()-1; i>=0; i--) {
570 if (dest.get(i).receiverList.receiver.asBinder() == target) {
571 return false;
572 }
573 }
574 return true;
575 }
576 };
577
578 /**
579 * State of all active sticky broadcasts. Keys are the action of the
580 * sticky Intent, values are an ArrayList of all broadcasted intents with
581 * that action (which should usually be one).
582 */
583 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
584 new HashMap<String, ArrayList<Intent>>();
585
586 /**
587 * All currently running services.
588 */
589 final HashMap<ComponentName, ServiceRecord> mServices =
590 new HashMap<ComponentName, ServiceRecord>();
591
592 /**
593 * All currently running services indexed by the Intent used to start them.
594 */
595 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
596 new HashMap<Intent.FilterComparison, ServiceRecord>();
597
598 /**
599 * All currently bound service connections. Keys are the IBinder of
600 * the client's IServiceConnection.
601 */
602 final HashMap<IBinder, ConnectionRecord> mServiceConnections
603 = new HashMap<IBinder, ConnectionRecord>();
604
605 /**
606 * List of services that we have been asked to start,
607 * but haven't yet been able to. It is used to hold start requests
608 * while waiting for their corresponding application thread to get
609 * going.
610 */
611 final ArrayList<ServiceRecord> mPendingServices
612 = new ArrayList<ServiceRecord>();
613
614 /**
615 * List of services that are scheduled to restart following a crash.
616 */
617 final ArrayList<ServiceRecord> mRestartingServices
618 = new ArrayList<ServiceRecord>();
619
620 /**
621 * List of services that are in the process of being stopped.
622 */
623 final ArrayList<ServiceRecord> mStoppingServices
624 = new ArrayList<ServiceRecord>();
625
626 /**
627 * List of PendingThumbnailsRecord objects of clients who are still
628 * waiting to receive all of the thumbnails for a task.
629 */
630 final ArrayList mPendingThumbnails = new ArrayList();
631
632 /**
633 * List of HistoryRecord objects that have been finished and must
634 * still report back to a pending thumbnail receiver.
635 */
636 final ArrayList mCancelledThumbnails = new ArrayList();
637
638 /**
639 * All of the currently running global content providers. Keys are a
640 * string containing the provider name and values are a
641 * ContentProviderRecord object containing the data about it. Note
642 * that a single provider may be published under multiple names, so
643 * there may be multiple entries here for a single one in mProvidersByClass.
644 */
645 final HashMap mProvidersByName = new HashMap();
646
647 /**
648 * All of the currently running global content providers. Keys are a
649 * string containing the provider's implementation class and values are a
650 * ContentProviderRecord object containing the data about it.
651 */
652 final HashMap mProvidersByClass = new HashMap();
653
654 /**
655 * List of content providers who have clients waiting for them. The
656 * application is currently being launched and the provider will be
657 * removed from this list once it is published.
658 */
659 final ArrayList mLaunchingProviders = new ArrayList();
660
661 /**
662 * Global set of specific Uri permissions that have been granted.
663 */
664 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
665 = new SparseArray<HashMap<Uri, UriPermission>>();
666
667 /**
668 * Thread-local storage used to carry caller permissions over through
669 * indirect content-provider access.
670 * @see #ActivityManagerService.openContentUri()
671 */
672 private class Identity {
673 public int pid;
674 public int uid;
675
676 Identity(int _pid, int _uid) {
677 pid = _pid;
678 uid = _uid;
679 }
680 }
681 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
682
683 /**
684 * All information we have collected about the runtime performance of
685 * any user id that can impact battery performance.
686 */
687 final BatteryStatsService mBatteryStatsService;
688
689 /**
690 * information about component usage
691 */
692 final UsageStatsService mUsageStatsService;
693
694 /**
695 * Current configuration information. HistoryRecord objects are given
696 * a reference to this object to indicate which configuration they are
697 * currently running in, so this object must be kept immutable.
698 */
699 Configuration mConfiguration = new Configuration();
700
701 /**
702 * List of initialization arguments to pass to all processes when binding applications to them.
703 * For example, references to the commonly used services.
704 */
705 HashMap<String, IBinder> mAppBindArgs;
706
707 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700708 * Temporary to avoid allocations. Protected by main lock.
709 */
710 final StringBuilder mStringBuilder = new StringBuilder(256);
711
712 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 * Used to control how we initialize the service.
714 */
715 boolean mStartRunning = false;
716 ComponentName mTopComponent;
717 String mTopAction;
718 String mTopData;
719 boolean mSystemReady = false;
720 boolean mBooting = false;
721
722 Context mContext;
723
724 int mFactoryTest;
725
726 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700727 * The time at which we will allow normal application switches again,
728 * after a call to {@link #stopAppSwitches()}.
729 */
730 long mAppSwitchesAllowedTime;
731
732 /**
733 * This is set to true after the first switch after mAppSwitchesAllowedTime
734 * is set; any switches after that will clear the time.
735 */
736 boolean mDidAppSwitch;
737
738 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 * Set while we are wanting to sleep, to prevent any
740 * activities from being started/resumed.
741 */
742 boolean mSleeping = false;
743
744 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700745 * Set if we are shutting down the system, similar to sleeping.
746 */
747 boolean mShuttingDown = false;
748
749 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 * Set when the system is going to sleep, until we have
751 * successfully paused the current activity and released our wake lock.
752 * At that point the system is allowed to actually sleep.
753 */
754 PowerManager.WakeLock mGoingToSleep;
755
756 /**
757 * We don't want to allow the device to go to sleep while in the process
758 * of launching an activity. This is primarily to allow alarm intent
759 * receivers to launch an activity and get that to run before the device
760 * goes back to sleep.
761 */
762 PowerManager.WakeLock mLaunchingActivity;
763
764 /**
765 * Task identifier that activities are currently being started
766 * in. Incremented each time a new task is created.
767 * todo: Replace this with a TokenSpace class that generates non-repeating
768 * integers that won't wrap.
769 */
770 int mCurTask = 1;
771
772 /**
773 * Current sequence id for oom_adj computation traversal.
774 */
775 int mAdjSeq = 0;
776
777 /**
778 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
779 * is set, indicating the user wants processes started in such a way
780 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
781 * running in each process (thus no pre-initialized process, etc).
782 */
783 boolean mSimpleProcessManagement = false;
784
785 /**
786 * System monitoring: number of processes that died since the last
787 * N procs were started.
788 */
789 int[] mProcDeaths = new int[20];
790
791 String mDebugApp = null;
792 boolean mWaitForDebugger = false;
793 boolean mDebugTransient = false;
794 String mOrigDebugApp = null;
795 boolean mOrigWaitForDebugger = false;
796 boolean mAlwaysFinishActivities = false;
797 IActivityWatcher mWatcher = null;
798
799 /**
800 * Callback of last caller to {@link #requestPss}.
801 */
802 Runnable mRequestPssCallback;
803
804 /**
805 * Remaining processes for which we are waiting results from the last
806 * call to {@link #requestPss}.
807 */
808 final ArrayList<ProcessRecord> mRequestPssList
809 = new ArrayList<ProcessRecord>();
810
811 /**
812 * Runtime statistics collection thread. This object's lock is used to
813 * protect all related state.
814 */
815 final Thread mProcessStatsThread;
816
817 /**
818 * Used to collect process stats when showing not responding dialog.
819 * Protected by mProcessStatsThread.
820 */
821 final ProcessStats mProcessStats = new ProcessStats(
822 MONITOR_THREAD_CPU_USAGE);
823 long mLastCpuTime = 0;
824 long mLastWriteTime = 0;
825
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700826 long mInitialStartTime = 0;
827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 /**
829 * Set to true after the system has finished booting.
830 */
831 boolean mBooted = false;
832
833 int mProcessLimit = 0;
834
835 WindowManagerService mWindowManager;
836
837 static ActivityManagerService mSelf;
838 static ActivityThread mSystemThread;
839
840 private final class AppDeathRecipient implements IBinder.DeathRecipient {
841 final ProcessRecord mApp;
842 final int mPid;
843 final IApplicationThread mAppThread;
844
845 AppDeathRecipient(ProcessRecord app, int pid,
846 IApplicationThread thread) {
847 if (localLOGV) Log.v(
848 TAG, "New death recipient " + this
849 + " for thread " + thread.asBinder());
850 mApp = app;
851 mPid = pid;
852 mAppThread = thread;
853 }
854
855 public void binderDied() {
856 if (localLOGV) Log.v(
857 TAG, "Death received in " + this
858 + " for thread " + mAppThread.asBinder());
859 removeRequestedPss(mApp);
860 synchronized(ActivityManagerService.this) {
861 appDiedLocked(mApp, mPid, mAppThread);
862 }
863 }
864 }
865
866 static final int SHOW_ERROR_MSG = 1;
867 static final int SHOW_NOT_RESPONDING_MSG = 2;
868 static final int SHOW_FACTORY_ERROR_MSG = 3;
869 static final int UPDATE_CONFIGURATION_MSG = 4;
870 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
871 static final int WAIT_FOR_DEBUGGER_MSG = 6;
872 static final int BROADCAST_INTENT_MSG = 7;
873 static final int BROADCAST_TIMEOUT_MSG = 8;
874 static final int PAUSE_TIMEOUT_MSG = 9;
875 static final int IDLE_TIMEOUT_MSG = 10;
876 static final int IDLE_NOW_MSG = 11;
877 static final int SERVICE_TIMEOUT_MSG = 12;
878 static final int UPDATE_TIME_ZONE = 13;
879 static final int SHOW_UID_ERROR_MSG = 14;
880 static final int IM_FEELING_LUCKY_MSG = 15;
881 static final int LAUNCH_TIMEOUT_MSG = 16;
882 static final int DESTROY_TIMEOUT_MSG = 17;
883 static final int SERVICE_ERROR_MSG = 18;
884 static final int RESUME_TOP_ACTIVITY_MSG = 19;
885 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700886 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887
888 AlertDialog mUidAlert;
889
890 final Handler mHandler = new Handler() {
891 //public Handler() {
892 // if (localLOGV) Log.v(TAG, "Handler started!");
893 //}
894
895 public void handleMessage(Message msg) {
896 switch (msg.what) {
897 case SHOW_ERROR_MSG: {
898 HashMap data = (HashMap) msg.obj;
899 byte[] crashData = (byte[])data.get("crashData");
900 if (crashData != null) {
901 // This needs to be *un*synchronized to avoid deadlock.
902 ContentResolver resolver = mContext.getContentResolver();
903 Checkin.reportCrash(resolver, crashData);
904 }
905 synchronized (ActivityManagerService.this) {
906 ProcessRecord proc = (ProcessRecord)data.get("app");
907 if (proc != null && proc.crashDialog != null) {
908 Log.e(TAG, "App already has crash dialog: " + proc);
909 return;
910 }
911 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700912 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 Dialog d = new AppErrorDialog(
914 mContext, res, proc,
915 (Integer)data.get("flags"),
916 (String)data.get("shortMsg"),
917 (String)data.get("longMsg"));
918 d.show();
919 proc.crashDialog = d;
920 } else {
921 // The device is asleep, so just pretend that the user
922 // saw a crash dialog and hit "force quit".
923 res.set(0);
924 }
925 }
926 } break;
927 case SHOW_NOT_RESPONDING_MSG: {
928 synchronized (ActivityManagerService.this) {
929 HashMap data = (HashMap) msg.obj;
930 ProcessRecord proc = (ProcessRecord)data.get("app");
931 if (proc != null && proc.anrDialog != null) {
932 Log.e(TAG, "App already has anr dialog: " + proc);
933 return;
934 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800935
936 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
937 null, null, 0, null, null, null,
938 false, false, MY_PID, Process.SYSTEM_UID);
939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
941 mContext, proc, (HistoryRecord)data.get("activity"));
942 d.show();
943 proc.anrDialog = d;
944 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700945
946 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 } break;
948 case SHOW_FACTORY_ERROR_MSG: {
949 Dialog d = new FactoryErrorDialog(
950 mContext, msg.getData().getCharSequence("msg"));
951 d.show();
952 enableScreenAfterBoot();
953 } break;
954 case UPDATE_CONFIGURATION_MSG: {
955 final ContentResolver resolver = mContext.getContentResolver();
956 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
957 } break;
958 case GC_BACKGROUND_PROCESSES_MSG: {
959 synchronized (ActivityManagerService.this) {
960 performAppGcsIfAppropriateLocked();
961 }
962 } break;
963 case WAIT_FOR_DEBUGGER_MSG: {
964 synchronized (ActivityManagerService.this) {
965 ProcessRecord app = (ProcessRecord)msg.obj;
966 if (msg.arg1 != 0) {
967 if (!app.waitedForDebugger) {
968 Dialog d = new AppWaitingForDebuggerDialog(
969 ActivityManagerService.this,
970 mContext, app);
971 app.waitDialog = d;
972 app.waitedForDebugger = true;
973 d.show();
974 }
975 } else {
976 if (app.waitDialog != null) {
977 app.waitDialog.dismiss();
978 app.waitDialog = null;
979 }
980 }
981 }
982 } break;
983 case BROADCAST_INTENT_MSG: {
984 if (DEBUG_BROADCAST) Log.v(
985 TAG, "Received BROADCAST_INTENT_MSG");
986 processNextBroadcast(true);
987 } break;
988 case BROADCAST_TIMEOUT_MSG: {
989 broadcastTimeout();
990 } break;
991 case PAUSE_TIMEOUT_MSG: {
992 IBinder token = (IBinder)msg.obj;
993 // We don't at this point know if the activity is fullscreen,
994 // so we need to be conservative and assume it isn't.
995 Log.w(TAG, "Activity pause timeout for " + token);
996 activityPaused(token, null, true);
997 } break;
998 case IDLE_TIMEOUT_MSG: {
999 IBinder token = (IBinder)msg.obj;
1000 // We don't at this point know if the activity is fullscreen,
1001 // so we need to be conservative and assume it isn't.
1002 Log.w(TAG, "Activity idle timeout for " + token);
1003 activityIdleInternal(token, true);
1004 } break;
1005 case DESTROY_TIMEOUT_MSG: {
1006 IBinder token = (IBinder)msg.obj;
1007 // We don't at this point know if the activity is fullscreen,
1008 // so we need to be conservative and assume it isn't.
1009 Log.w(TAG, "Activity destroy timeout for " + token);
1010 activityDestroyed(token);
1011 } break;
1012 case IDLE_NOW_MSG: {
1013 IBinder token = (IBinder)msg.obj;
1014 activityIdle(token);
1015 } break;
1016 case SERVICE_TIMEOUT_MSG: {
1017 serviceTimeout((ProcessRecord)msg.obj);
1018 } break;
1019 case UPDATE_TIME_ZONE: {
1020 synchronized (ActivityManagerService.this) {
1021 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1022 ProcessRecord r = mLRUProcesses.get(i);
1023 if (r.thread != null) {
1024 try {
1025 r.thread.updateTimeZone();
1026 } catch (RemoteException ex) {
1027 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1028 }
1029 }
1030 }
1031 }
1032 break;
1033 }
1034 case SHOW_UID_ERROR_MSG: {
1035 // XXX This is a temporary dialog, no need to localize.
1036 AlertDialog d = new BaseErrorDialog(mContext);
1037 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1038 d.setCancelable(false);
1039 d.setTitle("System UIDs Inconsistent");
1040 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1041 d.setButton("I'm Feeling Lucky",
1042 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1043 mUidAlert = d;
1044 d.show();
1045 } break;
1046 case IM_FEELING_LUCKY_MSG: {
1047 if (mUidAlert != null) {
1048 mUidAlert.dismiss();
1049 mUidAlert = null;
1050 }
1051 } break;
1052 case LAUNCH_TIMEOUT_MSG: {
1053 synchronized (ActivityManagerService.this) {
1054 if (mLaunchingActivity.isHeld()) {
1055 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1056 mLaunchingActivity.release();
1057 }
1058 }
1059 } break;
1060 case SERVICE_ERROR_MSG: {
1061 ServiceRecord srv = (ServiceRecord)msg.obj;
1062 // This needs to be *un*synchronized to avoid deadlock.
1063 Checkin.logEvent(mContext.getContentResolver(),
1064 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1065 srv.name.toShortString());
1066 } break;
1067 case RESUME_TOP_ACTIVITY_MSG: {
1068 synchronized (ActivityManagerService.this) {
1069 resumeTopActivityLocked(null);
1070 }
1071 }
1072 case PROC_START_TIMEOUT_MSG: {
1073 ProcessRecord app = (ProcessRecord)msg.obj;
1074 synchronized (ActivityManagerService.this) {
1075 processStartTimedOutLocked(app);
1076 }
1077 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001078 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1079 synchronized (ActivityManagerService.this) {
1080 doPendingActivityLaunchesLocked(true);
1081 }
1082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084 }
1085 };
1086
1087 public static void setSystemProcess() {
1088 try {
1089 ActivityManagerService m = mSelf;
1090
1091 ServiceManager.addService("activity", m);
1092 ServiceManager.addService("meminfo", new MemBinder(m));
1093 if (MONITOR_CPU_USAGE) {
1094 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1095 }
1096 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1097 ServiceManager.addService("activity.services", new ServicesBinder(m));
1098 ServiceManager.addService("activity.senders", new SendersBinder(m));
1099 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1100 ServiceManager.addService("permission", new PermissionController(m));
1101
1102 ApplicationInfo info =
1103 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001104 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 synchronized (mSelf) {
1106 ProcessRecord app = mSelf.newProcessRecordLocked(
1107 mSystemThread.getApplicationThread(), info,
1108 info.processName);
1109 app.persistent = true;
1110 app.pid = Process.myPid();
1111 app.maxAdj = SYSTEM_ADJ;
1112 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1113 synchronized (mSelf.mPidsSelfLocked) {
1114 mSelf.mPidsSelfLocked.put(app.pid, app);
1115 }
1116 mSelf.updateLRUListLocked(app, true);
1117 }
1118 } catch (PackageManager.NameNotFoundException e) {
1119 throw new RuntimeException(
1120 "Unable to find android system package", e);
1121 }
1122 }
1123
1124 public void setWindowManager(WindowManagerService wm) {
1125 mWindowManager = wm;
1126 }
1127
1128 public static final Context main(int factoryTest) {
1129 AThread thr = new AThread();
1130 thr.start();
1131
1132 synchronized (thr) {
1133 while (thr.mService == null) {
1134 try {
1135 thr.wait();
1136 } catch (InterruptedException e) {
1137 }
1138 }
1139 }
1140
1141 ActivityManagerService m = thr.mService;
1142 mSelf = m;
1143 ActivityThread at = ActivityThread.systemMain();
1144 mSystemThread = at;
1145 Context context = at.getSystemContext();
1146 m.mContext = context;
1147 m.mFactoryTest = factoryTest;
1148 PowerManager pm =
1149 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1150 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1151 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1152 m.mLaunchingActivity.setReferenceCounted(false);
1153
1154 m.mBatteryStatsService.publish(context);
1155 m.mUsageStatsService.publish(context);
1156
1157 synchronized (thr) {
1158 thr.mReady = true;
1159 thr.notifyAll();
1160 }
1161
1162 m.startRunning(null, null, null, null);
1163
1164 return context;
1165 }
1166
1167 public static ActivityManagerService self() {
1168 return mSelf;
1169 }
1170
1171 static class AThread extends Thread {
1172 ActivityManagerService mService;
1173 boolean mReady = false;
1174
1175 public AThread() {
1176 super("ActivityManager");
1177 }
1178
1179 public void run() {
1180 Looper.prepare();
1181
1182 android.os.Process.setThreadPriority(
1183 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1184
1185 ActivityManagerService m = new ActivityManagerService();
1186
1187 synchronized (this) {
1188 mService = m;
1189 notifyAll();
1190 }
1191
1192 synchronized (this) {
1193 while (!mReady) {
1194 try {
1195 wait();
1196 } catch (InterruptedException e) {
1197 }
1198 }
1199 }
1200
1201 Looper.loop();
1202 }
1203 }
1204
1205 static class BroadcastsBinder extends Binder {
1206 ActivityManagerService mActivityManagerService;
1207 BroadcastsBinder(ActivityManagerService activityManagerService) {
1208 mActivityManagerService = activityManagerService;
1209 }
1210
1211 @Override
1212 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1213 mActivityManagerService.dumpBroadcasts(pw);
1214 }
1215 }
1216
1217 static class ServicesBinder extends Binder {
1218 ActivityManagerService mActivityManagerService;
1219 ServicesBinder(ActivityManagerService activityManagerService) {
1220 mActivityManagerService = activityManagerService;
1221 }
1222
1223 @Override
1224 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1225 mActivityManagerService.dumpServices(pw);
1226 }
1227 }
1228
1229 static class SendersBinder extends Binder {
1230 ActivityManagerService mActivityManagerService;
1231 SendersBinder(ActivityManagerService activityManagerService) {
1232 mActivityManagerService = activityManagerService;
1233 }
1234
1235 @Override
1236 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1237 mActivityManagerService.dumpSenders(pw);
1238 }
1239 }
1240
1241 static class ProvidersBinder extends Binder {
1242 ActivityManagerService mActivityManagerService;
1243 ProvidersBinder(ActivityManagerService activityManagerService) {
1244 mActivityManagerService = activityManagerService;
1245 }
1246
1247 @Override
1248 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1249 mActivityManagerService.dumpProviders(pw);
1250 }
1251 }
1252
1253 static class MemBinder extends Binder {
1254 ActivityManagerService mActivityManagerService;
1255 MemBinder(ActivityManagerService activityManagerService) {
1256 mActivityManagerService = activityManagerService;
1257 }
1258
1259 @Override
1260 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1261 ActivityManagerService service = mActivityManagerService;
1262 ArrayList<ProcessRecord> procs;
1263 synchronized (mActivityManagerService) {
1264 if (args != null && args.length > 0
1265 && args[0].charAt(0) != '-') {
1266 procs = new ArrayList<ProcessRecord>();
1267 int pid = -1;
1268 try {
1269 pid = Integer.parseInt(args[0]);
1270 } catch (NumberFormatException e) {
1271
1272 }
1273 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1274 ProcessRecord proc = service.mLRUProcesses.get(i);
1275 if (proc.pid == pid) {
1276 procs.add(proc);
1277 } else if (proc.processName.equals(args[0])) {
1278 procs.add(proc);
1279 }
1280 }
1281 if (procs.size() <= 0) {
1282 pw.println("No process found for: " + args[0]);
1283 return;
1284 }
1285 } else {
1286 procs = service.mLRUProcesses;
1287 }
1288 }
1289 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1290 }
1291 }
1292
1293 static class CpuBinder extends Binder {
1294 ActivityManagerService mActivityManagerService;
1295 CpuBinder(ActivityManagerService activityManagerService) {
1296 mActivityManagerService = activityManagerService;
1297 }
1298
1299 @Override
1300 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1301 synchronized (mActivityManagerService.mProcessStatsThread) {
1302 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1303 }
1304 }
1305 }
1306
1307 private ActivityManagerService() {
1308 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1309 if (v != null && Integer.getInteger(v) != 0) {
1310 mSimpleProcessManagement = true;
1311 }
1312 v = System.getenv("ANDROID_DEBUG_APP");
1313 if (v != null) {
1314 mSimpleProcessManagement = true;
1315 }
1316
1317 MY_PID = Process.myPid();
1318
1319 File dataDir = Environment.getDataDirectory();
1320 File systemDir = new File(dataDir, "system");
1321 systemDir.mkdirs();
1322 mBatteryStatsService = new BatteryStatsService(new File(
1323 systemDir, "batterystats.bin").toString());
1324 mBatteryStatsService.getActiveStatistics().readLocked();
1325 mBatteryStatsService.getActiveStatistics().writeLocked();
1326
1327 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001328 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329
1330 mConfiguration.makeDefault();
1331 mProcessStats.init();
1332
1333 // Add ourself to the Watchdog monitors.
1334 Watchdog.getInstance().addMonitor(this);
1335
1336 // These values are set in system/rootdir/init.rc on startup.
1337 FOREGROUND_APP_ADJ =
1338 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1339 VISIBLE_APP_ADJ =
1340 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1341 SECONDARY_SERVER_ADJ =
1342 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001343 HOME_APP_ADJ =
1344 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 HIDDEN_APP_MIN_ADJ =
1346 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1347 CONTENT_PROVIDER_ADJ =
1348 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1349 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1350 EMPTY_APP_ADJ =
1351 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1352 FOREGROUND_APP_MEM =
1353 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1354 VISIBLE_APP_MEM =
1355 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1356 SECONDARY_SERVER_MEM =
1357 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001358 HOME_APP_MEM =
1359 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 HIDDEN_APP_MEM =
1361 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1362 EMPTY_APP_MEM =
1363 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1364
1365 mProcessStatsThread = new Thread("ProcessStats") {
1366 public void run() {
1367 while (true) {
1368 try {
1369 try {
1370 synchronized(this) {
1371 final long now = SystemClock.uptimeMillis();
1372 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1373 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1374 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1375 // + ", write delay=" + nextWriteDelay);
1376 if (nextWriteDelay < nextCpuDelay) {
1377 nextCpuDelay = nextWriteDelay;
1378 }
1379 if (nextCpuDelay > 0) {
1380 this.wait(nextCpuDelay);
1381 }
1382 }
1383 } catch (InterruptedException e) {
1384 }
1385
1386 updateCpuStatsNow();
1387 } catch (Exception e) {
1388 Log.e(TAG, "Unexpected exception collecting process stats", e);
1389 }
1390 }
1391 }
1392 };
1393 mProcessStatsThread.start();
1394 }
1395
1396 @Override
1397 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1398 throws RemoteException {
1399 try {
1400 return super.onTransact(code, data, reply, flags);
1401 } catch (RuntimeException e) {
1402 // The activity manager only throws security exceptions, so let's
1403 // log all others.
1404 if (!(e instanceof SecurityException)) {
1405 Log.e(TAG, "Activity Manager Crash", e);
1406 }
1407 throw e;
1408 }
1409 }
1410
1411 void updateCpuStats() {
1412 synchronized (mProcessStatsThread) {
1413 final long now = SystemClock.uptimeMillis();
1414 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1415 mProcessStatsThread.notify();
1416 }
1417 }
1418 }
1419
1420 void updateCpuStatsNow() {
1421 synchronized (mProcessStatsThread) {
1422 final long now = SystemClock.uptimeMillis();
1423 boolean haveNewCpuStats = false;
1424
1425 if (MONITOR_CPU_USAGE &&
1426 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1427 mLastCpuTime = now;
1428 haveNewCpuStats = true;
1429 mProcessStats.update();
1430 //Log.i(TAG, mProcessStats.printCurrentState());
1431 //Log.i(TAG, "Total CPU usage: "
1432 // + mProcessStats.getTotalCpuPercent() + "%");
1433
1434 // Log the cpu usage if the property is set.
1435 if ("true".equals(SystemProperties.get("events.cpu"))) {
1436 int user = mProcessStats.getLastUserTime();
1437 int system = mProcessStats.getLastSystemTime();
1438 int iowait = mProcessStats.getLastIoWaitTime();
1439 int irq = mProcessStats.getLastIrqTime();
1440 int softIrq = mProcessStats.getLastSoftIrqTime();
1441 int idle = mProcessStats.getLastIdleTime();
1442
1443 int total = user + system + iowait + irq + softIrq + idle;
1444 if (total == 0) total = 1;
1445
1446 EventLog.writeEvent(LOG_CPU,
1447 ((user+system+iowait+irq+softIrq) * 100) / total,
1448 (user * 100) / total,
1449 (system * 100) / total,
1450 (iowait * 100) / total,
1451 (irq * 100) / total,
1452 (softIrq * 100) / total);
1453 }
1454 }
1455
1456 synchronized(mBatteryStatsService.getActiveStatistics()) {
1457 synchronized(mPidsSelfLocked) {
1458 if (haveNewCpuStats) {
1459 if (mBatteryStatsService.isOnBattery()) {
1460 final int N = mProcessStats.countWorkingStats();
1461 for (int i=0; i<N; i++) {
1462 ProcessStats.Stats st
1463 = mProcessStats.getWorkingStats(i);
1464 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1465 if (pr != null) {
1466 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1467 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1468 }
1469 }
1470 }
1471 }
1472 }
1473
1474 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1475 mLastWriteTime = now;
1476 mBatteryStatsService.getActiveStatistics().writeLocked();
1477 }
1478 }
1479 }
1480 }
1481
1482 /**
1483 * Initialize the application bind args. These are passed to each
1484 * process when the bindApplication() IPC is sent to the process. They're
1485 * lazily setup to make sure the services are running when they're asked for.
1486 */
1487 private HashMap<String, IBinder> getCommonServicesLocked() {
1488 if (mAppBindArgs == null) {
1489 mAppBindArgs = new HashMap<String, IBinder>();
1490
1491 // Setup the application init args
1492 mAppBindArgs.put("package", ServiceManager.getService("package"));
1493 mAppBindArgs.put("window", ServiceManager.getService("window"));
1494 mAppBindArgs.put(Context.ALARM_SERVICE,
1495 ServiceManager.getService(Context.ALARM_SERVICE));
1496 }
1497 return mAppBindArgs;
1498 }
1499
1500 private final void setFocusedActivityLocked(HistoryRecord r) {
1501 if (mFocusedActivity != r) {
1502 mFocusedActivity = r;
1503 mWindowManager.setFocusedApp(r, true);
1504 }
1505 }
1506
1507 private final void updateLRUListLocked(ProcessRecord app,
1508 boolean oomAdj) {
1509 // put it on the LRU to keep track of when it should be exited.
1510 int lrui = mLRUProcesses.indexOf(app);
1511 if (lrui >= 0) mLRUProcesses.remove(lrui);
1512 mLRUProcesses.add(app);
1513 //Log.i(TAG, "Putting proc to front: " + app.processName);
1514 if (oomAdj) {
1515 updateOomAdjLocked();
1516 }
1517 }
1518
1519 private final boolean updateLRUListLocked(HistoryRecord r) {
1520 final boolean hadit = mLRUActivities.remove(r);
1521 mLRUActivities.add(r);
1522 return hadit;
1523 }
1524
1525 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1526 int i = mHistory.size()-1;
1527 while (i >= 0) {
1528 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1529 if (!r.finishing && r != notTop) {
1530 return r;
1531 }
1532 i--;
1533 }
1534 return null;
1535 }
1536
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001537 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1538 int i = mHistory.size()-1;
1539 while (i >= 0) {
1540 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1541 if (!r.finishing && !r.delayedResume && r != notTop) {
1542 return r;
1543 }
1544 i--;
1545 }
1546 return null;
1547 }
1548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 /**
1550 * This is a simplified version of topRunningActivityLocked that provides a number of
1551 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1552 *
1553 * @param token If non-null, any history records matching this token will be skipped.
1554 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1555 *
1556 * @return Returns the HistoryRecord of the next activity on the stack.
1557 */
1558 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1559 int i = mHistory.size()-1;
1560 while (i >= 0) {
1561 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1562 // Note: the taskId check depends on real taskId fields being non-zero
1563 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1564 return r;
1565 }
1566 i--;
1567 }
1568 return null;
1569 }
1570
1571 private final ProcessRecord getProcessRecordLocked(
1572 String processName, int uid) {
1573 if (uid == Process.SYSTEM_UID) {
1574 // The system gets to run in any process. If there are multiple
1575 // processes with the same uid, just pick the first (this
1576 // should never happen).
1577 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1578 processName);
1579 return procs != null ? procs.valueAt(0) : null;
1580 }
1581 ProcessRecord proc = mProcessNames.get(processName, uid);
1582 return proc;
1583 }
1584
1585 private boolean isNextTransitionForward() {
1586 int transit = mWindowManager.getPendingAppTransition();
1587 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1588 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1589 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1590 }
1591
1592 private final boolean realStartActivityLocked(HistoryRecord r,
1593 ProcessRecord app, boolean andResume, boolean checkConfig)
1594 throws RemoteException {
1595
1596 r.startFreezingScreenLocked(app, 0);
1597 mWindowManager.setAppVisibility(r, true);
1598
1599 // Have the window manager re-evaluate the orientation of
1600 // the screen based on the new activity order. Note that
1601 // as a result of this, it can call back into the activity
1602 // manager with a new orientation. We don't care about that,
1603 // because the activity is not currently running so we are
1604 // just restarting it anyway.
1605 if (checkConfig) {
1606 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001607 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 r.mayFreezeScreenLocked(app) ? r : null);
1609 updateConfigurationLocked(config, r);
1610 }
1611
1612 r.app = app;
1613
1614 if (localLOGV) Log.v(TAG, "Launching: " + r);
1615
1616 int idx = app.activities.indexOf(r);
1617 if (idx < 0) {
1618 app.activities.add(r);
1619 }
1620 updateLRUListLocked(app, true);
1621
1622 try {
1623 if (app.thread == null) {
1624 throw new RemoteException();
1625 }
1626 List<ResultInfo> results = null;
1627 List<Intent> newIntents = null;
1628 if (andResume) {
1629 results = r.results;
1630 newIntents = r.newIntents;
1631 }
1632 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1633 + " icicle=" + r.icicle
1634 + " with results=" + results + " newIntents=" + newIntents
1635 + " andResume=" + andResume);
1636 if (andResume) {
1637 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1638 System.identityHashCode(r),
1639 r.task.taskId, r.shortComponentName);
1640 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001641 if (r.isHomeActivity) {
1642 mHomeProcess = app;
1643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1645 r.info, r.icicle, results, newIntents, !andResume,
1646 isNextTransitionForward());
1647 // Update usage stats for launched activity
1648 updateUsageStats(r, true);
1649 } catch (RemoteException e) {
1650 if (r.launchFailed) {
1651 // This is the second time we failed -- finish activity
1652 // and give up.
1653 Log.e(TAG, "Second failure launching "
1654 + r.intent.getComponent().flattenToShortString()
1655 + ", giving up", e);
1656 appDiedLocked(app, app.pid, app.thread);
1657 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1658 "2nd-crash");
1659 return false;
1660 }
1661
1662 // This is the first time we failed -- restart process and
1663 // retry.
1664 app.activities.remove(r);
1665 throw e;
1666 }
1667
1668 r.launchFailed = false;
1669 if (updateLRUListLocked(r)) {
1670 Log.w(TAG, "Activity " + r
1671 + " being launched, but already in LRU list");
1672 }
1673
1674 if (andResume) {
1675 // As part of the process of launching, ActivityThread also performs
1676 // a resume.
1677 r.state = ActivityState.RESUMED;
1678 r.icicle = null;
1679 r.haveState = false;
1680 r.stopped = false;
1681 mResumedActivity = r;
1682 r.task.touchActiveTime();
1683 completeResumeLocked(r);
1684 pauseIfSleepingLocked();
1685 } else {
1686 // This activity is not starting in the resumed state... which
1687 // should look like we asked it to pause+stop (but remain visible),
1688 // and it has done so and reported back the current icicle and
1689 // other state.
1690 r.state = ActivityState.STOPPED;
1691 r.stopped = true;
1692 }
1693
1694 return true;
1695 }
1696
1697 private final void startSpecificActivityLocked(HistoryRecord r,
1698 boolean andResume, boolean checkConfig) {
1699 // Is this activity's application already running?
1700 ProcessRecord app = getProcessRecordLocked(r.processName,
1701 r.info.applicationInfo.uid);
1702
1703 if (r.startTime == 0) {
1704 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001705 if (mInitialStartTime == 0) {
1706 mInitialStartTime = r.startTime;
1707 }
1708 } else if (mInitialStartTime == 0) {
1709 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
1711
1712 if (app != null && app.thread != null) {
1713 try {
1714 realStartActivityLocked(r, app, andResume, checkConfig);
1715 return;
1716 } catch (RemoteException e) {
1717 Log.w(TAG, "Exception when starting activity "
1718 + r.intent.getComponent().flattenToShortString(), e);
1719 }
1720
1721 // If a dead object exception was thrown -- fall through to
1722 // restart the application.
1723 }
1724
1725 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1726 "activity", r.intent.getComponent());
1727 }
1728
1729 private final ProcessRecord startProcessLocked(String processName,
1730 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1731 String hostingType, ComponentName hostingName) {
1732 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1733 // We don't have to do anything more if:
1734 // (1) There is an existing application record; and
1735 // (2) The caller doesn't think it is dead, OR there is no thread
1736 // object attached to it so we know it couldn't have crashed; and
1737 // (3) There is a pid assigned to it, so it is either starting or
1738 // already running.
1739 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1740 + " app=" + app + " knownToBeDead=" + knownToBeDead
1741 + " thread=" + (app != null ? app.thread : null)
1742 + " pid=" + (app != null ? app.pid : -1));
1743 if (app != null &&
1744 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1745 return app;
1746 }
1747
1748 String hostingNameStr = hostingName != null
1749 ? hostingName.flattenToShortString() : null;
1750
1751 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1752 // If we are in the background, then check to see if this process
1753 // is bad. If so, we will just silently fail.
1754 if (mBadProcesses.get(info.processName, info.uid) != null) {
1755 return null;
1756 }
1757 } else {
1758 // When the user is explicitly starting a process, then clear its
1759 // crash count so that we won't make it bad until they see at
1760 // least one crash dialog again, and make the process good again
1761 // if it had been bad.
1762 mProcessCrashTimes.remove(info.processName, info.uid);
1763 if (mBadProcesses.get(info.processName, info.uid) != null) {
1764 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1765 info.processName);
1766 mBadProcesses.remove(info.processName, info.uid);
1767 if (app != null) {
1768 app.bad = false;
1769 }
1770 }
1771 }
1772
1773 if (app == null) {
1774 app = newProcessRecordLocked(null, info, processName);
1775 mProcessNames.put(processName, info.uid, app);
1776 } else {
1777 // If this is a new package in the process, add the package to the list
1778 app.addPackage(info.packageName);
1779 }
1780
1781 // If the system is not ready yet, then hold off on starting this
1782 // process until it is.
1783 if (!mSystemReady
1784 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1785 if (!mProcessesOnHold.contains(app)) {
1786 mProcessesOnHold.add(app);
1787 }
1788 return app;
1789 }
1790
1791 startProcessLocked(app, hostingType, hostingNameStr);
1792 return (app.pid != 0) ? app : null;
1793 }
1794
1795 private final void startProcessLocked(ProcessRecord app,
1796 String hostingType, String hostingNameStr) {
1797 if (app.pid > 0 && app.pid != MY_PID) {
1798 synchronized (mPidsSelfLocked) {
1799 mPidsSelfLocked.remove(app.pid);
1800 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1801 }
1802 app.pid = 0;
1803 }
1804
1805 mProcessesOnHold.remove(app);
1806
1807 updateCpuStats();
1808
1809 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1810 mProcDeaths[0] = 0;
1811
1812 try {
1813 int uid = app.info.uid;
1814 int[] gids = null;
1815 try {
1816 gids = mContext.getPackageManager().getPackageGids(
1817 app.info.packageName);
1818 } catch (PackageManager.NameNotFoundException e) {
1819 Log.w(TAG, "Unable to retrieve gids", e);
1820 }
1821 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1822 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1823 && mTopComponent != null
1824 && app.processName.equals(mTopComponent.getPackageName())) {
1825 uid = 0;
1826 }
1827 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1828 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1829 uid = 0;
1830 }
1831 }
1832 int debugFlags = 0;
1833 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1834 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1835 }
1836 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1837 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1838 }
1839 if ("1".equals(SystemProperties.get("debug.assert"))) {
1840 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1841 }
1842 int pid = Process.start("android.app.ActivityThread",
1843 mSimpleProcessManagement ? app.processName : null, uid, uid,
1844 gids, debugFlags, null);
1845 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1846 synchronized (bs) {
1847 if (bs.isOnBattery()) {
1848 app.batteryStats.incStartsLocked();
1849 }
1850 }
1851
1852 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1853 app.processName, hostingType,
1854 hostingNameStr != null ? hostingNameStr : "");
1855
1856 if (app.persistent) {
1857 Watchdog.getInstance().processStarted(app, app.processName, pid);
1858 }
1859
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001860 StringBuilder buf = mStringBuilder;
1861 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 buf.append("Start proc ");
1863 buf.append(app.processName);
1864 buf.append(" for ");
1865 buf.append(hostingType);
1866 if (hostingNameStr != null) {
1867 buf.append(" ");
1868 buf.append(hostingNameStr);
1869 }
1870 buf.append(": pid=");
1871 buf.append(pid);
1872 buf.append(" uid=");
1873 buf.append(uid);
1874 buf.append(" gids={");
1875 if (gids != null) {
1876 for (int gi=0; gi<gids.length; gi++) {
1877 if (gi != 0) buf.append(", ");
1878 buf.append(gids[gi]);
1879
1880 }
1881 }
1882 buf.append("}");
1883 Log.i(TAG, buf.toString());
1884 if (pid == 0 || pid == MY_PID) {
1885 // Processes are being emulated with threads.
1886 app.pid = MY_PID;
1887 app.removed = false;
1888 mStartingProcesses.add(app);
1889 } else if (pid > 0) {
1890 app.pid = pid;
1891 app.removed = false;
1892 synchronized (mPidsSelfLocked) {
1893 this.mPidsSelfLocked.put(pid, app);
1894 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1895 msg.obj = app;
1896 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1897 }
1898 } else {
1899 app.pid = 0;
1900 RuntimeException e = new RuntimeException(
1901 "Failure starting process " + app.processName
1902 + ": returned pid=" + pid);
1903 Log.e(TAG, e.getMessage(), e);
1904 }
1905 } catch (RuntimeException e) {
1906 // XXX do better error recovery.
1907 app.pid = 0;
1908 Log.e(TAG, "Failure starting process " + app.processName, e);
1909 }
1910 }
1911
1912 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1913 if (mPausingActivity != null) {
1914 RuntimeException e = new RuntimeException();
1915 Log.e(TAG, "Trying to pause when pause is already pending for "
1916 + mPausingActivity, e);
1917 }
1918 HistoryRecord prev = mResumedActivity;
1919 if (prev == null) {
1920 RuntimeException e = new RuntimeException();
1921 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1922 resumeTopActivityLocked(null);
1923 return;
1924 }
1925 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
1926 mResumedActivity = null;
1927 mPausingActivity = prev;
1928 mLastPausedActivity = prev;
1929 prev.state = ActivityState.PAUSING;
1930 prev.task.touchActiveTime();
1931
1932 updateCpuStats();
1933
1934 if (prev.app != null && prev.app.thread != null) {
1935 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
1936 try {
1937 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
1938 System.identityHashCode(prev),
1939 prev.shortComponentName);
1940 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
1941 prev.configChangeFlags);
1942 updateUsageStats(prev, false);
1943 } catch (Exception e) {
1944 // Ignore exception, if process died other code will cleanup.
1945 Log.w(TAG, "Exception thrown during pause", e);
1946 mPausingActivity = null;
1947 mLastPausedActivity = null;
1948 }
1949 } else {
1950 mPausingActivity = null;
1951 mLastPausedActivity = null;
1952 }
1953
1954 // If we are not going to sleep, we want to ensure the device is
1955 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07001956 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 mLaunchingActivity.acquire();
1958 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
1959 // To be safe, don't allow the wake lock to be held for too long.
1960 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1961 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
1962 }
1963 }
1964
1965
1966 if (mPausingActivity != null) {
1967 // Have the window manager pause its key dispatching until the new
1968 // activity has started. If we're pausing the activity just because
1969 // the screen is being turned off and the UI is sleeping, don't interrupt
1970 // key dispatch; the same activity will pick it up again on wakeup.
1971 if (!uiSleeping) {
1972 prev.pauseKeyDispatchingLocked();
1973 } else {
1974 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
1975 }
1976
1977 // Schedule a pause timeout in case the app doesn't respond.
1978 // We don't give it much time because this directly impacts the
1979 // responsiveness seen by the user.
1980 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
1981 msg.obj = prev;
1982 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
1983 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
1984 } else {
1985 // This activity failed to schedule the
1986 // pause, so just treat it as being paused now.
1987 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
1988 resumeTopActivityLocked(null);
1989 }
1990 }
1991
1992 private final void completePauseLocked() {
1993 HistoryRecord prev = mPausingActivity;
1994 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
1995
1996 if (prev != null) {
1997 if (prev.finishing) {
1998 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
1999 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2000 } else if (prev.app != null) {
2001 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2002 if (prev.waitingVisible) {
2003 prev.waitingVisible = false;
2004 mWaitingVisibleActivities.remove(prev);
2005 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2006 TAG, "Complete pause, no longer waiting: " + prev);
2007 }
2008 if (prev.configDestroy) {
2009 // The previous is being paused because the configuration
2010 // is changing, which means it is actually stopping...
2011 // To juggle the fact that we are also starting a new
2012 // instance right now, we need to first completely stop
2013 // the current instance before starting the new one.
2014 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2015 destroyActivityLocked(prev, true);
2016 } else {
2017 mStoppingActivities.add(prev);
2018 if (mStoppingActivities.size() > 3) {
2019 // If we already have a few activities waiting to stop,
2020 // then give up on things going idle and start clearing
2021 // them out.
2022 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2023 Message msg = Message.obtain();
2024 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2025 mHandler.sendMessage(msg);
2026 }
2027 }
2028 } else {
2029 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2030 prev = null;
2031 }
2032 mPausingActivity = null;
2033 }
2034
Dianne Hackborn55280a92009-05-07 15:53:46 -07002035 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 resumeTopActivityLocked(prev);
2037 } else {
2038 if (mGoingToSleep.isHeld()) {
2039 mGoingToSleep.release();
2040 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002041 if (mShuttingDown) {
2042 notifyAll();
2043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 }
2045
2046 if (prev != null) {
2047 prev.resumeKeyDispatchingLocked();
2048 }
2049 }
2050
2051 /**
2052 * Once we know that we have asked an application to put an activity in
2053 * the resumed state (either by launching it or explicitly telling it),
2054 * this function updates the rest of our state to match that fact.
2055 */
2056 private final void completeResumeLocked(HistoryRecord next) {
2057 next.idle = false;
2058 next.results = null;
2059 next.newIntents = null;
2060
2061 // schedule an idle timeout in case the app doesn't do it for us.
2062 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2063 msg.obj = next;
2064 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2065
2066 if (false) {
2067 // The activity was never told to pause, so just keep
2068 // things going as-is. To maintain our own state,
2069 // we need to emulate it coming back and saying it is
2070 // idle.
2071 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2072 msg.obj = next;
2073 mHandler.sendMessage(msg);
2074 }
2075
2076 next.thumbnail = null;
2077 setFocusedActivityLocked(next);
2078 next.resumeKeyDispatchingLocked();
2079 ensureActivitiesVisibleLocked(null, 0);
2080 mWindowManager.executeAppTransition();
2081 }
2082
2083 /**
2084 * Make sure that all activities that need to be visible (that is, they
2085 * currently can be seen by the user) actually are.
2086 */
2087 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2088 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2089 if (DEBUG_VISBILITY) Log.v(
2090 TAG, "ensureActivitiesVisible behind " + top
2091 + " configChanges=0x" + Integer.toHexString(configChanges));
2092
2093 // If the top activity is not fullscreen, then we need to
2094 // make sure any activities under it are now visible.
2095 final int count = mHistory.size();
2096 int i = count-1;
2097 while (mHistory.get(i) != top) {
2098 i--;
2099 }
2100 HistoryRecord r;
2101 boolean behindFullscreen = false;
2102 for (; i>=0; i--) {
2103 r = (HistoryRecord)mHistory.get(i);
2104 if (DEBUG_VISBILITY) Log.v(
2105 TAG, "Make visible? " + r + " finishing=" + r.finishing
2106 + " state=" + r.state);
2107 if (r.finishing) {
2108 continue;
2109 }
2110
2111 final boolean doThisProcess = onlyThisProcess == null
2112 || onlyThisProcess.equals(r.processName);
2113
2114 // First: if this is not the current activity being started, make
2115 // sure it matches the current configuration.
2116 if (r != starting && doThisProcess) {
2117 ensureActivityConfigurationLocked(r, 0);
2118 }
2119
2120 if (r.app == null || r.app.thread == null) {
2121 if (onlyThisProcess == null
2122 || onlyThisProcess.equals(r.processName)) {
2123 // This activity needs to be visible, but isn't even
2124 // running... get it started, but don't resume it
2125 // at this point.
2126 if (DEBUG_VISBILITY) Log.v(
2127 TAG, "Start and freeze screen for " + r);
2128 if (r != starting) {
2129 r.startFreezingScreenLocked(r.app, configChanges);
2130 }
2131 if (!r.visible) {
2132 if (DEBUG_VISBILITY) Log.v(
2133 TAG, "Starting and making visible: " + r);
2134 mWindowManager.setAppVisibility(r, true);
2135 }
2136 if (r != starting) {
2137 startSpecificActivityLocked(r, false, false);
2138 }
2139 }
2140
2141 } else if (r.visible) {
2142 // If this activity is already visible, then there is nothing
2143 // else to do here.
2144 if (DEBUG_VISBILITY) Log.v(
2145 TAG, "Skipping: already visible at " + r);
2146 r.stopFreezingScreenLocked(false);
2147
2148 } else if (onlyThisProcess == null) {
2149 // This activity is not currently visible, but is running.
2150 // Tell it to become visible.
2151 r.visible = true;
2152 if (r.state != ActivityState.RESUMED && r != starting) {
2153 // If this activity is paused, tell it
2154 // to now show its window.
2155 if (DEBUG_VISBILITY) Log.v(
2156 TAG, "Making visible and scheduling visibility: " + r);
2157 try {
2158 mWindowManager.setAppVisibility(r, true);
2159 r.app.thread.scheduleWindowVisibility(r, true);
2160 r.stopFreezingScreenLocked(false);
2161 } catch (Exception e) {
2162 // Just skip on any failure; we'll make it
2163 // visible when it next restarts.
2164 Log.w(TAG, "Exception thrown making visibile: "
2165 + r.intent.getComponent(), e);
2166 }
2167 }
2168 }
2169
2170 // Aggregate current change flags.
2171 configChanges |= r.configChangeFlags;
2172
2173 if (r.fullscreen) {
2174 // At this point, nothing else needs to be shown
2175 if (DEBUG_VISBILITY) Log.v(
2176 TAG, "Stopping: fullscreen at " + r);
2177 behindFullscreen = true;
2178 i--;
2179 break;
2180 }
2181 }
2182
2183 // Now for any activities that aren't visible to the user, make
2184 // sure they no longer are keeping the screen frozen.
2185 while (i >= 0) {
2186 r = (HistoryRecord)mHistory.get(i);
2187 if (DEBUG_VISBILITY) Log.v(
2188 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2189 + " state=" + r.state
2190 + " behindFullscreen=" + behindFullscreen);
2191 if (!r.finishing) {
2192 if (behindFullscreen) {
2193 if (r.visible) {
2194 if (DEBUG_VISBILITY) Log.v(
2195 TAG, "Making invisible: " + r);
2196 r.visible = false;
2197 try {
2198 mWindowManager.setAppVisibility(r, false);
2199 if ((r.state == ActivityState.STOPPING
2200 || r.state == ActivityState.STOPPED)
2201 && r.app != null && r.app.thread != null) {
2202 if (DEBUG_VISBILITY) Log.v(
2203 TAG, "Scheduling invisibility: " + r);
2204 r.app.thread.scheduleWindowVisibility(r, false);
2205 }
2206 } catch (Exception e) {
2207 // Just skip on any failure; we'll make it
2208 // visible when it next restarts.
2209 Log.w(TAG, "Exception thrown making hidden: "
2210 + r.intent.getComponent(), e);
2211 }
2212 } else {
2213 if (DEBUG_VISBILITY) Log.v(
2214 TAG, "Already invisible: " + r);
2215 }
2216 } else if (r.fullscreen) {
2217 if (DEBUG_VISBILITY) Log.v(
2218 TAG, "Now behindFullscreen: " + r);
2219 behindFullscreen = true;
2220 }
2221 }
2222 i--;
2223 }
2224 }
2225
2226 /**
2227 * Version of ensureActivitiesVisible that can easily be called anywhere.
2228 */
2229 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2230 int configChanges) {
2231 HistoryRecord r = topRunningActivityLocked(null);
2232 if (r != null) {
2233 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2234 }
2235 }
2236
2237 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2238 if (resumed) {
2239 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2240 } else {
2241 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2242 }
2243 }
2244
2245 /**
2246 * Ensure that the top activity in the stack is resumed.
2247 *
2248 * @param prev The previously resumed activity, for when in the process
2249 * of pausing; can be null to call from elsewhere.
2250 *
2251 * @return Returns true if something is being resumed, or false if
2252 * nothing happened.
2253 */
2254 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2255 // Find the first activity that is not finishing.
2256 HistoryRecord next = topRunningActivityLocked(null);
2257
2258 // Remember how we'll process this pause/resume situation, and ensure
2259 // that the state is reset however we wind up proceeding.
2260 final boolean userLeaving = mUserLeaving;
2261 mUserLeaving = false;
2262
2263 if (next == null) {
2264 // There are no more activities! Let's just start up the
2265 // Launcher...
2266 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2267 && mTopAction == null) {
2268 // We are running in factory test mode, but unable to find
2269 // the factory test app, so just sit around displaying the
2270 // error message and don't try to start anything.
2271 return false;
2272 }
2273 Intent intent = new Intent(
2274 mTopAction,
2275 mTopData != null ? Uri.parse(mTopData) : null);
2276 intent.setComponent(mTopComponent);
2277 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2278 intent.addCategory(Intent.CATEGORY_HOME);
2279 }
2280 ActivityInfo aInfo =
2281 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002282 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 if (aInfo != null) {
2284 intent.setComponent(new ComponentName(
2285 aInfo.applicationInfo.packageName, aInfo.name));
2286 // Don't do this if the home app is currently being
2287 // instrumented.
2288 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2289 aInfo.applicationInfo.uid);
2290 if (app == null || app.instrumentationClass == null) {
2291 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2292 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002293 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 }
2295 }
2296 return true;
2297 }
2298
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002299 next.delayedResume = false;
2300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002301 // If the top activity is the resumed one, nothing to do.
2302 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2303 // Make sure we have executed any pending transitions, since there
2304 // should be nothing left to do at this point.
2305 mWindowManager.executeAppTransition();
2306 return false;
2307 }
2308
2309 // If we are sleeping, and there is no resumed activity, and the top
2310 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002311 if ((mSleeping || mShuttingDown)
2312 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 // Make sure we have executed any pending transitions, since there
2314 // should be nothing left to do at this point.
2315 mWindowManager.executeAppTransition();
2316 return false;
2317 }
2318
2319 // The activity may be waiting for stop, but that is no longer
2320 // appropriate for it.
2321 mStoppingActivities.remove(next);
2322 mWaitingVisibleActivities.remove(next);
2323
2324 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2325
2326 // If we are currently pausing an activity, then don't do anything
2327 // until that is done.
2328 if (mPausingActivity != null) {
2329 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2330 return false;
2331 }
2332
2333 // We need to start pausing the current activity so the top one
2334 // can be resumed...
2335 if (mResumedActivity != null) {
2336 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2337 startPausingLocked(userLeaving, false);
2338 return true;
2339 }
2340
2341 if (prev != null && prev != next) {
2342 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2343 prev.waitingVisible = true;
2344 mWaitingVisibleActivities.add(prev);
2345 if (DEBUG_SWITCH) Log.v(
2346 TAG, "Resuming top, waiting visible to hide: " + prev);
2347 } else {
2348 // The next activity is already visible, so hide the previous
2349 // activity's windows right now so we can show the new one ASAP.
2350 // We only do this if the previous is finishing, which should mean
2351 // it is on top of the one being resumed so hiding it quickly
2352 // is good. Otherwise, we want to do the normal route of allowing
2353 // the resumed activity to be shown so we can decide if the
2354 // previous should actually be hidden depending on whether the
2355 // new one is found to be full-screen or not.
2356 if (prev.finishing) {
2357 mWindowManager.setAppVisibility(prev, false);
2358 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2359 + prev + ", waitingVisible="
2360 + (prev != null ? prev.waitingVisible : null)
2361 + ", nowVisible=" + next.nowVisible);
2362 } else {
2363 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2364 + prev + ", waitingVisible="
2365 + (prev != null ? prev.waitingVisible : null)
2366 + ", nowVisible=" + next.nowVisible);
2367 }
2368 }
2369 }
2370
2371 // We are starting up the next activity, so tell the window manager
2372 // that the previous one will be hidden soon. This way it can know
2373 // to ignore it when computing the desired screen orientation.
2374 if (prev != null) {
2375 if (prev.finishing) {
2376 if (DEBUG_TRANSITION) Log.v(TAG,
2377 "Prepare close transition: prev=" + prev);
2378 mWindowManager.prepareAppTransition(prev.task == next.task
2379 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2380 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2381 mWindowManager.setAppWillBeHidden(prev);
2382 mWindowManager.setAppVisibility(prev, false);
2383 } else {
2384 if (DEBUG_TRANSITION) Log.v(TAG,
2385 "Prepare open transition: prev=" + prev);
2386 mWindowManager.prepareAppTransition(prev.task == next.task
2387 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2388 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2389 }
2390 if (false) {
2391 mWindowManager.setAppWillBeHidden(prev);
2392 mWindowManager.setAppVisibility(prev, false);
2393 }
2394 } else if (mHistory.size() > 1) {
2395 if (DEBUG_TRANSITION) Log.v(TAG,
2396 "Prepare open transition: no previous");
2397 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2398 }
2399
2400 if (next.app != null && next.app.thread != null) {
2401 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2402
2403 // This activity is now becoming visible.
2404 mWindowManager.setAppVisibility(next, true);
2405
2406 HistoryRecord lastResumedActivity = mResumedActivity;
2407 ActivityState lastState = next.state;
2408
2409 updateCpuStats();
2410
2411 next.state = ActivityState.RESUMED;
2412 mResumedActivity = next;
2413 next.task.touchActiveTime();
2414 updateLRUListLocked(next.app, true);
2415 updateLRUListLocked(next);
2416
2417 // Have the window manager re-evaluate the orientation of
2418 // the screen based on the new activity order.
2419 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002420 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002421 next.mayFreezeScreenLocked(next.app) ? next : null);
2422 if (config != null) {
2423 next.frozenBeforeDestroy = true;
2424 }
2425 if (!updateConfigurationLocked(config, next)) {
2426 // The configuration update wasn't able to keep the existing
2427 // instance of the activity, and instead started a new one.
2428 // We should be all done, but let's just make sure our activity
2429 // is still at the top and schedule another run if something
2430 // weird happened.
2431 HistoryRecord nextNext = topRunningActivityLocked(null);
2432 if (DEBUG_SWITCH) Log.i(TAG,
2433 "Activity config changed during resume: " + next
2434 + ", new next: " + nextNext);
2435 if (nextNext != next) {
2436 // Do over!
2437 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2438 }
2439 mWindowManager.executeAppTransition();
2440 return true;
2441 }
2442
2443 try {
2444 // Deliver all pending results.
2445 ArrayList a = next.results;
2446 if (a != null) {
2447 final int N = a.size();
2448 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002449 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450 TAG, "Delivering results to " + next
2451 + ": " + a);
2452 next.app.thread.scheduleSendResult(next, a);
2453 }
2454 }
2455
2456 if (next.newIntents != null) {
2457 next.app.thread.scheduleNewIntent(next.newIntents, next);
2458 }
2459
2460 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2461 System.identityHashCode(next),
2462 next.task.taskId, next.shortComponentName);
2463 updateUsageStats(next, true);
2464
2465 next.app.thread.scheduleResumeActivity(next,
2466 isNextTransitionForward());
2467 pauseIfSleepingLocked();
2468
2469 } catch (Exception e) {
2470 // Whoops, need to restart this activity!
2471 next.state = lastState;
2472 mResumedActivity = lastResumedActivity;
2473 if (Config.LOGD) Log.d(TAG,
2474 "Restarting because process died: " + next);
2475 if (!next.hasBeenLaunched) {
2476 next.hasBeenLaunched = true;
2477 } else {
2478 if (SHOW_APP_STARTING_ICON) {
2479 mWindowManager.setAppStartingWindow(
2480 next, next.packageName, next.theme,
2481 next.nonLocalizedLabel,
2482 next.labelRes, next.icon, null, true);
2483 }
2484 }
2485 startSpecificActivityLocked(next, true, false);
2486 return true;
2487 }
2488
2489 // From this point on, if something goes wrong there is no way
2490 // to recover the activity.
2491 try {
2492 next.visible = true;
2493 completeResumeLocked(next);
2494 } catch (Exception e) {
2495 // If any exception gets thrown, toss away this
2496 // activity and try the next one.
2497 Log.w(TAG, "Exception thrown during resume of " + next, e);
2498 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2499 "resume-exception");
2500 return true;
2501 }
2502
2503 // Didn't need to use the icicle, and it is now out of date.
2504 next.icicle = null;
2505 next.haveState = false;
2506 next.stopped = false;
2507
2508 } else {
2509 // Whoops, need to restart this activity!
2510 if (!next.hasBeenLaunched) {
2511 next.hasBeenLaunched = true;
2512 } else {
2513 if (SHOW_APP_STARTING_ICON) {
2514 mWindowManager.setAppStartingWindow(
2515 next, next.packageName, next.theme,
2516 next.nonLocalizedLabel,
2517 next.labelRes, next.icon, null, true);
2518 }
2519 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2520 }
2521 startSpecificActivityLocked(next, true, true);
2522 }
2523
2524 return true;
2525 }
2526
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002527 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2528 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 final int NH = mHistory.size();
2530
2531 int addPos = -1;
2532
2533 if (!newTask) {
2534 // If starting in an existing task, find where that is...
2535 HistoryRecord next = null;
2536 boolean startIt = true;
2537 for (int i = NH-1; i >= 0; i--) {
2538 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2539 if (p.finishing) {
2540 continue;
2541 }
2542 if (p.task == r.task) {
2543 // Here it is! Now, if this is not yet visible to the
2544 // user, then just add it without starting; it will
2545 // get started when the user navigates back to it.
2546 addPos = i+1;
2547 if (!startIt) {
2548 mHistory.add(addPos, r);
2549 r.inHistory = true;
2550 r.task.numActivities++;
2551 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2552 r.info.screenOrientation, r.fullscreen);
2553 if (VALIDATE_TOKENS) {
2554 mWindowManager.validateAppTokens(mHistory);
2555 }
2556 return;
2557 }
2558 break;
2559 }
2560 if (p.fullscreen) {
2561 startIt = false;
2562 }
2563 next = p;
2564 }
2565 }
2566
2567 // Place a new activity at top of stack, so it is next to interact
2568 // with the user.
2569 if (addPos < 0) {
2570 addPos = mHistory.size();
2571 }
2572
2573 // If we are not placing the new activity frontmost, we do not want
2574 // to deliver the onUserLeaving callback to the actual frontmost
2575 // activity
2576 if (addPos < NH) {
2577 mUserLeaving = false;
2578 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2579 }
2580
2581 // Slot the activity into the history stack and proceed
2582 mHistory.add(addPos, r);
2583 r.inHistory = true;
2584 r.frontOfTask = newTask;
2585 r.task.numActivities++;
2586 if (NH > 0) {
2587 // We want to show the starting preview window if we are
2588 // switching to a new task, or the next activity's process is
2589 // not currently running.
2590 boolean showStartingIcon = newTask;
2591 ProcessRecord proc = r.app;
2592 if (proc == null) {
2593 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2594 }
2595 if (proc == null || proc.thread == null) {
2596 showStartingIcon = true;
2597 }
2598 if (DEBUG_TRANSITION) Log.v(TAG,
2599 "Prepare open transition: starting " + r);
2600 mWindowManager.prepareAppTransition(newTask
2601 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2602 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2603 mWindowManager.addAppToken(
2604 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2605 boolean doShow = true;
2606 if (newTask) {
2607 // Even though this activity is starting fresh, we still need
2608 // to reset it to make sure we apply affinities to move any
2609 // existing activities from other tasks in to it.
2610 // If the caller has requested that the target task be
2611 // reset, then do so.
2612 if ((r.intent.getFlags()
2613 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2614 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002615 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 }
2617 }
2618 if (SHOW_APP_STARTING_ICON && doShow) {
2619 // Figure out if we are transitioning from another activity that is
2620 // "has the same starting icon" as the next one. This allows the
2621 // window manager to keep the previous window it had previously
2622 // created, if it still had one.
2623 HistoryRecord prev = mResumedActivity;
2624 if (prev != null) {
2625 // We don't want to reuse the previous starting preview if:
2626 // (1) The current activity is in a different task.
2627 if (prev.task != r.task) prev = null;
2628 // (2) The current activity is already displayed.
2629 else if (prev.nowVisible) prev = null;
2630 }
2631 mWindowManager.setAppStartingWindow(
2632 r, r.packageName, r.theme, r.nonLocalizedLabel,
2633 r.labelRes, r.icon, prev, showStartingIcon);
2634 }
2635 } else {
2636 // If this is the first activity, don't do any fancy animations,
2637 // because there is nothing for it to animate on top of.
2638 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2639 r.info.screenOrientation, r.fullscreen);
2640 }
2641 if (VALIDATE_TOKENS) {
2642 mWindowManager.validateAppTokens(mHistory);
2643 }
2644
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002645 if (doResume) {
2646 resumeTopActivityLocked(null);
2647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002648 }
2649
2650 /**
2651 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002652 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2653 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 * an instance of that activity in the stack and, if found, finish all
2655 * activities on top of it and return the instance.
2656 *
2657 * @param newR Description of the new activity being started.
2658 * @return Returns the old activity that should be continue to be used,
2659 * or null if none was found.
2660 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002661 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 HistoryRecord newR, boolean doClear) {
2663 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002664
2665 // First find the requested task.
2666 while (i > 0) {
2667 i--;
2668 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2669 if (r.task.taskId == taskId) {
2670 i++;
2671 break;
2672 }
2673 }
2674
2675 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002676 while (i > 0) {
2677 i--;
2678 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2679 if (r.finishing) {
2680 continue;
2681 }
2682 if (r.task.taskId != taskId) {
2683 return null;
2684 }
2685 if (r.realActivity.equals(newR.realActivity)) {
2686 // Here it is! Now finish everything in front...
2687 HistoryRecord ret = r;
2688 if (doClear) {
2689 while (i < (mHistory.size()-1)) {
2690 i++;
2691 r = (HistoryRecord)mHistory.get(i);
2692 if (r.finishing) {
2693 continue;
2694 }
2695 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2696 null, "clear")) {
2697 i--;
2698 }
2699 }
2700 }
2701
2702 // Finally, if this is a normal launch mode (that is, not
2703 // expecting onNewIntent()), then we will finish the current
2704 // instance of the activity so a new fresh one can be started.
2705 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2706 if (!ret.finishing) {
2707 int index = indexOfTokenLocked(ret, false);
2708 if (index >= 0) {
2709 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2710 null, "clear");
2711 }
2712 return null;
2713 }
2714 }
2715
2716 return ret;
2717 }
2718 }
2719
2720 return null;
2721 }
2722
2723 /**
2724 * Find the activity in the history stack within the given task. Returns
2725 * the index within the history at which it's found, or < 0 if not found.
2726 */
2727 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2728 int i = mHistory.size();
2729 while (i > 0) {
2730 i--;
2731 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2732 if (candidate.task.taskId != task) {
2733 break;
2734 }
2735 if (candidate.realActivity.equals(r.realActivity)) {
2736 return i;
2737 }
2738 }
2739
2740 return -1;
2741 }
2742
2743 /**
2744 * Reorder the history stack so that the activity at the given index is
2745 * brought to the front.
2746 */
2747 private final HistoryRecord moveActivityToFrontLocked(int where) {
2748 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2749 int top = mHistory.size();
2750 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2751 mHistory.add(top, newTop);
2752 oldTop.frontOfTask = false;
2753 newTop.frontOfTask = true;
2754 return newTop;
2755 }
2756
2757 /**
2758 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2759 * method will be called at the proper time.
2760 */
2761 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2762 boolean sent = false;
2763 if (r.state == ActivityState.RESUMED
2764 && r.app != null && r.app.thread != null) {
2765 try {
2766 ArrayList<Intent> ar = new ArrayList<Intent>();
2767 ar.add(new Intent(intent));
2768 r.app.thread.scheduleNewIntent(ar, r);
2769 sent = true;
2770 } catch (Exception e) {
2771 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2772 }
2773 }
2774 if (!sent) {
2775 r.addNewIntentLocked(new Intent(intent));
2776 }
2777 }
2778
2779 private final void logStartActivity(int tag, HistoryRecord r,
2780 TaskRecord task) {
2781 EventLog.writeEvent(tag,
2782 System.identityHashCode(r), task.taskId,
2783 r.shortComponentName, r.intent.getAction(),
2784 r.intent.getType(), r.intent.getDataString(),
2785 r.intent.getFlags());
2786 }
2787
2788 private final int startActivityLocked(IApplicationThread caller,
2789 Intent intent, String resolvedType,
2790 Uri[] grantedUriPermissions,
2791 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2792 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002793 int callingPid, int callingUid, boolean onlyIfNeeded,
2794 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 Log.i(TAG, "Starting activity: " + intent);
2796
2797 HistoryRecord sourceRecord = null;
2798 HistoryRecord resultRecord = null;
2799 if (resultTo != null) {
2800 int index = indexOfTokenLocked(resultTo, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002801 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002802 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2803 if (index >= 0) {
2804 sourceRecord = (HistoryRecord)mHistory.get(index);
2805 if (requestCode >= 0 && !sourceRecord.finishing) {
2806 resultRecord = sourceRecord;
2807 }
2808 }
2809 }
2810
2811 int launchFlags = intent.getFlags();
2812
2813 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2814 && sourceRecord != null) {
2815 // Transfer the result target from the source activity to the new
2816 // one being started, including any failures.
2817 if (requestCode >= 0) {
2818 return START_FORWARD_AND_REQUEST_CONFLICT;
2819 }
2820 resultRecord = sourceRecord.resultTo;
2821 resultWho = sourceRecord.resultWho;
2822 requestCode = sourceRecord.requestCode;
2823 sourceRecord.resultTo = null;
2824 if (resultRecord != null) {
2825 resultRecord.removeResultsLocked(
2826 sourceRecord, resultWho, requestCode);
2827 }
2828 }
2829
2830 int err = START_SUCCESS;
2831
2832 if (intent.getComponent() == null) {
2833 // We couldn't find a class that can handle the given Intent.
2834 // That's the end of that!
2835 err = START_INTENT_NOT_RESOLVED;
2836 }
2837
2838 if (err == START_SUCCESS && aInfo == null) {
2839 // We couldn't find the specific class specified in the Intent.
2840 // Also the end of the line.
2841 err = START_CLASS_NOT_FOUND;
2842 }
2843
2844 ProcessRecord callerApp = null;
2845 if (err == START_SUCCESS && caller != null) {
2846 callerApp = getRecordForAppLocked(caller);
2847 if (callerApp != null) {
2848 callingPid = callerApp.pid;
2849 callingUid = callerApp.info.uid;
2850 } else {
2851 Log.w(TAG, "Unable to find app for caller " + caller
2852 + " (pid=" + callingPid + ") when starting: "
2853 + intent.toString());
2854 err = START_PERMISSION_DENIED;
2855 }
2856 }
2857
2858 if (err != START_SUCCESS) {
2859 if (resultRecord != null) {
2860 sendActivityResultLocked(-1,
2861 resultRecord, resultWho, requestCode,
2862 Activity.RESULT_CANCELED, null);
2863 }
2864 return err;
2865 }
2866
2867 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2868 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2869 if (perm != PackageManager.PERMISSION_GRANTED) {
2870 if (resultRecord != null) {
2871 sendActivityResultLocked(-1,
2872 resultRecord, resultWho, requestCode,
2873 Activity.RESULT_CANCELED, null);
2874 }
2875 String msg = "Permission Denial: starting " + intent.toString()
2876 + " from " + callerApp + " (pid=" + callingPid
2877 + ", uid=" + callingUid + ")"
2878 + " requires " + aInfo.permission;
2879 Log.w(TAG, msg);
2880 throw new SecurityException(msg);
2881 }
2882
2883 if (mWatcher != null) {
2884 boolean abort = false;
2885 try {
2886 // The Intent we give to the watcher has the extra data
2887 // stripped off, since it can contain private information.
2888 Intent watchIntent = intent.cloneFilter();
2889 abort = !mWatcher.activityStarting(watchIntent,
2890 aInfo.applicationInfo.packageName);
2891 } catch (RemoteException e) {
2892 mWatcher = null;
2893 }
2894
2895 if (abort) {
2896 if (resultRecord != null) {
2897 sendActivityResultLocked(-1,
2898 resultRecord, resultWho, requestCode,
2899 Activity.RESULT_CANCELED, null);
2900 }
2901 // We pretend to the caller that it was really started, but
2902 // they will just get a cancel result.
2903 return START_SUCCESS;
2904 }
2905 }
2906
2907 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
2908 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002909 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002911 if (mResumedActivity == null
2912 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2913 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2914 PendingActivityLaunch pal = new PendingActivityLaunch();
2915 pal.r = r;
2916 pal.sourceRecord = sourceRecord;
2917 pal.grantedUriPermissions = grantedUriPermissions;
2918 pal.grantedMode = grantedMode;
2919 pal.onlyIfNeeded = onlyIfNeeded;
2920 mPendingActivityLaunches.add(pal);
2921 return START_SWITCHES_CANCELED;
2922 }
2923 }
2924
2925 if (mDidAppSwitch) {
2926 // This is the second allowed switch since we stopped switches,
2927 // so now just generally allow switches. Use case: user presses
2928 // home (switches disabled, switch to home, mDidAppSwitch now true);
2929 // user taps a home icon (coming from home so allowed, we hit here
2930 // and now allow anyone to switch again).
2931 mAppSwitchesAllowedTime = 0;
2932 } else {
2933 mDidAppSwitch = true;
2934 }
2935
2936 doPendingActivityLaunchesLocked(false);
2937
2938 return startActivityUncheckedLocked(r, sourceRecord,
2939 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2940 }
2941
2942 private final void doPendingActivityLaunchesLocked(boolean doResume) {
2943 final int N = mPendingActivityLaunches.size();
2944 if (N <= 0) {
2945 return;
2946 }
2947 for (int i=0; i<N; i++) {
2948 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
2949 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
2950 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
2951 doResume && i == (N-1));
2952 }
2953 mPendingActivityLaunches.clear();
2954 }
2955
2956 private final int startActivityUncheckedLocked(HistoryRecord r,
2957 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
2958 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2959 final Intent intent = r.intent;
2960 final int callingUid = r.launchedFromUid;
2961
2962 int launchFlags = intent.getFlags();
2963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 // We'll invoke onUserLeaving before onPause only if the launching
2965 // activity did not explicitly state that this is an automated launch.
2966 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2967 if (DEBUG_USER_LEAVING) Log.v(TAG,
2968 "startActivity() => mUserLeaving=" + mUserLeaving);
2969
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002970 // If the caller has asked not to resume at this point, we make note
2971 // of this in the record so that we can skip it when trying to find
2972 // the top running activity.
2973 if (!doResume) {
2974 r.delayedResume = true;
2975 }
2976
2977 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2978 != 0 ? r : null;
2979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 // If the onlyIfNeeded flag is set, then we can do this if the activity
2981 // being launched is the same as the one making the call... or, as
2982 // a special case, if we do not know the caller then we count the
2983 // current top activity as the caller.
2984 if (onlyIfNeeded) {
2985 HistoryRecord checkedCaller = sourceRecord;
2986 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002987 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002988 }
2989 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2990 // Caller is not the same as launcher, so always needed.
2991 onlyIfNeeded = false;
2992 }
2993 }
2994
2995 if (grantedUriPermissions != null && callingUid > 0) {
2996 for (int i=0; i<grantedUriPermissions.length; i++) {
2997 grantUriPermissionLocked(callingUid, r.packageName,
2998 grantedUriPermissions[i], grantedMode, r);
2999 }
3000 }
3001
3002 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3003 intent, r);
3004
3005 if (sourceRecord == null) {
3006 // This activity is not being started from another... in this
3007 // case we -always- start a new task.
3008 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3009 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3010 + intent);
3011 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3012 }
3013 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3014 // The original activity who is starting us is running as a single
3015 // instance... this new activity it is starting must go on its
3016 // own task.
3017 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3018 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3019 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3020 // The activity being started is a single instance... it always
3021 // gets launched into its own task.
3022 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3023 }
3024
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003025 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003026 // For whatever reason this activity is being launched into a new
3027 // task... yet the caller has requested a result back. Well, that
3028 // is pretty messed up, so instead immediately send back a cancel
3029 // and let the new task continue launched as normal without a
3030 // dependency on its originator.
3031 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3032 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003033 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 Activity.RESULT_CANCELED, null);
3035 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 }
3037
3038 boolean addingToTask = false;
3039 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3040 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3041 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3042 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3043 // If bring to front is requested, and no result is requested, and
3044 // we can find a task that was started with this same
3045 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003046 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047 // See if there is a task to bring to the front. If this is
3048 // a SINGLE_INSTANCE activity, there can be one and only one
3049 // instance of it in the history, and it is always in its own
3050 // unique task, so we do a special search.
3051 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3052 ? findTaskLocked(intent, r.info)
3053 : findActivityLocked(intent, r.info);
3054 if (taskTop != null) {
3055 if (taskTop.task.intent == null) {
3056 // This task was started because of movement of
3057 // the activity based on affinity... now that we
3058 // are actually launching it, we can assign the
3059 // base intent.
3060 taskTop.task.setIntent(intent, r.info);
3061 }
3062 // If the target task is not in the front, then we need
3063 // to bring it to the front... except... well, with
3064 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3065 // to have the same behavior as if a new instance was
3066 // being started, which means not bringing it to the front
3067 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003068 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 if (curTop.task != taskTop.task) {
3070 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3071 boolean callerAtFront = sourceRecord == null
3072 || curTop.task == sourceRecord.task;
3073 if (callerAtFront) {
3074 // We really do want to push this one into the
3075 // user's face, right now.
3076 moveTaskToFrontLocked(taskTop.task);
3077 }
3078 }
3079 // If the caller has requested that the target task be
3080 // reset, then do so.
3081 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3082 taskTop = resetTaskIfNeededLocked(taskTop, r);
3083 }
3084 if (onlyIfNeeded) {
3085 // We don't need to start a new activity, and
3086 // the client said not to do anything if that
3087 // is the case, so this is it! And for paranoia, make
3088 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003089 if (doResume) {
3090 resumeTopActivityLocked(null);
3091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 return START_RETURN_INTENT_TO_CALLER;
3093 }
3094 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3095 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3096 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3097 // In this situation we want to remove all activities
3098 // from the task up to the one being started. In most
3099 // cases this means we are resetting the task to its
3100 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003101 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 taskTop.task.taskId, r, true);
3103 if (top != null) {
3104 if (top.frontOfTask) {
3105 // Activity aliases may mean we use different
3106 // intents for the top activity, so make sure
3107 // the task now has the identity of the new
3108 // intent.
3109 top.task.setIntent(r.intent, r.info);
3110 }
3111 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3112 deliverNewIntentLocked(top, r.intent);
3113 } else {
3114 // A special case: we need to
3115 // start the activity because it is not currently
3116 // running, and the caller has asked to clear the
3117 // current task to have this activity at the top.
3118 addingToTask = true;
3119 // Now pretend like this activity is being started
3120 // by the top of its task, so it is put in the
3121 // right place.
3122 sourceRecord = taskTop;
3123 }
3124 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3125 // In this case the top activity on the task is the
3126 // same as the one being launched, so we take that
3127 // as a request to bring the task to the foreground.
3128 // If the top activity in the task is the root
3129 // activity, deliver this new intent to it if it
3130 // desires.
3131 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3132 && taskTop.realActivity.equals(r.realActivity)) {
3133 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3134 if (taskTop.frontOfTask) {
3135 taskTop.task.setIntent(r.intent, r.info);
3136 }
3137 deliverNewIntentLocked(taskTop, r.intent);
3138 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3139 // In this case we are launching the root activity
3140 // of the task, but with a different intent. We
3141 // should start a new instance on top.
3142 addingToTask = true;
3143 sourceRecord = taskTop;
3144 }
3145 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3146 // In this case an activity is being launched in to an
3147 // existing task, without resetting that task. This
3148 // is typically the situation of launching an activity
3149 // from a notification or shortcut. We want to place
3150 // the new activity on top of the current task.
3151 addingToTask = true;
3152 sourceRecord = taskTop;
3153 } else if (!taskTop.task.rootWasReset) {
3154 // In this case we are launching in to an existing task
3155 // that has not yet been started from its front door.
3156 // The current task has been brought to the front.
3157 // Ideally, we'd probably like to place this new task
3158 // at the bottom of its stack, but that's a little hard
3159 // to do with the current organization of the code so
3160 // for now we'll just drop it.
3161 taskTop.task.setIntent(r.intent, r.info);
3162 }
3163 if (!addingToTask) {
3164 // We didn't do anything... but it was needed (a.k.a., client
3165 // don't use that intent!) And for paranoia, make
3166 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003167 if (doResume) {
3168 resumeTopActivityLocked(null);
3169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 return START_TASK_TO_FRONT;
3171 }
3172 }
3173 }
3174 }
3175
3176 //String uri = r.intent.toURI();
3177 //Intent intent2 = new Intent(uri);
3178 //Log.i(TAG, "Given intent: " + r.intent);
3179 //Log.i(TAG, "URI is: " + uri);
3180 //Log.i(TAG, "To intent: " + intent2);
3181
3182 if (r.packageName != null) {
3183 // If the activity being launched is the same as the one currently
3184 // at the top, then we need to check if it should only be launched
3185 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003186 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3187 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 if (top.realActivity.equals(r.realActivity)) {
3189 if (top.app != null && top.app.thread != null) {
3190 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3191 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3192 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3193 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3194 // For paranoia, make sure we have correctly
3195 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003196 if (doResume) {
3197 resumeTopActivityLocked(null);
3198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003199 if (onlyIfNeeded) {
3200 // We don't need to start a new activity, and
3201 // the client said not to do anything if that
3202 // is the case, so this is it!
3203 return START_RETURN_INTENT_TO_CALLER;
3204 }
3205 deliverNewIntentLocked(top, r.intent);
3206 return START_DELIVERED_TO_TOP;
3207 }
3208 }
3209 }
3210 }
3211
3212 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003213 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003214 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003215 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 Activity.RESULT_CANCELED, null);
3217 }
3218 return START_CLASS_NOT_FOUND;
3219 }
3220
3221 boolean newTask = false;
3222
3223 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003224 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3226 // todo: should do better management of integers.
3227 mCurTask++;
3228 if (mCurTask <= 0) {
3229 mCurTask = 1;
3230 }
3231 r.task = new TaskRecord(mCurTask, r.info, intent,
3232 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3233 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3234 + " in new task " + r.task);
3235 newTask = true;
3236 addRecentTask(r.task);
3237
3238 } else if (sourceRecord != null) {
3239 if (!addingToTask &&
3240 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3241 // In this case, we are adding the activity to an existing
3242 // task, but the caller has asked to clear that task if the
3243 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003244 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 sourceRecord.task.taskId, r, true);
3246 if (top != null) {
3247 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3248 deliverNewIntentLocked(top, r.intent);
3249 // For paranoia, make sure we have correctly
3250 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003251 if (doResume) {
3252 resumeTopActivityLocked(null);
3253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 return START_DELIVERED_TO_TOP;
3255 }
3256 } else if (!addingToTask &&
3257 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3258 // In this case, we are launching an activity in our own task
3259 // that may already be running somewhere in the history, and
3260 // we want to shuffle it to the front of the stack if so.
3261 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3262 if (where >= 0) {
3263 HistoryRecord top = moveActivityToFrontLocked(where);
3264 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3265 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003266 if (doResume) {
3267 resumeTopActivityLocked(null);
3268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 return START_DELIVERED_TO_TOP;
3270 }
3271 }
3272 // An existing activity is starting this new activity, so we want
3273 // to keep the new one in the same task as the one that is starting
3274 // it.
3275 r.task = sourceRecord.task;
3276 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3277 + " in existing task " + r.task);
3278
3279 } else {
3280 // This not being started from an existing activity, and not part
3281 // of a new task... just put it in the top task, though these days
3282 // this case should never happen.
3283 final int N = mHistory.size();
3284 HistoryRecord prev =
3285 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3286 r.task = prev != null
3287 ? prev.task
3288 : new TaskRecord(mCurTask, r.info, intent,
3289 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3290 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3291 + " in new guessed " + r.task);
3292 }
3293 if (newTask) {
3294 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3295 }
3296 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003297 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003298 return START_SUCCESS;
3299 }
3300
3301 public final int startActivity(IApplicationThread caller,
3302 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3303 int grantedMode, IBinder resultTo,
3304 String resultWho, int requestCode, boolean onlyIfNeeded,
3305 boolean debug) {
3306 // Refuse possible leaked file descriptors
3307 if (intent != null && intent.hasFileDescriptors()) {
3308 throw new IllegalArgumentException("File descriptors passed in Intent");
3309 }
3310
The Android Open Source Project4df24232009-03-05 14:34:35 -08003311 final boolean componentSpecified = intent.getComponent() != null;
3312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 // Don't modify the client's object!
3314 intent = new Intent(intent);
3315
3316 // Collect information about the target of the Intent.
3317 // Must do this before locking, because resolving the intent
3318 // may require launching a process to run its content provider.
3319 ActivityInfo aInfo;
3320 try {
3321 ResolveInfo rInfo =
3322 ActivityThread.getPackageManager().resolveIntent(
3323 intent, resolvedType,
3324 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003325 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 aInfo = rInfo != null ? rInfo.activityInfo : null;
3327 } catch (RemoteException e) {
3328 aInfo = null;
3329 }
3330
3331 if (aInfo != null) {
3332 // Store the found target back into the intent, because now that
3333 // we have it we never want to do this again. For example, if the
3334 // user navigates back to this point in the history, we should
3335 // always restart the exact same activity.
3336 intent.setComponent(new ComponentName(
3337 aInfo.applicationInfo.packageName, aInfo.name));
3338
3339 // Don't debug things in the system process
3340 if (debug) {
3341 if (!aInfo.processName.equals("system")) {
3342 setDebugApp(aInfo.processName, true, false);
3343 }
3344 }
3345 }
3346
3347 synchronized(this) {
3348 final long origId = Binder.clearCallingIdentity();
3349 int res = startActivityLocked(caller, intent, resolvedType,
3350 grantedUriPermissions, grantedMode, aInfo,
3351 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003352 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003353 Binder.restoreCallingIdentity(origId);
3354 return res;
3355 }
3356 }
3357
3358 public boolean startNextMatchingActivity(IBinder callingActivity,
3359 Intent intent) {
3360 // Refuse possible leaked file descriptors
3361 if (intent != null && intent.hasFileDescriptors() == true) {
3362 throw new IllegalArgumentException("File descriptors passed in Intent");
3363 }
3364
3365 synchronized (this) {
3366 int index = indexOfTokenLocked(callingActivity, false);
3367 if (index < 0) {
3368 return false;
3369 }
3370 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3371 if (r.app == null || r.app.thread == null) {
3372 // The caller is not running... d'oh!
3373 return false;
3374 }
3375 intent = new Intent(intent);
3376 // The caller is not allowed to change the data.
3377 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3378 // And we are resetting to find the next component...
3379 intent.setComponent(null);
3380
3381 ActivityInfo aInfo = null;
3382 try {
3383 List<ResolveInfo> resolves =
3384 ActivityThread.getPackageManager().queryIntentActivities(
3385 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003386 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003387
3388 // Look for the original activity in the list...
3389 final int N = resolves != null ? resolves.size() : 0;
3390 for (int i=0; i<N; i++) {
3391 ResolveInfo rInfo = resolves.get(i);
3392 if (rInfo.activityInfo.packageName.equals(r.packageName)
3393 && rInfo.activityInfo.name.equals(r.info.name)) {
3394 // We found the current one... the next matching is
3395 // after it.
3396 i++;
3397 if (i<N) {
3398 aInfo = resolves.get(i).activityInfo;
3399 }
3400 break;
3401 }
3402 }
3403 } catch (RemoteException e) {
3404 }
3405
3406 if (aInfo == null) {
3407 // Nobody who is next!
3408 return false;
3409 }
3410
3411 intent.setComponent(new ComponentName(
3412 aInfo.applicationInfo.packageName, aInfo.name));
3413 intent.setFlags(intent.getFlags()&~(
3414 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3415 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3416 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3417 Intent.FLAG_ACTIVITY_NEW_TASK));
3418
3419 // Okay now we need to start the new activity, replacing the
3420 // currently running activity. This is a little tricky because
3421 // we want to start the new one as if the current one is finished,
3422 // but not finish the current one first so that there is no flicker.
3423 // And thus...
3424 final boolean wasFinishing = r.finishing;
3425 r.finishing = true;
3426
3427 // Propagate reply information over to the new activity.
3428 final HistoryRecord resultTo = r.resultTo;
3429 final String resultWho = r.resultWho;
3430 final int requestCode = r.requestCode;
3431 r.resultTo = null;
3432 if (resultTo != null) {
3433 resultTo.removeResultsLocked(r, resultWho, requestCode);
3434 }
3435
3436 final long origId = Binder.clearCallingIdentity();
3437 // XXX we are not dealing with propagating grantedUriPermissions...
3438 // those are not yet exposed to user code, so there is no need.
3439 int res = startActivityLocked(r.app.thread, intent,
3440 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003441 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 Binder.restoreCallingIdentity(origId);
3443
3444 r.finishing = wasFinishing;
3445 if (res != START_SUCCESS) {
3446 return false;
3447 }
3448 return true;
3449 }
3450 }
3451
3452 final int startActivityInPackage(int uid,
3453 Intent intent, String resolvedType, IBinder resultTo,
3454 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003455 final boolean componentSpecified = intent.getComponent() != null;
3456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003457 // Don't modify the client's object!
3458 intent = new Intent(intent);
3459
3460 // Collect information about the target of the Intent.
3461 // Must do this before locking, because resolving the intent
3462 // may require launching a process to run its content provider.
3463 ActivityInfo aInfo;
3464 try {
3465 ResolveInfo rInfo =
3466 ActivityThread.getPackageManager().resolveIntent(
3467 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003468 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 aInfo = rInfo != null ? rInfo.activityInfo : null;
3470 } catch (RemoteException e) {
3471 aInfo = null;
3472 }
3473
3474 if (aInfo != null) {
3475 // Store the found target back into the intent, because now that
3476 // we have it we never want to do this again. For example, if the
3477 // user navigates back to this point in the history, we should
3478 // always restart the exact same activity.
3479 intent.setComponent(new ComponentName(
3480 aInfo.applicationInfo.packageName, aInfo.name));
3481 }
3482
3483 synchronized(this) {
3484 return startActivityLocked(null, intent, resolvedType,
3485 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003486 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 }
3488 }
3489
3490 private final void addRecentTask(TaskRecord task) {
3491 // Remove any existing entries that are the same kind of task.
3492 int N = mRecentTasks.size();
3493 for (int i=0; i<N; i++) {
3494 TaskRecord tr = mRecentTasks.get(i);
3495 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3496 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3497 mRecentTasks.remove(i);
3498 i--;
3499 N--;
3500 if (task.intent == null) {
3501 // If the new recent task we are adding is not fully
3502 // specified, then replace it with the existing recent task.
3503 task = tr;
3504 }
3505 }
3506 }
3507 if (N >= MAX_RECENT_TASKS) {
3508 mRecentTasks.remove(N-1);
3509 }
3510 mRecentTasks.add(0, task);
3511 }
3512
3513 public void setRequestedOrientation(IBinder token,
3514 int requestedOrientation) {
3515 synchronized (this) {
3516 int index = indexOfTokenLocked(token, false);
3517 if (index < 0) {
3518 return;
3519 }
3520 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3521 final long origId = Binder.clearCallingIdentity();
3522 mWindowManager.setAppOrientation(r, requestedOrientation);
3523 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003524 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 r.mayFreezeScreenLocked(r.app) ? r : null);
3526 if (config != null) {
3527 r.frozenBeforeDestroy = true;
3528 if (!updateConfigurationLocked(config, r)) {
3529 resumeTopActivityLocked(null);
3530 }
3531 }
3532 Binder.restoreCallingIdentity(origId);
3533 }
3534 }
3535
3536 public int getRequestedOrientation(IBinder token) {
3537 synchronized (this) {
3538 int index = indexOfTokenLocked(token, false);
3539 if (index < 0) {
3540 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3541 }
3542 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3543 return mWindowManager.getAppOrientation(r);
3544 }
3545 }
3546
3547 private final void stopActivityLocked(HistoryRecord r) {
3548 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3549 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3550 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3551 if (!r.finishing) {
3552 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3553 "no-history");
3554 }
3555 } else if (r.app != null && r.app.thread != null) {
3556 if (mFocusedActivity == r) {
3557 setFocusedActivityLocked(topRunningActivityLocked(null));
3558 }
3559 r.resumeKeyDispatchingLocked();
3560 try {
3561 r.stopped = false;
3562 r.state = ActivityState.STOPPING;
3563 if (DEBUG_VISBILITY) Log.v(
3564 TAG, "Stopping visible=" + r.visible + " for " + r);
3565 if (!r.visible) {
3566 mWindowManager.setAppVisibility(r, false);
3567 }
3568 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3569 } catch (Exception e) {
3570 // Maybe just ignore exceptions here... if the process
3571 // has crashed, our death notification will clean things
3572 // up.
3573 Log.w(TAG, "Exception thrown during pause", e);
3574 // Just in case, assume it to be stopped.
3575 r.stopped = true;
3576 r.state = ActivityState.STOPPED;
3577 if (r.configDestroy) {
3578 destroyActivityLocked(r, true);
3579 }
3580 }
3581 }
3582 }
3583
3584 /**
3585 * @return Returns true if the activity is being finished, false if for
3586 * some reason it is being left as-is.
3587 */
3588 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3589 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003590 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 TAG, "Finishing activity: token=" + token
3592 + ", result=" + resultCode + ", data=" + resultData);
3593
3594 int index = indexOfTokenLocked(token, false);
3595 if (index < 0) {
3596 return false;
3597 }
3598 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3599
3600 // Is this the last activity left?
3601 boolean lastActivity = true;
3602 for (int i=mHistory.size()-1; i>=0; i--) {
3603 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3604 if (!p.finishing && p != r) {
3605 lastActivity = false;
3606 break;
3607 }
3608 }
3609
3610 // If this is the last activity, but it is the home activity, then
3611 // just don't finish it.
3612 if (lastActivity) {
3613 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3614 return false;
3615 }
3616 }
3617
3618 finishActivityLocked(r, index, resultCode, resultData, reason);
3619 return true;
3620 }
3621
3622 /**
3623 * @return Returns true if this activity has been removed from the history
3624 * list, or false if it is still in the list and will be removed later.
3625 */
3626 private final boolean finishActivityLocked(HistoryRecord r, int index,
3627 int resultCode, Intent resultData, String reason) {
3628 if (r.finishing) {
3629 Log.w(TAG, "Duplicate finish request for " + r);
3630 return false;
3631 }
3632
3633 r.finishing = true;
3634 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3635 System.identityHashCode(r),
3636 r.task.taskId, r.shortComponentName, reason);
3637 r.task.numActivities--;
3638 if (r.frontOfTask && index < (mHistory.size()-1)) {
3639 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3640 if (next.task == r.task) {
3641 next.frontOfTask = true;
3642 }
3643 }
3644
3645 r.pauseKeyDispatchingLocked();
3646 if (mFocusedActivity == r) {
3647 setFocusedActivityLocked(topRunningActivityLocked(null));
3648 }
3649
3650 // send the result
3651 HistoryRecord resultTo = r.resultTo;
3652 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003653 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3654 + " who=" + r.resultWho + " req=" + r.requestCode
3655 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 if (r.info.applicationInfo.uid > 0) {
3657 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3658 r.packageName, resultData, r);
3659 }
3660 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3661 resultData);
3662 r.resultTo = null;
3663 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003664 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003665
3666 // Make sure this HistoryRecord is not holding on to other resources,
3667 // because clients have remote IPC references to this object so we
3668 // can't assume that will go away and want to avoid circular IPC refs.
3669 r.results = null;
3670 r.pendingResults = null;
3671 r.newIntents = null;
3672 r.icicle = null;
3673
3674 if (mPendingThumbnails.size() > 0) {
3675 // There are clients waiting to receive thumbnails so, in case
3676 // this is an activity that someone is waiting for, add it
3677 // to the pending list so we can correctly update the clients.
3678 mCancelledThumbnails.add(r);
3679 }
3680
3681 if (mResumedActivity == r) {
3682 boolean endTask = index <= 0
3683 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3684 if (DEBUG_TRANSITION) Log.v(TAG,
3685 "Prepare close transition: finishing " + r);
3686 mWindowManager.prepareAppTransition(endTask
3687 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3688 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3689
3690 // Tell window manager to prepare for this one to be removed.
3691 mWindowManager.setAppVisibility(r, false);
3692
3693 if (mPausingActivity == null) {
3694 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3695 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3696 startPausingLocked(false, false);
3697 }
3698
3699 } else if (r.state != ActivityState.PAUSING) {
3700 // If the activity is PAUSING, we will complete the finish once
3701 // it is done pausing; else we can just directly finish it here.
3702 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3703 return finishCurrentActivityLocked(r, index,
3704 FINISH_AFTER_PAUSE) == null;
3705 } else {
3706 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3707 }
3708
3709 return false;
3710 }
3711
3712 private static final int FINISH_IMMEDIATELY = 0;
3713 private static final int FINISH_AFTER_PAUSE = 1;
3714 private static final int FINISH_AFTER_VISIBLE = 2;
3715
3716 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3717 int mode) {
3718 final int index = indexOfTokenLocked(r, false);
3719 if (index < 0) {
3720 return null;
3721 }
3722
3723 return finishCurrentActivityLocked(r, index, mode);
3724 }
3725
3726 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3727 int index, int mode) {
3728 // First things first: if this activity is currently visible,
3729 // and the resumed activity is not yet visible, then hold off on
3730 // finishing until the resumed one becomes visible.
3731 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3732 if (!mStoppingActivities.contains(r)) {
3733 mStoppingActivities.add(r);
3734 if (mStoppingActivities.size() > 3) {
3735 // If we already have a few activities waiting to stop,
3736 // then give up on things going idle and start clearing
3737 // them out.
3738 Message msg = Message.obtain();
3739 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3740 mHandler.sendMessage(msg);
3741 }
3742 }
3743 r.state = ActivityState.STOPPING;
3744 updateOomAdjLocked();
3745 return r;
3746 }
3747
3748 // make sure the record is cleaned out of other places.
3749 mStoppingActivities.remove(r);
3750 mWaitingVisibleActivities.remove(r);
3751 if (mResumedActivity == r) {
3752 mResumedActivity = null;
3753 }
3754 final ActivityState prevState = r.state;
3755 r.state = ActivityState.FINISHING;
3756
3757 if (mode == FINISH_IMMEDIATELY
3758 || prevState == ActivityState.STOPPED
3759 || prevState == ActivityState.INITIALIZING) {
3760 // If this activity is already stopped, we can just finish
3761 // it right now.
3762 return destroyActivityLocked(r, true) ? null : r;
3763 } else {
3764 // Need to go through the full pause cycle to get this
3765 // activity into the stopped state and then finish it.
3766 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3767 mFinishingActivities.add(r);
3768 resumeTopActivityLocked(null);
3769 }
3770 return r;
3771 }
3772
3773 /**
3774 * This is the internal entry point for handling Activity.finish().
3775 *
3776 * @param token The Binder token referencing the Activity we want to finish.
3777 * @param resultCode Result code, if any, from this Activity.
3778 * @param resultData Result data (Intent), if any, from this Activity.
3779 *
3780 * @result Returns true if the activity successfully finished, or false if it is still running.
3781 */
3782 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3783 // Refuse possible leaked file descriptors
3784 if (resultData != null && resultData.hasFileDescriptors() == true) {
3785 throw new IllegalArgumentException("File descriptors passed in Intent");
3786 }
3787
3788 synchronized(this) {
3789 if (mWatcher != null) {
3790 // Find the first activity that is not finishing.
3791 HistoryRecord next = topRunningActivityLocked(token, 0);
3792 if (next != null) {
3793 // ask watcher if this is allowed
3794 boolean resumeOK = true;
3795 try {
3796 resumeOK = mWatcher.activityResuming(next.packageName);
3797 } catch (RemoteException e) {
3798 mWatcher = null;
3799 }
3800
3801 if (!resumeOK) {
3802 return false;
3803 }
3804 }
3805 }
3806 final long origId = Binder.clearCallingIdentity();
3807 boolean res = requestFinishActivityLocked(token, resultCode,
3808 resultData, "app-request");
3809 Binder.restoreCallingIdentity(origId);
3810 return res;
3811 }
3812 }
3813
3814 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3815 String resultWho, int requestCode, int resultCode, Intent data) {
3816
3817 if (callingUid > 0) {
3818 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3819 data, r);
3820 }
3821
The Android Open Source Project10592532009-03-18 17:39:46 -07003822 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3823 + " : who=" + resultWho + " req=" + requestCode
3824 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3826 try {
3827 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3828 list.add(new ResultInfo(resultWho, requestCode,
3829 resultCode, data));
3830 r.app.thread.scheduleSendResult(r, list);
3831 return;
3832 } catch (Exception e) {
3833 Log.w(TAG, "Exception thrown sending result to " + r, e);
3834 }
3835 }
3836
3837 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3838 }
3839
3840 public final void finishSubActivity(IBinder token, String resultWho,
3841 int requestCode) {
3842 synchronized(this) {
3843 int index = indexOfTokenLocked(token, false);
3844 if (index < 0) {
3845 return;
3846 }
3847 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3848
3849 final long origId = Binder.clearCallingIdentity();
3850
3851 int i;
3852 for (i=mHistory.size()-1; i>=0; i--) {
3853 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3854 if (r.resultTo == self && r.requestCode == requestCode) {
3855 if ((r.resultWho == null && resultWho == null) ||
3856 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3857 finishActivityLocked(r, i,
3858 Activity.RESULT_CANCELED, null, "request-sub");
3859 }
3860 }
3861 }
3862
3863 Binder.restoreCallingIdentity(origId);
3864 }
3865 }
3866
3867 /**
3868 * Perform clean-up of service connections in an activity record.
3869 */
3870 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3871 // Throw away any services that have been bound by this activity.
3872 if (r.connections != null) {
3873 Iterator<ConnectionRecord> it = r.connections.iterator();
3874 while (it.hasNext()) {
3875 ConnectionRecord c = it.next();
3876 removeConnectionLocked(c, null, r);
3877 }
3878 r.connections = null;
3879 }
3880 }
3881
3882 /**
3883 * Perform the common clean-up of an activity record. This is called both
3884 * as part of destroyActivityLocked() (when destroying the client-side
3885 * representation) and cleaning things up as a result of its hosting
3886 * processing going away, in which case there is no remaining client-side
3887 * state to destroy so only the cleanup here is needed.
3888 */
3889 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3890 if (mResumedActivity == r) {
3891 mResumedActivity = null;
3892 }
3893 if (mFocusedActivity == r) {
3894 mFocusedActivity = null;
3895 }
3896
3897 r.configDestroy = false;
3898 r.frozenBeforeDestroy = false;
3899
3900 // Make sure this record is no longer in the pending finishes list.
3901 // This could happen, for example, if we are trimming activities
3902 // down to the max limit while they are still waiting to finish.
3903 mFinishingActivities.remove(r);
3904 mWaitingVisibleActivities.remove(r);
3905
3906 // Remove any pending results.
3907 if (r.finishing && r.pendingResults != null) {
3908 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3909 PendingIntentRecord rec = apr.get();
3910 if (rec != null) {
3911 cancelIntentSenderLocked(rec, false);
3912 }
3913 }
3914 r.pendingResults = null;
3915 }
3916
3917 if (cleanServices) {
3918 cleanUpActivityServicesLocked(r);
3919 }
3920
3921 if (mPendingThumbnails.size() > 0) {
3922 // There are clients waiting to receive thumbnails so, in case
3923 // this is an activity that someone is waiting for, add it
3924 // to the pending list so we can correctly update the clients.
3925 mCancelledThumbnails.add(r);
3926 }
3927
3928 // Get rid of any pending idle timeouts.
3929 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3930 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3931 }
3932
3933 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
3934 if (r.state != ActivityState.DESTROYED) {
3935 mHistory.remove(r);
3936 r.inHistory = false;
3937 r.state = ActivityState.DESTROYED;
3938 mWindowManager.removeAppToken(r);
3939 if (VALIDATE_TOKENS) {
3940 mWindowManager.validateAppTokens(mHistory);
3941 }
3942 cleanUpActivityServicesLocked(r);
3943 removeActivityUriPermissionsLocked(r);
3944 }
3945 }
3946
3947 /**
3948 * Destroy the current CLIENT SIDE instance of an activity. This may be
3949 * called both when actually finishing an activity, or when performing
3950 * a configuration switch where we destroy the current client-side object
3951 * but then create a new client-side object for this same HistoryRecord.
3952 */
3953 private final boolean destroyActivityLocked(HistoryRecord r,
3954 boolean removeFromApp) {
3955 if (DEBUG_SWITCH) Log.v(
3956 TAG, "Removing activity: token=" + r
3957 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3958 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
3959 System.identityHashCode(r),
3960 r.task.taskId, r.shortComponentName);
3961
3962 boolean removedFromHistory = false;
3963
3964 cleanUpActivityLocked(r, false);
3965
3966 if (r.app != null) {
3967 if (removeFromApp) {
3968 int idx = r.app.activities.indexOf(r);
3969 if (idx >= 0) {
3970 r.app.activities.remove(idx);
3971 }
3972 if (r.persistent) {
3973 decPersistentCountLocked(r.app);
3974 }
3975 }
3976
3977 boolean skipDestroy = false;
3978
3979 try {
3980 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
3981 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3982 r.configChangeFlags);
3983 } catch (Exception e) {
3984 // We can just ignore exceptions here... if the process
3985 // has crashed, our death notification will clean things
3986 // up.
3987 //Log.w(TAG, "Exception thrown during finish", e);
3988 if (r.finishing) {
3989 removeActivityFromHistoryLocked(r);
3990 removedFromHistory = true;
3991 skipDestroy = true;
3992 }
3993 }
3994
3995 r.app = null;
3996 r.nowVisible = false;
3997
3998 if (r.finishing && !skipDestroy) {
3999 r.state = ActivityState.DESTROYING;
4000 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4001 msg.obj = r;
4002 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4003 } else {
4004 r.state = ActivityState.DESTROYED;
4005 }
4006 } else {
4007 // remove this record from the history.
4008 if (r.finishing) {
4009 removeActivityFromHistoryLocked(r);
4010 removedFromHistory = true;
4011 } else {
4012 r.state = ActivityState.DESTROYED;
4013 }
4014 }
4015
4016 r.configChangeFlags = 0;
4017
4018 if (!mLRUActivities.remove(r)) {
4019 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4020 }
4021
4022 return removedFromHistory;
4023 }
4024
4025 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4026 ProcessRecord app)
4027 {
4028 int i = list.size();
4029 if (localLOGV) Log.v(
4030 TAG, "Removing app " + app + " from list " + list
4031 + " with " + i + " entries");
4032 while (i > 0) {
4033 i--;
4034 HistoryRecord r = (HistoryRecord)list.get(i);
4035 if (localLOGV) Log.v(
4036 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4037 if (r.app == app) {
4038 if (localLOGV) Log.v(TAG, "Removing this entry!");
4039 list.remove(i);
4040 }
4041 }
4042 }
4043
4044 /**
4045 * Main function for removing an existing process from the activity manager
4046 * as a result of that process going away. Clears out all connections
4047 * to the process.
4048 */
4049 private final void handleAppDiedLocked(ProcessRecord app,
4050 boolean restarting) {
4051 cleanUpApplicationRecordLocked(app, restarting, -1);
4052 if (!restarting) {
4053 mLRUProcesses.remove(app);
4054 }
4055
4056 // Just in case...
4057 if (mPausingActivity != null && mPausingActivity.app == app) {
4058 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4059 mPausingActivity = null;
4060 }
4061 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4062 mLastPausedActivity = null;
4063 }
4064
4065 // Remove this application's activities from active lists.
4066 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4067 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4068 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4069 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4070
4071 boolean atTop = true;
4072 boolean hasVisibleActivities = false;
4073
4074 // Clean out the history list.
4075 int i = mHistory.size();
4076 if (localLOGV) Log.v(
4077 TAG, "Removing app " + app + " from history with " + i + " entries");
4078 while (i > 0) {
4079 i--;
4080 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4081 if (localLOGV) Log.v(
4082 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4083 if (r.app == app) {
4084 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4085 if (localLOGV) Log.v(
4086 TAG, "Removing this entry! frozen=" + r.haveState
4087 + " finishing=" + r.finishing);
4088 mHistory.remove(i);
4089
4090 r.inHistory = false;
4091 mWindowManager.removeAppToken(r);
4092 if (VALIDATE_TOKENS) {
4093 mWindowManager.validateAppTokens(mHistory);
4094 }
4095 removeActivityUriPermissionsLocked(r);
4096
4097 } else {
4098 // We have the current state for this activity, so
4099 // it can be restarted later when needed.
4100 if (localLOGV) Log.v(
4101 TAG, "Keeping entry, setting app to null");
4102 if (r.visible) {
4103 hasVisibleActivities = true;
4104 }
4105 r.app = null;
4106 r.nowVisible = false;
4107 if (!r.haveState) {
4108 r.icicle = null;
4109 }
4110 }
4111
4112 cleanUpActivityLocked(r, true);
4113 r.state = ActivityState.STOPPED;
4114 }
4115 atTop = false;
4116 }
4117
4118 app.activities.clear();
4119
4120 if (app.instrumentationClass != null) {
4121 Log.w(TAG, "Crash of app " + app.processName
4122 + " running instrumentation " + app.instrumentationClass);
4123 Bundle info = new Bundle();
4124 info.putString("shortMsg", "Process crashed.");
4125 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4126 }
4127
4128 if (!restarting) {
4129 if (!resumeTopActivityLocked(null)) {
4130 // If there was nothing to resume, and we are not already
4131 // restarting this process, but there is a visible activity that
4132 // is hosted by the process... then make sure all visible
4133 // activities are running, taking care of restarting this
4134 // process.
4135 if (hasVisibleActivities) {
4136 ensureActivitiesVisibleLocked(null, 0);
4137 }
4138 }
4139 }
4140 }
4141
4142 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4143 IBinder threadBinder = thread.asBinder();
4144
4145 // Find the application record.
4146 int count = mLRUProcesses.size();
4147 int i;
4148 for (i=0; i<count; i++) {
4149 ProcessRecord rec = mLRUProcesses.get(i);
4150 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4151 return i;
4152 }
4153 }
4154 return -1;
4155 }
4156
4157 private final ProcessRecord getRecordForAppLocked(
4158 IApplicationThread thread) {
4159 if (thread == null) {
4160 return null;
4161 }
4162
4163 int appIndex = getLRURecordIndexForAppLocked(thread);
4164 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4165 }
4166
4167 private final void appDiedLocked(ProcessRecord app, int pid,
4168 IApplicationThread thread) {
4169
4170 mProcDeaths[0]++;
4171
4172 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4173 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4174 + ") has died.");
4175 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4176 if (localLOGV) Log.v(
4177 TAG, "Dying app: " + app + ", pid: " + pid
4178 + ", thread: " + thread.asBinder());
4179 boolean doLowMem = app.instrumentationClass == null;
4180 handleAppDiedLocked(app, false);
4181
4182 if (doLowMem) {
4183 // If there are no longer any background processes running,
4184 // and the app that died was not running instrumentation,
4185 // then tell everyone we are now low on memory.
4186 boolean haveBg = false;
4187 int count = mLRUProcesses.size();
4188 int i;
4189 for (i=0; i<count; i++) {
4190 ProcessRecord rec = mLRUProcesses.get(i);
4191 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4192 haveBg = true;
4193 break;
4194 }
4195 }
4196
4197 if (!haveBg) {
4198 Log.i(TAG, "Low Memory: No more background processes.");
4199 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4200 for (i=0; i<count; i++) {
4201 ProcessRecord rec = mLRUProcesses.get(i);
4202 if (rec.thread != null) {
4203 rec.lastRequestedGc = SystemClock.uptimeMillis();
4204 try {
4205 rec.thread.scheduleLowMemory();
4206 } catch (RemoteException e) {
4207 // Don't care if the process is gone.
4208 }
4209 }
4210 }
4211 }
4212 }
4213 } else if (Config.LOGD) {
4214 Log.d(TAG, "Received spurious death notification for thread "
4215 + thread.asBinder());
4216 }
4217 }
4218
4219 final String readFile(String filename) {
4220 try {
4221 FileInputStream fs = new FileInputStream(filename);
4222 byte[] inp = new byte[8192];
4223 int size = fs.read(inp);
4224 fs.close();
4225 return new String(inp, 0, 0, size);
4226 } catch (java.io.IOException e) {
4227 }
4228 return "";
4229 }
4230
4231 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4232 final String annotation) {
4233 if (app.notResponding || app.crashing) {
4234 return;
4235 }
4236
4237 // Log the ANR to the event log.
4238 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4239
4240 // If we are on a secure build and the application is not interesting to the user (it is
4241 // not visible or in the background), just kill it instead of displaying a dialog.
4242 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4243 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4244 Process.killProcess(app.pid);
4245 return;
4246 }
4247
4248 // DeviceMonitor.start();
4249
4250 String processInfo = null;
4251 if (MONITOR_CPU_USAGE) {
4252 updateCpuStatsNow();
4253 synchronized (mProcessStatsThread) {
4254 processInfo = mProcessStats.printCurrentState();
4255 }
4256 }
4257
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004258 StringBuilder info = mStringBuilder;
4259 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004260 info.append("ANR (application not responding) in process: ");
4261 info.append(app.processName);
4262 if (annotation != null) {
4263 info.append("\nAnnotation: ");
4264 info.append(annotation);
4265 }
4266 if (MONITOR_CPU_USAGE) {
4267 info.append("\nCPU usage:\n");
4268 info.append(processInfo);
4269 }
4270 Log.i(TAG, info.toString());
4271
4272 // The application is not responding. Dump as many thread traces as we can.
4273 boolean fileDump = prepareTraceFile(true);
4274 if (!fileDump) {
4275 // Dumping traces to the log, just dump the process that isn't responding so
4276 // we don't overflow the log
4277 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4278 } else {
4279 // Dumping traces to a file so dump all active processes we know about
4280 synchronized (this) {
4281 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4282 ProcessRecord r = mLRUProcesses.get(i);
4283 if (r.thread != null) {
4284 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4285 }
4286 }
4287 }
4288 }
4289
4290 if (mWatcher != null) {
4291 try {
4292 int res = mWatcher.appNotResponding(app.processName,
4293 app.pid, info.toString());
4294 if (res != 0) {
4295 if (res < 0) {
4296 // wait until the SIGQUIT has had a chance to process before killing the
4297 // process.
4298 try {
4299 wait(2000);
4300 } catch (InterruptedException e) {
4301 }
4302
4303 Process.killProcess(app.pid);
4304 return;
4305 }
4306 }
4307 } catch (RemoteException e) {
4308 mWatcher = null;
4309 }
4310 }
4311
4312 makeAppNotRespondingLocked(app,
4313 activity != null ? activity.shortComponentName : null,
4314 annotation != null ? "ANR " + annotation : "ANR",
4315 info.toString(), null);
4316 Message msg = Message.obtain();
4317 HashMap map = new HashMap();
4318 msg.what = SHOW_NOT_RESPONDING_MSG;
4319 msg.obj = map;
4320 map.put("app", app);
4321 if (activity != null) {
4322 map.put("activity", activity);
4323 }
4324
4325 mHandler.sendMessage(msg);
4326 return;
4327 }
4328
4329 /**
4330 * If a stack trace file has been configured, prepare the filesystem
4331 * by creating the directory if it doesn't exist and optionally
4332 * removing the old trace file.
4333 *
4334 * @param removeExisting If set, the existing trace file will be removed.
4335 * @return Returns true if the trace file preparations succeeded
4336 */
4337 public static boolean prepareTraceFile(boolean removeExisting) {
4338 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4339 boolean fileReady = false;
4340 if (!TextUtils.isEmpty(tracesPath)) {
4341 File f = new File(tracesPath);
4342 if (!f.exists()) {
4343 // Ensure the enclosing directory exists
4344 File dir = f.getParentFile();
4345 if (!dir.exists()) {
4346 fileReady = dir.mkdirs();
4347 FileUtils.setPermissions(dir.getAbsolutePath(),
4348 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4349 } else if (dir.isDirectory()) {
4350 fileReady = true;
4351 }
4352 } else if (removeExisting) {
4353 // Remove the previous traces file, so we don't fill the disk.
4354 // The VM will recreate it
4355 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4356 fileReady = f.delete();
4357 }
4358 }
4359
4360 return fileReady;
4361 }
4362
4363
4364 private final void decPersistentCountLocked(ProcessRecord app)
4365 {
4366 app.persistentActivities--;
4367 if (app.persistentActivities > 0) {
4368 // Still more of 'em...
4369 return;
4370 }
4371 if (app.persistent) {
4372 // Ah, but the application itself is persistent. Whatever!
4373 return;
4374 }
4375
4376 // App is no longer persistent... make sure it and the ones
4377 // following it in the LRU list have the correc oom_adj.
4378 updateOomAdjLocked();
4379 }
4380
4381 public void setPersistent(IBinder token, boolean isPersistent) {
4382 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4383 != PackageManager.PERMISSION_GRANTED) {
4384 String msg = "Permission Denial: setPersistent() from pid="
4385 + Binder.getCallingPid()
4386 + ", uid=" + Binder.getCallingUid()
4387 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4388 Log.w(TAG, msg);
4389 throw new SecurityException(msg);
4390 }
4391
4392 synchronized(this) {
4393 int index = indexOfTokenLocked(token, true);
4394 if (index < 0) {
4395 return;
4396 }
4397 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4398 ProcessRecord app = r.app;
4399
4400 if (localLOGV) Log.v(
4401 TAG, "Setting persistence " + isPersistent + ": " + r);
4402
4403 if (isPersistent) {
4404 if (r.persistent) {
4405 // Okay okay, I heard you already!
4406 if (localLOGV) Log.v(TAG, "Already persistent!");
4407 return;
4408 }
4409 r.persistent = true;
4410 app.persistentActivities++;
4411 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4412 if (app.persistentActivities > 1) {
4413 // We aren't the first...
4414 if (localLOGV) Log.v(TAG, "Not the first!");
4415 return;
4416 }
4417 if (app.persistent) {
4418 // This would be redundant.
4419 if (localLOGV) Log.v(TAG, "App is persistent!");
4420 return;
4421 }
4422
4423 // App is now persistent... make sure it and the ones
4424 // following it now have the correct oom_adj.
4425 final long origId = Binder.clearCallingIdentity();
4426 updateOomAdjLocked();
4427 Binder.restoreCallingIdentity(origId);
4428
4429 } else {
4430 if (!r.persistent) {
4431 // Okay okay, I heard you already!
4432 return;
4433 }
4434 r.persistent = false;
4435 final long origId = Binder.clearCallingIdentity();
4436 decPersistentCountLocked(app);
4437 Binder.restoreCallingIdentity(origId);
4438
4439 }
4440 }
4441 }
4442
4443 public boolean clearApplicationUserData(final String packageName,
4444 final IPackageDataObserver observer) {
4445 int uid = Binder.getCallingUid();
4446 int pid = Binder.getCallingPid();
4447 long callingId = Binder.clearCallingIdentity();
4448 try {
4449 IPackageManager pm = ActivityThread.getPackageManager();
4450 int pkgUid = -1;
4451 synchronized(this) {
4452 try {
4453 pkgUid = pm.getPackageUid(packageName);
4454 } catch (RemoteException e) {
4455 }
4456 if (pkgUid == -1) {
4457 Log.w(TAG, "Invalid packageName:" + packageName);
4458 return false;
4459 }
4460 if (uid == pkgUid || checkComponentPermission(
4461 android.Manifest.permission.CLEAR_APP_USER_DATA,
4462 pid, uid, -1)
4463 == PackageManager.PERMISSION_GRANTED) {
4464 restartPackageLocked(packageName, pkgUid);
4465 } else {
4466 throw new SecurityException(pid+" does not have permission:"+
4467 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4468 "for process:"+packageName);
4469 }
4470 }
4471
4472 try {
4473 //clear application user data
4474 pm.clearApplicationUserData(packageName, observer);
4475 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4476 Uri.fromParts("package", packageName, null));
4477 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4478 broadcastIntentLocked(null, null, intent,
4479 null, null, 0, null, null, null,
4480 false, false, MY_PID, Process.SYSTEM_UID);
4481 } catch (RemoteException e) {
4482 }
4483 } finally {
4484 Binder.restoreCallingIdentity(callingId);
4485 }
4486 return true;
4487 }
4488
4489 public void restartPackage(final String packageName) {
4490 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4491 != PackageManager.PERMISSION_GRANTED) {
4492 String msg = "Permission Denial: restartPackage() from pid="
4493 + Binder.getCallingPid()
4494 + ", uid=" + Binder.getCallingUid()
4495 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4496 Log.w(TAG, msg);
4497 throw new SecurityException(msg);
4498 }
4499
4500 long callingId = Binder.clearCallingIdentity();
4501 try {
4502 IPackageManager pm = ActivityThread.getPackageManager();
4503 int pkgUid = -1;
4504 synchronized(this) {
4505 try {
4506 pkgUid = pm.getPackageUid(packageName);
4507 } catch (RemoteException e) {
4508 }
4509 if (pkgUid == -1) {
4510 Log.w(TAG, "Invalid packageName: " + packageName);
4511 return;
4512 }
4513 restartPackageLocked(packageName, pkgUid);
4514 }
4515 } finally {
4516 Binder.restoreCallingIdentity(callingId);
4517 }
4518 }
4519
4520 private void restartPackageLocked(final String packageName, int uid) {
4521 uninstallPackageLocked(packageName, uid, false);
4522 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4523 Uri.fromParts("package", packageName, null));
4524 intent.putExtra(Intent.EXTRA_UID, uid);
4525 broadcastIntentLocked(null, null, intent,
4526 null, null, 0, null, null, null,
4527 false, false, MY_PID, Process.SYSTEM_UID);
4528 }
4529
4530 private final void uninstallPackageLocked(String name, int uid,
4531 boolean callerWillRestart) {
4532 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4533
4534 int i, N;
4535
4536 final String procNamePrefix = name + ":";
4537 if (uid < 0) {
4538 try {
4539 uid = ActivityThread.getPackageManager().getPackageUid(name);
4540 } catch (RemoteException e) {
4541 }
4542 }
4543
4544 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4545 while (badApps.hasNext()) {
4546 SparseArray<Long> ba = badApps.next();
4547 if (ba.get(uid) != null) {
4548 badApps.remove();
4549 }
4550 }
4551
4552 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4553
4554 // Remove all processes this package may have touched: all with the
4555 // same UID (except for the system or root user), and all whose name
4556 // matches the package name.
4557 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4558 final int NA = apps.size();
4559 for (int ia=0; ia<NA; ia++) {
4560 ProcessRecord app = apps.valueAt(ia);
4561 if (app.removed) {
4562 procs.add(app);
4563 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4564 || app.processName.equals(name)
4565 || app.processName.startsWith(procNamePrefix)) {
4566 app.removed = true;
4567 procs.add(app);
4568 }
4569 }
4570 }
4571
4572 N = procs.size();
4573 for (i=0; i<N; i++) {
4574 removeProcessLocked(procs.get(i), callerWillRestart);
4575 }
4576
4577 for (i=mHistory.size()-1; i>=0; i--) {
4578 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4579 if (r.packageName.equals(name)) {
4580 if (Config.LOGD) Log.d(
4581 TAG, " Force finishing activity "
4582 + r.intent.getComponent().flattenToShortString());
4583 if (r.app != null) {
4584 r.app.removed = true;
4585 }
4586 r.app = null;
4587 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4588 }
4589 }
4590
4591 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4592 for (ServiceRecord service : mServices.values()) {
4593 if (service.packageName.equals(name)) {
4594 if (service.app != null) {
4595 service.app.removed = true;
4596 }
4597 service.app = null;
4598 services.add(service);
4599 }
4600 }
4601
4602 N = services.size();
4603 for (i=0; i<N; i++) {
4604 bringDownServiceLocked(services.get(i), true);
4605 }
4606
4607 resumeTopActivityLocked(null);
4608 }
4609
4610 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4611 final String name = app.processName;
4612 final int uid = app.info.uid;
4613 if (Config.LOGD) Log.d(
4614 TAG, "Force removing process " + app + " (" + name
4615 + "/" + uid + ")");
4616
4617 mProcessNames.remove(name, uid);
4618 boolean needRestart = false;
4619 if (app.pid > 0 && app.pid != MY_PID) {
4620 int pid = app.pid;
4621 synchronized (mPidsSelfLocked) {
4622 mPidsSelfLocked.remove(pid);
4623 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4624 }
4625 handleAppDiedLocked(app, true);
4626 mLRUProcesses.remove(app);
4627 Process.killProcess(pid);
4628
4629 if (app.persistent) {
4630 if (!callerWillRestart) {
4631 addAppLocked(app.info);
4632 } else {
4633 needRestart = true;
4634 }
4635 }
4636 } else {
4637 mRemovedProcesses.add(app);
4638 }
4639
4640 return needRestart;
4641 }
4642
4643 private final void processStartTimedOutLocked(ProcessRecord app) {
4644 final int pid = app.pid;
4645 boolean gone = false;
4646 synchronized (mPidsSelfLocked) {
4647 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4648 if (knownApp != null && knownApp.thread == null) {
4649 mPidsSelfLocked.remove(pid);
4650 gone = true;
4651 }
4652 }
4653
4654 if (gone) {
4655 Log.w(TAG, "Process " + app + " failed to attach");
4656 mProcessNames.remove(app.processName, app.info.uid);
4657 Process.killProcess(pid);
4658 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4659 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4660 mPendingBroadcast = null;
4661 scheduleBroadcastsLocked();
4662 }
4663 } else {
4664 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4665 }
4666 }
4667
4668 private final boolean attachApplicationLocked(IApplicationThread thread,
4669 int pid) {
4670
4671 // Find the application record that is being attached... either via
4672 // the pid if we are running in multiple processes, or just pull the
4673 // next app record if we are emulating process with anonymous threads.
4674 ProcessRecord app;
4675 if (pid != MY_PID && pid >= 0) {
4676 synchronized (mPidsSelfLocked) {
4677 app = mPidsSelfLocked.get(pid);
4678 }
4679 } else if (mStartingProcesses.size() > 0) {
4680 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004681 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 } else {
4683 app = null;
4684 }
4685
4686 if (app == null) {
4687 Log.w(TAG, "No pending application record for pid " + pid
4688 + " (IApplicationThread " + thread + "); dropping process");
4689 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4690 if (pid > 0 && pid != MY_PID) {
4691 Process.killProcess(pid);
4692 } else {
4693 try {
4694 thread.scheduleExit();
4695 } catch (Exception e) {
4696 // Ignore exceptions.
4697 }
4698 }
4699 return false;
4700 }
4701
4702 // If this application record is still attached to a previous
4703 // process, clean it up now.
4704 if (app.thread != null) {
4705 handleAppDiedLocked(app, true);
4706 }
4707
4708 // Tell the process all about itself.
4709
4710 if (localLOGV) Log.v(
4711 TAG, "Binding process pid " + pid + " to record " + app);
4712
4713 String processName = app.processName;
4714 try {
4715 thread.asBinder().linkToDeath(new AppDeathRecipient(
4716 app, pid, thread), 0);
4717 } catch (RemoteException e) {
4718 app.resetPackageList();
4719 startProcessLocked(app, "link fail", processName);
4720 return false;
4721 }
4722
4723 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4724
4725 app.thread = thread;
4726 app.curAdj = app.setAdj = -100;
4727 app.forcingToForeground = null;
4728 app.foregroundServices = false;
4729 app.debugging = false;
4730
4731 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4732
4733 List providers = generateApplicationProvidersLocked(app);
4734
4735 if (localLOGV) Log.v(
4736 TAG, "New app record " + app
4737 + " thread=" + thread.asBinder() + " pid=" + pid);
4738 try {
4739 int testMode = IApplicationThread.DEBUG_OFF;
4740 if (mDebugApp != null && mDebugApp.equals(processName)) {
4741 testMode = mWaitForDebugger
4742 ? IApplicationThread.DEBUG_WAIT
4743 : IApplicationThread.DEBUG_ON;
4744 app.debugging = true;
4745 if (mDebugTransient) {
4746 mDebugApp = mOrigDebugApp;
4747 mWaitForDebugger = mOrigWaitForDebugger;
4748 }
4749 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004750 thread.bindApplication(processName, app.instrumentationInfo != null
4751 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 app.instrumentationClass, app.instrumentationProfileFile,
4753 app.instrumentationArguments, app.instrumentationWatcher, testMode,
4754 mConfiguration, getCommonServicesLocked());
4755 updateLRUListLocked(app, false);
4756 app.lastRequestedGc = SystemClock.uptimeMillis();
4757 } catch (Exception e) {
4758 // todo: Yikes! What should we do? For now we will try to
4759 // start another process, but that could easily get us in
4760 // an infinite loop of restarting processes...
4761 Log.w(TAG, "Exception thrown during bind!", e);
4762
4763 app.resetPackageList();
4764 startProcessLocked(app, "bind fail", processName);
4765 return false;
4766 }
4767
4768 // Remove this record from the list of starting applications.
4769 mPersistentStartingProcesses.remove(app);
4770 mProcessesOnHold.remove(app);
4771
4772 boolean badApp = false;
4773 boolean didSomething = false;
4774
4775 // See if the top visible activity is waiting to run in this process...
4776 HistoryRecord hr = topRunningActivityLocked(null);
4777 if (hr != null) {
4778 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4779 && processName.equals(hr.processName)) {
4780 try {
4781 if (realStartActivityLocked(hr, app, true, true)) {
4782 didSomething = true;
4783 }
4784 } catch (Exception e) {
4785 Log.w(TAG, "Exception in new application when starting activity "
4786 + hr.intent.getComponent().flattenToShortString(), e);
4787 badApp = true;
4788 }
4789 } else {
4790 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4791 }
4792 }
4793
4794 // Find any services that should be running in this process...
4795 if (!badApp && mPendingServices.size() > 0) {
4796 ServiceRecord sr = null;
4797 try {
4798 for (int i=0; i<mPendingServices.size(); i++) {
4799 sr = mPendingServices.get(i);
4800 if (app.info.uid != sr.appInfo.uid
4801 || !processName.equals(sr.processName)) {
4802 continue;
4803 }
4804
4805 mPendingServices.remove(i);
4806 i--;
4807 realStartServiceLocked(sr, app);
4808 didSomething = true;
4809 }
4810 } catch (Exception e) {
4811 Log.w(TAG, "Exception in new application when starting service "
4812 + sr.shortName, e);
4813 badApp = true;
4814 }
4815 }
4816
4817 // Check if the next broadcast receiver is in this process...
4818 BroadcastRecord br = mPendingBroadcast;
4819 if (!badApp && br != null && br.curApp == app) {
4820 try {
4821 mPendingBroadcast = null;
4822 processCurBroadcastLocked(br, app);
4823 didSomething = true;
4824 } catch (Exception e) {
4825 Log.w(TAG, "Exception in new application when starting receiver "
4826 + br.curComponent.flattenToShortString(), e);
4827 badApp = true;
4828 logBroadcastReceiverDiscard(br);
4829 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4830 br.resultExtras, br.resultAbort, true);
4831 scheduleBroadcastsLocked();
4832 }
4833 }
4834
4835 if (badApp) {
4836 // todo: Also need to kill application to deal with all
4837 // kinds of exceptions.
4838 handleAppDiedLocked(app, false);
4839 return false;
4840 }
4841
4842 if (!didSomething) {
4843 updateOomAdjLocked();
4844 }
4845
4846 return true;
4847 }
4848
4849 public final void attachApplication(IApplicationThread thread) {
4850 synchronized (this) {
4851 int callingPid = Binder.getCallingPid();
4852 final long origId = Binder.clearCallingIdentity();
4853 attachApplicationLocked(thread, callingPid);
4854 Binder.restoreCallingIdentity(origId);
4855 }
4856 }
4857
4858 public final void activityIdle(IBinder token) {
4859 final long origId = Binder.clearCallingIdentity();
4860 activityIdleInternal(token, false);
4861 Binder.restoreCallingIdentity(origId);
4862 }
4863
4864 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4865 boolean remove) {
4866 int N = mStoppingActivities.size();
4867 if (N <= 0) return null;
4868
4869 ArrayList<HistoryRecord> stops = null;
4870
4871 final boolean nowVisible = mResumedActivity != null
4872 && mResumedActivity.nowVisible
4873 && !mResumedActivity.waitingVisible;
4874 for (int i=0; i<N; i++) {
4875 HistoryRecord s = mStoppingActivities.get(i);
4876 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4877 + nowVisible + " waitingVisible=" + s.waitingVisible
4878 + " finishing=" + s.finishing);
4879 if (s.waitingVisible && nowVisible) {
4880 mWaitingVisibleActivities.remove(s);
4881 s.waitingVisible = false;
4882 if (s.finishing) {
4883 // If this activity is finishing, it is sitting on top of
4884 // everyone else but we now know it is no longer needed...
4885 // so get rid of it. Otherwise, we need to go through the
4886 // normal flow and hide it once we determine that it is
4887 // hidden by the activities in front of it.
4888 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4889 mWindowManager.setAppVisibility(s, false);
4890 }
4891 }
4892 if (!s.waitingVisible && remove) {
4893 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4894 if (stops == null) {
4895 stops = new ArrayList<HistoryRecord>();
4896 }
4897 stops.add(s);
4898 mStoppingActivities.remove(i);
4899 N--;
4900 i--;
4901 }
4902 }
4903
4904 return stops;
4905 }
4906
4907 void enableScreenAfterBoot() {
4908 mWindowManager.enableScreenAfterBoot();
4909 }
4910
4911 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4912 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4913
4914 ArrayList<HistoryRecord> stops = null;
4915 ArrayList<HistoryRecord> finishes = null;
4916 ArrayList<HistoryRecord> thumbnails = null;
4917 int NS = 0;
4918 int NF = 0;
4919 int NT = 0;
4920 IApplicationThread sendThumbnail = null;
4921 boolean booting = false;
4922 boolean enableScreen = false;
4923
4924 synchronized (this) {
4925 if (token != null) {
4926 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
4927 }
4928
4929 // Get the activity record.
4930 int index = indexOfTokenLocked(token, false);
4931 if (index >= 0) {
4932 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4933
4934 // No longer need to keep the device awake.
4935 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
4936 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
4937 mLaunchingActivity.release();
4938 }
4939
4940 // We are now idle. If someone is waiting for a thumbnail from
4941 // us, we can now deliver.
4942 r.idle = true;
4943 scheduleAppGcsLocked();
4944 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
4945 sendThumbnail = r.app.thread;
4946 r.thumbnailNeeded = false;
4947 }
4948
4949 // If this activity is fullscreen, set up to hide those under it.
4950
4951 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
4952 ensureActivitiesVisibleLocked(null, 0);
4953
4954 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
4955 if (!mBooted && !fromTimeout) {
4956 mBooted = true;
4957 enableScreen = true;
4958 }
4959 }
4960
4961 // Atomically retrieve all of the other things to do.
4962 stops = processStoppingActivitiesLocked(true);
4963 NS = stops != null ? stops.size() : 0;
4964 if ((NF=mFinishingActivities.size()) > 0) {
4965 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
4966 mFinishingActivities.clear();
4967 }
4968 if ((NT=mCancelledThumbnails.size()) > 0) {
4969 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
4970 mCancelledThumbnails.clear();
4971 }
4972
4973 booting = mBooting;
4974 mBooting = false;
4975 }
4976
4977 int i;
4978
4979 // Send thumbnail if requested.
4980 if (sendThumbnail != null) {
4981 try {
4982 sendThumbnail.requestThumbnail(token);
4983 } catch (Exception e) {
4984 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
4985 sendPendingThumbnail(null, token, null, null, true);
4986 }
4987 }
4988
4989 // Stop any activities that are scheduled to do so but have been
4990 // waiting for the next one to start.
4991 for (i=0; i<NS; i++) {
4992 HistoryRecord r = (HistoryRecord)stops.get(i);
4993 synchronized (this) {
4994 if (r.finishing) {
4995 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
4996 } else {
4997 stopActivityLocked(r);
4998 }
4999 }
5000 }
5001
5002 // Finish any activities that are scheduled to do so but have been
5003 // waiting for the next one to start.
5004 for (i=0; i<NF; i++) {
5005 HistoryRecord r = (HistoryRecord)finishes.get(i);
5006 synchronized (this) {
5007 destroyActivityLocked(r, true);
5008 }
5009 }
5010
5011 // Report back to any thumbnail receivers.
5012 for (i=0; i<NT; i++) {
5013 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5014 sendPendingThumbnail(r, null, null, null, true);
5015 }
5016
5017 if (booting) {
5018 // Ensure that any processes we had put on hold are now started
5019 // up.
5020 final int NP = mProcessesOnHold.size();
5021 if (NP > 0) {
5022 ArrayList<ProcessRecord> procs =
5023 new ArrayList<ProcessRecord>(mProcessesOnHold);
5024 for (int ip=0; ip<NP; ip++) {
5025 this.startProcessLocked(procs.get(ip), "on-hold", null);
5026 }
5027 }
5028 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5029 // Tell anyone interested that we are done booting!
5030 synchronized (this) {
5031 broadcastIntentLocked(null, null,
5032 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5033 null, null, 0, null, null,
5034 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5035 false, false, MY_PID, Process.SYSTEM_UID);
5036 }
5037 }
5038 }
5039
5040 trimApplications();
5041 //dump();
5042 //mWindowManager.dump();
5043
5044 if (enableScreen) {
5045 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5046 SystemClock.uptimeMillis());
5047 enableScreenAfterBoot();
5048 }
5049 }
5050
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005051 final void ensureScreenEnabled() {
5052 boolean enableScreen;
5053 synchronized (this) {
5054 enableScreen = !mBooted;
5055 mBooted = true;
5056 }
5057
5058 if (enableScreen) {
5059 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5060 SystemClock.uptimeMillis());
5061 enableScreenAfterBoot();
5062 }
5063 }
5064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005065 public final void activityPaused(IBinder token, Bundle icicle) {
5066 // Refuse possible leaked file descriptors
5067 if (icicle != null && icicle.hasFileDescriptors()) {
5068 throw new IllegalArgumentException("File descriptors passed in Bundle");
5069 }
5070
5071 final long origId = Binder.clearCallingIdentity();
5072 activityPaused(token, icicle, false);
5073 Binder.restoreCallingIdentity(origId);
5074 }
5075
5076 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5077 if (DEBUG_PAUSE) Log.v(
5078 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5079 + ", timeout=" + timeout);
5080
5081 HistoryRecord r = null;
5082
5083 synchronized (this) {
5084 int index = indexOfTokenLocked(token, false);
5085 if (index >= 0) {
5086 r = (HistoryRecord)mHistory.get(index);
5087 if (!timeout) {
5088 r.icicle = icicle;
5089 r.haveState = true;
5090 }
5091 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5092 if (mPausingActivity == r) {
5093 r.state = ActivityState.PAUSED;
5094 completePauseLocked();
5095 } else {
5096 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5097 System.identityHashCode(r), r.shortComponentName,
5098 mPausingActivity != null
5099 ? mPausingActivity.shortComponentName : "(none)");
5100 }
5101 }
5102 }
5103 }
5104
5105 public final void activityStopped(IBinder token, Bitmap thumbnail,
5106 CharSequence description) {
5107 if (localLOGV) Log.v(
5108 TAG, "Activity stopped: token=" + token);
5109
5110 HistoryRecord r = null;
5111
5112 final long origId = Binder.clearCallingIdentity();
5113
5114 synchronized (this) {
5115 int index = indexOfTokenLocked(token, false);
5116 if (index >= 0) {
5117 r = (HistoryRecord)mHistory.get(index);
5118 r.thumbnail = thumbnail;
5119 r.description = description;
5120 r.stopped = true;
5121 r.state = ActivityState.STOPPED;
5122 if (!r.finishing) {
5123 if (r.configDestroy) {
5124 destroyActivityLocked(r, true);
5125 resumeTopActivityLocked(null);
5126 }
5127 }
5128 }
5129 }
5130
5131 if (r != null) {
5132 sendPendingThumbnail(r, null, null, null, false);
5133 }
5134
5135 trimApplications();
5136
5137 Binder.restoreCallingIdentity(origId);
5138 }
5139
5140 public final void activityDestroyed(IBinder token) {
5141 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5142 synchronized (this) {
5143 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5144
5145 int index = indexOfTokenLocked(token, false);
5146 if (index >= 0) {
5147 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5148 if (r.state == ActivityState.DESTROYING) {
5149 final long origId = Binder.clearCallingIdentity();
5150 removeActivityFromHistoryLocked(r);
5151 Binder.restoreCallingIdentity(origId);
5152 }
5153 }
5154 }
5155 }
5156
5157 public String getCallingPackage(IBinder token) {
5158 synchronized (this) {
5159 HistoryRecord r = getCallingRecordLocked(token);
5160 return r != null && r.app != null ? r.app.processName : null;
5161 }
5162 }
5163
5164 public ComponentName getCallingActivity(IBinder token) {
5165 synchronized (this) {
5166 HistoryRecord r = getCallingRecordLocked(token);
5167 return r != null ? r.intent.getComponent() : null;
5168 }
5169 }
5170
5171 private HistoryRecord getCallingRecordLocked(IBinder token) {
5172 int index = indexOfTokenLocked(token, true);
5173 if (index >= 0) {
5174 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5175 if (r != null) {
5176 return r.resultTo;
5177 }
5178 }
5179 return null;
5180 }
5181
5182 public ComponentName getActivityClassForToken(IBinder token) {
5183 synchronized(this) {
5184 int index = indexOfTokenLocked(token, false);
5185 if (index >= 0) {
5186 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5187 return r.intent.getComponent();
5188 }
5189 return null;
5190 }
5191 }
5192
5193 public String getPackageForToken(IBinder token) {
5194 synchronized(this) {
5195 int index = indexOfTokenLocked(token, false);
5196 if (index >= 0) {
5197 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5198 return r.packageName;
5199 }
5200 return null;
5201 }
5202 }
5203
5204 public IIntentSender getIntentSender(int type,
5205 String packageName, IBinder token, String resultWho,
5206 int requestCode, Intent intent, String resolvedType, int flags) {
5207 // Refuse possible leaked file descriptors
5208 if (intent != null && intent.hasFileDescriptors() == true) {
5209 throw new IllegalArgumentException("File descriptors passed in Intent");
5210 }
5211
5212 synchronized(this) {
5213 int callingUid = Binder.getCallingUid();
5214 try {
5215 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5216 Process.supportsProcesses()) {
5217 int uid = ActivityThread.getPackageManager()
5218 .getPackageUid(packageName);
5219 if (uid != Binder.getCallingUid()) {
5220 String msg = "Permission Denial: getIntentSender() from pid="
5221 + Binder.getCallingPid()
5222 + ", uid=" + Binder.getCallingUid()
5223 + ", (need uid=" + uid + ")"
5224 + " is not allowed to send as package " + packageName;
5225 Log.w(TAG, msg);
5226 throw new SecurityException(msg);
5227 }
5228 }
5229 } catch (RemoteException e) {
5230 throw new SecurityException(e);
5231 }
5232 HistoryRecord activity = null;
5233 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5234 int index = indexOfTokenLocked(token, false);
5235 if (index < 0) {
5236 return null;
5237 }
5238 activity = (HistoryRecord)mHistory.get(index);
5239 if (activity.finishing) {
5240 return null;
5241 }
5242 }
5243
5244 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5245 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5246 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5247 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5248 |PendingIntent.FLAG_UPDATE_CURRENT);
5249
5250 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5251 type, packageName, activity, resultWho,
5252 requestCode, intent, resolvedType, flags);
5253 WeakReference<PendingIntentRecord> ref;
5254 ref = mIntentSenderRecords.get(key);
5255 PendingIntentRecord rec = ref != null ? ref.get() : null;
5256 if (rec != null) {
5257 if (!cancelCurrent) {
5258 if (updateCurrent) {
5259 rec.key.requestIntent.replaceExtras(intent);
5260 }
5261 return rec;
5262 }
5263 rec.canceled = true;
5264 mIntentSenderRecords.remove(key);
5265 }
5266 if (noCreate) {
5267 return rec;
5268 }
5269 rec = new PendingIntentRecord(this, key, callingUid);
5270 mIntentSenderRecords.put(key, rec.ref);
5271 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5272 if (activity.pendingResults == null) {
5273 activity.pendingResults
5274 = new HashSet<WeakReference<PendingIntentRecord>>();
5275 }
5276 activity.pendingResults.add(rec.ref);
5277 }
5278 return rec;
5279 }
5280 }
5281
5282 public void cancelIntentSender(IIntentSender sender) {
5283 if (!(sender instanceof PendingIntentRecord)) {
5284 return;
5285 }
5286 synchronized(this) {
5287 PendingIntentRecord rec = (PendingIntentRecord)sender;
5288 try {
5289 int uid = ActivityThread.getPackageManager()
5290 .getPackageUid(rec.key.packageName);
5291 if (uid != Binder.getCallingUid()) {
5292 String msg = "Permission Denial: cancelIntentSender() from pid="
5293 + Binder.getCallingPid()
5294 + ", uid=" + Binder.getCallingUid()
5295 + " is not allowed to cancel packges "
5296 + rec.key.packageName;
5297 Log.w(TAG, msg);
5298 throw new SecurityException(msg);
5299 }
5300 } catch (RemoteException e) {
5301 throw new SecurityException(e);
5302 }
5303 cancelIntentSenderLocked(rec, true);
5304 }
5305 }
5306
5307 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5308 rec.canceled = true;
5309 mIntentSenderRecords.remove(rec.key);
5310 if (cleanActivity && rec.key.activity != null) {
5311 rec.key.activity.pendingResults.remove(rec.ref);
5312 }
5313 }
5314
5315 public String getPackageForIntentSender(IIntentSender pendingResult) {
5316 if (!(pendingResult instanceof PendingIntentRecord)) {
5317 return null;
5318 }
5319 synchronized(this) {
5320 try {
5321 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5322 return res.key.packageName;
5323 } catch (ClassCastException e) {
5324 }
5325 }
5326 return null;
5327 }
5328
5329 public void setProcessLimit(int max) {
5330 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5331 "setProcessLimit()");
5332 mProcessLimit = max;
5333 }
5334
5335 public int getProcessLimit() {
5336 return mProcessLimit;
5337 }
5338
5339 void foregroundTokenDied(ForegroundToken token) {
5340 synchronized (ActivityManagerService.this) {
5341 synchronized (mPidsSelfLocked) {
5342 ForegroundToken cur
5343 = mForegroundProcesses.get(token.pid);
5344 if (cur != token) {
5345 return;
5346 }
5347 mForegroundProcesses.remove(token.pid);
5348 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5349 if (pr == null) {
5350 return;
5351 }
5352 pr.forcingToForeground = null;
5353 pr.foregroundServices = false;
5354 }
5355 updateOomAdjLocked();
5356 }
5357 }
5358
5359 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5360 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5361 "setProcessForeground()");
5362 synchronized(this) {
5363 boolean changed = false;
5364
5365 synchronized (mPidsSelfLocked) {
5366 ProcessRecord pr = mPidsSelfLocked.get(pid);
5367 if (pr == null) {
5368 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5369 return;
5370 }
5371 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5372 if (oldToken != null) {
5373 oldToken.token.unlinkToDeath(oldToken, 0);
5374 mForegroundProcesses.remove(pid);
5375 pr.forcingToForeground = null;
5376 changed = true;
5377 }
5378 if (isForeground && token != null) {
5379 ForegroundToken newToken = new ForegroundToken() {
5380 public void binderDied() {
5381 foregroundTokenDied(this);
5382 }
5383 };
5384 newToken.pid = pid;
5385 newToken.token = token;
5386 try {
5387 token.linkToDeath(newToken, 0);
5388 mForegroundProcesses.put(pid, newToken);
5389 pr.forcingToForeground = token;
5390 changed = true;
5391 } catch (RemoteException e) {
5392 // If the process died while doing this, we will later
5393 // do the cleanup with the process death link.
5394 }
5395 }
5396 }
5397
5398 if (changed) {
5399 updateOomAdjLocked();
5400 }
5401 }
5402 }
5403
5404 // =========================================================
5405 // PERMISSIONS
5406 // =========================================================
5407
5408 static class PermissionController extends IPermissionController.Stub {
5409 ActivityManagerService mActivityManagerService;
5410 PermissionController(ActivityManagerService activityManagerService) {
5411 mActivityManagerService = activityManagerService;
5412 }
5413
5414 public boolean checkPermission(String permission, int pid, int uid) {
5415 return mActivityManagerService.checkPermission(permission, pid,
5416 uid) == PackageManager.PERMISSION_GRANTED;
5417 }
5418 }
5419
5420 /**
5421 * This can be called with or without the global lock held.
5422 */
5423 int checkComponentPermission(String permission, int pid, int uid,
5424 int reqUid) {
5425 // We might be performing an operation on behalf of an indirect binder
5426 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5427 // client identity accordingly before proceeding.
5428 Identity tlsIdentity = sCallerIdentity.get();
5429 if (tlsIdentity != null) {
5430 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5431 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5432 uid = tlsIdentity.uid;
5433 pid = tlsIdentity.pid;
5434 }
5435
5436 // Root, system server and our own process get to do everything.
5437 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5438 !Process.supportsProcesses()) {
5439 return PackageManager.PERMISSION_GRANTED;
5440 }
5441 // If the target requires a specific UID, always fail for others.
5442 if (reqUid >= 0 && uid != reqUid) {
5443 return PackageManager.PERMISSION_DENIED;
5444 }
5445 if (permission == null) {
5446 return PackageManager.PERMISSION_GRANTED;
5447 }
5448 try {
5449 return ActivityThread.getPackageManager()
5450 .checkUidPermission(permission, uid);
5451 } catch (RemoteException e) {
5452 // Should never happen, but if it does... deny!
5453 Log.e(TAG, "PackageManager is dead?!?", e);
5454 }
5455 return PackageManager.PERMISSION_DENIED;
5456 }
5457
5458 /**
5459 * As the only public entry point for permissions checking, this method
5460 * can enforce the semantic that requesting a check on a null global
5461 * permission is automatically denied. (Internally a null permission
5462 * string is used when calling {@link #checkComponentPermission} in cases
5463 * when only uid-based security is needed.)
5464 *
5465 * This can be called with or without the global lock held.
5466 */
5467 public int checkPermission(String permission, int pid, int uid) {
5468 if (permission == null) {
5469 return PackageManager.PERMISSION_DENIED;
5470 }
5471 return checkComponentPermission(permission, pid, uid, -1);
5472 }
5473
5474 /**
5475 * Binder IPC calls go through the public entry point.
5476 * This can be called with or without the global lock held.
5477 */
5478 int checkCallingPermission(String permission) {
5479 return checkPermission(permission,
5480 Binder.getCallingPid(),
5481 Binder.getCallingUid());
5482 }
5483
5484 /**
5485 * This can be called with or without the global lock held.
5486 */
5487 void enforceCallingPermission(String permission, String func) {
5488 if (checkCallingPermission(permission)
5489 == PackageManager.PERMISSION_GRANTED) {
5490 return;
5491 }
5492
5493 String msg = "Permission Denial: " + func + " from pid="
5494 + Binder.getCallingPid()
5495 + ", uid=" + Binder.getCallingUid()
5496 + " requires " + permission;
5497 Log.w(TAG, msg);
5498 throw new SecurityException(msg);
5499 }
5500
5501 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5502 ProviderInfo pi, int uid, int modeFlags) {
5503 try {
5504 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5505 if ((pi.readPermission != null) &&
5506 (pm.checkUidPermission(pi.readPermission, uid)
5507 != PackageManager.PERMISSION_GRANTED)) {
5508 return false;
5509 }
5510 }
5511 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5512 if ((pi.writePermission != null) &&
5513 (pm.checkUidPermission(pi.writePermission, uid)
5514 != PackageManager.PERMISSION_GRANTED)) {
5515 return false;
5516 }
5517 }
5518 return true;
5519 } catch (RemoteException e) {
5520 return false;
5521 }
5522 }
5523
5524 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5525 int modeFlags) {
5526 // Root gets to do everything.
5527 if (uid == 0 || !Process.supportsProcesses()) {
5528 return true;
5529 }
5530 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5531 if (perms == null) return false;
5532 UriPermission perm = perms.get(uri);
5533 if (perm == null) return false;
5534 return (modeFlags&perm.modeFlags) == modeFlags;
5535 }
5536
5537 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5538 // Another redirected-binder-call permissions check as in
5539 // {@link checkComponentPermission}.
5540 Identity tlsIdentity = sCallerIdentity.get();
5541 if (tlsIdentity != null) {
5542 uid = tlsIdentity.uid;
5543 pid = tlsIdentity.pid;
5544 }
5545
5546 // Our own process gets to do everything.
5547 if (pid == MY_PID) {
5548 return PackageManager.PERMISSION_GRANTED;
5549 }
5550 synchronized(this) {
5551 return checkUriPermissionLocked(uri, uid, modeFlags)
5552 ? PackageManager.PERMISSION_GRANTED
5553 : PackageManager.PERMISSION_DENIED;
5554 }
5555 }
5556
5557 private void grantUriPermissionLocked(int callingUid,
5558 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5559 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5560 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5561 if (modeFlags == 0) {
5562 return;
5563 }
5564
5565 final IPackageManager pm = ActivityThread.getPackageManager();
5566
5567 // If this is not a content: uri, we can't do anything with it.
5568 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5569 return;
5570 }
5571
5572 String name = uri.getAuthority();
5573 ProviderInfo pi = null;
5574 ContentProviderRecord cpr
5575 = (ContentProviderRecord)mProvidersByName.get(name);
5576 if (cpr != null) {
5577 pi = cpr.info;
5578 } else {
5579 try {
5580 pi = pm.resolveContentProvider(name,
5581 PackageManager.GET_URI_PERMISSION_PATTERNS);
5582 } catch (RemoteException ex) {
5583 }
5584 }
5585 if (pi == null) {
5586 Log.w(TAG, "No content provider found for: " + name);
5587 return;
5588 }
5589
5590 int targetUid;
5591 try {
5592 targetUid = pm.getPackageUid(targetPkg);
5593 if (targetUid < 0) {
5594 return;
5595 }
5596 } catch (RemoteException ex) {
5597 return;
5598 }
5599
5600 // First... does the target actually need this permission?
5601 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5602 // No need to grant the target this permission.
5603 return;
5604 }
5605
5606 // Second... maybe someone else has already granted the
5607 // permission?
5608 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5609 // No need to grant the target this permission.
5610 return;
5611 }
5612
5613 // Third... is the provider allowing granting of URI permissions?
5614 if (!pi.grantUriPermissions) {
5615 throw new SecurityException("Provider " + pi.packageName
5616 + "/" + pi.name
5617 + " does not allow granting of Uri permissions (uri "
5618 + uri + ")");
5619 }
5620 if (pi.uriPermissionPatterns != null) {
5621 final int N = pi.uriPermissionPatterns.length;
5622 boolean allowed = false;
5623 for (int i=0; i<N; i++) {
5624 if (pi.uriPermissionPatterns[i] != null
5625 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5626 allowed = true;
5627 break;
5628 }
5629 }
5630 if (!allowed) {
5631 throw new SecurityException("Provider " + pi.packageName
5632 + "/" + pi.name
5633 + " does not allow granting of permission to path of Uri "
5634 + uri);
5635 }
5636 }
5637
5638 // Fourth... does the caller itself have permission to access
5639 // this uri?
5640 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5641 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5642 throw new SecurityException("Uid " + callingUid
5643 + " does not have permission to uri " + uri);
5644 }
5645 }
5646
5647 // Okay! So here we are: the caller has the assumed permission
5648 // to the uri, and the target doesn't. Let's now give this to
5649 // the target.
5650
5651 HashMap<Uri, UriPermission> targetUris
5652 = mGrantedUriPermissions.get(targetUid);
5653 if (targetUris == null) {
5654 targetUris = new HashMap<Uri, UriPermission>();
5655 mGrantedUriPermissions.put(targetUid, targetUris);
5656 }
5657
5658 UriPermission perm = targetUris.get(uri);
5659 if (perm == null) {
5660 perm = new UriPermission(targetUid, uri);
5661 targetUris.put(uri, perm);
5662
5663 }
5664 perm.modeFlags |= modeFlags;
5665 if (activity == null) {
5666 perm.globalModeFlags |= modeFlags;
5667 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5668 perm.readActivities.add(activity);
5669 if (activity.readUriPermissions == null) {
5670 activity.readUriPermissions = new HashSet<UriPermission>();
5671 }
5672 activity.readUriPermissions.add(perm);
5673 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5674 perm.writeActivities.add(activity);
5675 if (activity.writeUriPermissions == null) {
5676 activity.writeUriPermissions = new HashSet<UriPermission>();
5677 }
5678 activity.writeUriPermissions.add(perm);
5679 }
5680 }
5681
5682 private void grantUriPermissionFromIntentLocked(int callingUid,
5683 String targetPkg, Intent intent, HistoryRecord activity) {
5684 if (intent == null) {
5685 return;
5686 }
5687 Uri data = intent.getData();
5688 if (data == null) {
5689 return;
5690 }
5691 grantUriPermissionLocked(callingUid, targetPkg, data,
5692 intent.getFlags(), activity);
5693 }
5694
5695 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5696 Uri uri, int modeFlags) {
5697 synchronized(this) {
5698 final ProcessRecord r = getRecordForAppLocked(caller);
5699 if (r == null) {
5700 throw new SecurityException("Unable to find app for caller "
5701 + caller
5702 + " when granting permission to uri " + uri);
5703 }
5704 if (targetPkg == null) {
5705 Log.w(TAG, "grantUriPermission: null target");
5706 return;
5707 }
5708 if (uri == null) {
5709 Log.w(TAG, "grantUriPermission: null uri");
5710 return;
5711 }
5712
5713 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5714 null);
5715 }
5716 }
5717
5718 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5719 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5720 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5721 HashMap<Uri, UriPermission> perms
5722 = mGrantedUriPermissions.get(perm.uid);
5723 if (perms != null) {
5724 perms.remove(perm.uri);
5725 if (perms.size() == 0) {
5726 mGrantedUriPermissions.remove(perm.uid);
5727 }
5728 }
5729 }
5730 }
5731
5732 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5733 if (activity.readUriPermissions != null) {
5734 for (UriPermission perm : activity.readUriPermissions) {
5735 perm.readActivities.remove(activity);
5736 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5737 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5738 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5739 removeUriPermissionIfNeededLocked(perm);
5740 }
5741 }
5742 }
5743 if (activity.writeUriPermissions != null) {
5744 for (UriPermission perm : activity.writeUriPermissions) {
5745 perm.writeActivities.remove(activity);
5746 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5747 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5748 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5749 removeUriPermissionIfNeededLocked(perm);
5750 }
5751 }
5752 }
5753 }
5754
5755 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5756 int modeFlags) {
5757 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5758 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5759 if (modeFlags == 0) {
5760 return;
5761 }
5762
5763 final IPackageManager pm = ActivityThread.getPackageManager();
5764
5765 final String authority = uri.getAuthority();
5766 ProviderInfo pi = null;
5767 ContentProviderRecord cpr
5768 = (ContentProviderRecord)mProvidersByName.get(authority);
5769 if (cpr != null) {
5770 pi = cpr.info;
5771 } else {
5772 try {
5773 pi = pm.resolveContentProvider(authority,
5774 PackageManager.GET_URI_PERMISSION_PATTERNS);
5775 } catch (RemoteException ex) {
5776 }
5777 }
5778 if (pi == null) {
5779 Log.w(TAG, "No content provider found for: " + authority);
5780 return;
5781 }
5782
5783 // Does the caller have this permission on the URI?
5784 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5785 // Right now, if you are not the original owner of the permission,
5786 // you are not allowed to revoke it.
5787 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5788 throw new SecurityException("Uid " + callingUid
5789 + " does not have permission to uri " + uri);
5790 //}
5791 }
5792
5793 // Go through all of the permissions and remove any that match.
5794 final List<String> SEGMENTS = uri.getPathSegments();
5795 if (SEGMENTS != null) {
5796 final int NS = SEGMENTS.size();
5797 int N = mGrantedUriPermissions.size();
5798 for (int i=0; i<N; i++) {
5799 HashMap<Uri, UriPermission> perms
5800 = mGrantedUriPermissions.valueAt(i);
5801 Iterator<UriPermission> it = perms.values().iterator();
5802 toploop:
5803 while (it.hasNext()) {
5804 UriPermission perm = it.next();
5805 Uri targetUri = perm.uri;
5806 if (!authority.equals(targetUri.getAuthority())) {
5807 continue;
5808 }
5809 List<String> targetSegments = targetUri.getPathSegments();
5810 if (targetSegments == null) {
5811 continue;
5812 }
5813 if (targetSegments.size() < NS) {
5814 continue;
5815 }
5816 for (int j=0; j<NS; j++) {
5817 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5818 continue toploop;
5819 }
5820 }
5821 perm.clearModes(modeFlags);
5822 if (perm.modeFlags == 0) {
5823 it.remove();
5824 }
5825 }
5826 if (perms.size() == 0) {
5827 mGrantedUriPermissions.remove(
5828 mGrantedUriPermissions.keyAt(i));
5829 N--;
5830 i--;
5831 }
5832 }
5833 }
5834 }
5835
5836 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5837 int modeFlags) {
5838 synchronized(this) {
5839 final ProcessRecord r = getRecordForAppLocked(caller);
5840 if (r == null) {
5841 throw new SecurityException("Unable to find app for caller "
5842 + caller
5843 + " when revoking permission to uri " + uri);
5844 }
5845 if (uri == null) {
5846 Log.w(TAG, "revokeUriPermission: null uri");
5847 return;
5848 }
5849
5850 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5851 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5852 if (modeFlags == 0) {
5853 return;
5854 }
5855
5856 final IPackageManager pm = ActivityThread.getPackageManager();
5857
5858 final String authority = uri.getAuthority();
5859 ProviderInfo pi = null;
5860 ContentProviderRecord cpr
5861 = (ContentProviderRecord)mProvidersByName.get(authority);
5862 if (cpr != null) {
5863 pi = cpr.info;
5864 } else {
5865 try {
5866 pi = pm.resolveContentProvider(authority,
5867 PackageManager.GET_URI_PERMISSION_PATTERNS);
5868 } catch (RemoteException ex) {
5869 }
5870 }
5871 if (pi == null) {
5872 Log.w(TAG, "No content provider found for: " + authority);
5873 return;
5874 }
5875
5876 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5877 }
5878 }
5879
5880 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5881 synchronized (this) {
5882 ProcessRecord app =
5883 who != null ? getRecordForAppLocked(who) : null;
5884 if (app == null) return;
5885
5886 Message msg = Message.obtain();
5887 msg.what = WAIT_FOR_DEBUGGER_MSG;
5888 msg.obj = app;
5889 msg.arg1 = waiting ? 1 : 0;
5890 mHandler.sendMessage(msg);
5891 }
5892 }
5893
5894 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5895 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005896 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005897 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005898 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005899 }
5900
5901 // =========================================================
5902 // TASK MANAGEMENT
5903 // =========================================================
5904
5905 public List getTasks(int maxNum, int flags,
5906 IThumbnailReceiver receiver) {
5907 ArrayList list = new ArrayList();
5908
5909 PendingThumbnailsRecord pending = null;
5910 IApplicationThread topThumbnail = null;
5911 HistoryRecord topRecord = null;
5912
5913 synchronized(this) {
5914 if (localLOGV) Log.v(
5915 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
5916 + ", receiver=" + receiver);
5917
5918 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
5919 != PackageManager.PERMISSION_GRANTED) {
5920 if (receiver != null) {
5921 // If the caller wants to wait for pending thumbnails,
5922 // it ain't gonna get them.
5923 try {
5924 receiver.finished();
5925 } catch (RemoteException ex) {
5926 }
5927 }
5928 String msg = "Permission Denial: getTasks() from pid="
5929 + Binder.getCallingPid()
5930 + ", uid=" + Binder.getCallingUid()
5931 + " requires " + android.Manifest.permission.GET_TASKS;
5932 Log.w(TAG, msg);
5933 throw new SecurityException(msg);
5934 }
5935
5936 int pos = mHistory.size()-1;
5937 HistoryRecord next =
5938 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5939 HistoryRecord top = null;
5940 CharSequence topDescription = null;
5941 TaskRecord curTask = null;
5942 int numActivities = 0;
5943 int numRunning = 0;
5944 while (pos >= 0 && maxNum > 0) {
5945 final HistoryRecord r = next;
5946 pos--;
5947 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5948
5949 // Initialize state for next task if needed.
5950 if (top == null ||
5951 (top.state == ActivityState.INITIALIZING
5952 && top.task == r.task)) {
5953 top = r;
5954 topDescription = r.description;
5955 curTask = r.task;
5956 numActivities = numRunning = 0;
5957 }
5958
5959 // Add 'r' into the current task.
5960 numActivities++;
5961 if (r.app != null && r.app.thread != null) {
5962 numRunning++;
5963 }
5964 if (topDescription == null) {
5965 topDescription = r.description;
5966 }
5967
5968 if (localLOGV) Log.v(
5969 TAG, r.intent.getComponent().flattenToShortString()
5970 + ": task=" + r.task);
5971
5972 // If the next one is a different task, generate a new
5973 // TaskInfo entry for what we have.
5974 if (next == null || next.task != curTask) {
5975 ActivityManager.RunningTaskInfo ci
5976 = new ActivityManager.RunningTaskInfo();
5977 ci.id = curTask.taskId;
5978 ci.baseActivity = r.intent.getComponent();
5979 ci.topActivity = top.intent.getComponent();
5980 ci.thumbnail = top.thumbnail;
5981 ci.description = topDescription;
5982 ci.numActivities = numActivities;
5983 ci.numRunning = numRunning;
5984 //System.out.println(
5985 // "#" + maxNum + ": " + " descr=" + ci.description);
5986 if (ci.thumbnail == null && receiver != null) {
5987 if (localLOGV) Log.v(
5988 TAG, "State=" + top.state + "Idle=" + top.idle
5989 + " app=" + top.app
5990 + " thr=" + (top.app != null ? top.app.thread : null));
5991 if (top.state == ActivityState.RESUMED
5992 || top.state == ActivityState.PAUSING) {
5993 if (top.idle && top.app != null
5994 && top.app.thread != null) {
5995 topRecord = top;
5996 topThumbnail = top.app.thread;
5997 } else {
5998 top.thumbnailNeeded = true;
5999 }
6000 }
6001 if (pending == null) {
6002 pending = new PendingThumbnailsRecord(receiver);
6003 }
6004 pending.pendingRecords.add(top);
6005 }
6006 list.add(ci);
6007 maxNum--;
6008 top = null;
6009 }
6010 }
6011
6012 if (pending != null) {
6013 mPendingThumbnails.add(pending);
6014 }
6015 }
6016
6017 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6018
6019 if (topThumbnail != null) {
6020 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6021 try {
6022 topThumbnail.requestThumbnail(topRecord);
6023 } catch (Exception e) {
6024 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6025 sendPendingThumbnail(null, topRecord, null, null, true);
6026 }
6027 }
6028
6029 if (pending == null && receiver != null) {
6030 // In this case all thumbnails were available and the client
6031 // is being asked to be told when the remaining ones come in...
6032 // which is unusually, since the top-most currently running
6033 // activity should never have a canned thumbnail! Oh well.
6034 try {
6035 receiver.finished();
6036 } catch (RemoteException ex) {
6037 }
6038 }
6039
6040 return list;
6041 }
6042
6043 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6044 int flags) {
6045 synchronized (this) {
6046 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6047 "getRecentTasks()");
6048
6049 final int N = mRecentTasks.size();
6050 ArrayList<ActivityManager.RecentTaskInfo> res
6051 = new ArrayList<ActivityManager.RecentTaskInfo>(
6052 maxNum < N ? maxNum : N);
6053 for (int i=0; i<N && maxNum > 0; i++) {
6054 TaskRecord tr = mRecentTasks.get(i);
6055 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6056 || (tr.intent == null)
6057 || ((tr.intent.getFlags()
6058 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6059 ActivityManager.RecentTaskInfo rti
6060 = new ActivityManager.RecentTaskInfo();
6061 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6062 rti.baseIntent = new Intent(
6063 tr.intent != null ? tr.intent : tr.affinityIntent);
6064 rti.origActivity = tr.origActivity;
6065 res.add(rti);
6066 maxNum--;
6067 }
6068 }
6069 return res;
6070 }
6071 }
6072
6073 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6074 int j;
6075 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6076 TaskRecord jt = startTask;
6077
6078 // First look backwards
6079 for (j=startIndex-1; j>=0; j--) {
6080 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6081 if (r.task != jt) {
6082 jt = r.task;
6083 if (affinity.equals(jt.affinity)) {
6084 return j;
6085 }
6086 }
6087 }
6088
6089 // Now look forwards
6090 final int N = mHistory.size();
6091 jt = startTask;
6092 for (j=startIndex+1; j<N; j++) {
6093 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6094 if (r.task != jt) {
6095 if (affinity.equals(jt.affinity)) {
6096 return j;
6097 }
6098 jt = r.task;
6099 }
6100 }
6101
6102 // Might it be at the top?
6103 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6104 return N-1;
6105 }
6106
6107 return -1;
6108 }
6109
6110 /**
6111 * Perform a reset of the given task, if needed as part of launching it.
6112 * Returns the new HistoryRecord at the top of the task.
6113 */
6114 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6115 HistoryRecord newActivity) {
6116 boolean forceReset = (newActivity.info.flags
6117 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6118 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6119 if ((newActivity.info.flags
6120 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6121 forceReset = true;
6122 }
6123 }
6124
6125 final TaskRecord task = taskTop.task;
6126
6127 // We are going to move through the history list so that we can look
6128 // at each activity 'target' with 'below' either the interesting
6129 // activity immediately below it in the stack or null.
6130 HistoryRecord target = null;
6131 int targetI = 0;
6132 int taskTopI = -1;
6133 int replyChainEnd = -1;
6134 int lastReparentPos = -1;
6135 for (int i=mHistory.size()-1; i>=-1; i--) {
6136 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6137
6138 if (below != null && below.finishing) {
6139 continue;
6140 }
6141 if (target == null) {
6142 target = below;
6143 targetI = i;
6144 // If we were in the middle of a reply chain before this
6145 // task, it doesn't appear like the root of the chain wants
6146 // anything interesting, so drop it.
6147 replyChainEnd = -1;
6148 continue;
6149 }
6150
6151 final int flags = target.info.flags;
6152
6153 final boolean finishOnTaskLaunch =
6154 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6155 final boolean allowTaskReparenting =
6156 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6157
6158 if (target.task == task) {
6159 // We are inside of the task being reset... we'll either
6160 // finish this activity, push it out for another task,
6161 // or leave it as-is. We only do this
6162 // for activities that are not the root of the task (since
6163 // if we finish the root, we may no longer have the task!).
6164 if (taskTopI < 0) {
6165 taskTopI = targetI;
6166 }
6167 if (below != null && below.task == task) {
6168 final boolean clearWhenTaskReset =
6169 (target.intent.getFlags()
6170 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006171 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006172 // If this activity is sending a reply to a previous
6173 // activity, we can't do anything with it now until
6174 // we reach the start of the reply chain.
6175 // XXX note that we are assuming the result is always
6176 // to the previous activity, which is almost always
6177 // the case but we really shouldn't count on.
6178 if (replyChainEnd < 0) {
6179 replyChainEnd = targetI;
6180 }
Ed Heyl73798232009-03-24 21:32:21 -07006181 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006182 && target.taskAffinity != null
6183 && !target.taskAffinity.equals(task.affinity)) {
6184 // If this activity has an affinity for another
6185 // task, then we need to move it out of here. We will
6186 // move it as far out of the way as possible, to the
6187 // bottom of the activity stack. This also keeps it
6188 // correctly ordered with any activities we previously
6189 // moved.
6190 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6191 if (target.taskAffinity != null
6192 && target.taskAffinity.equals(p.task.affinity)) {
6193 // If the activity currently at the bottom has the
6194 // same task affinity as the one we are moving,
6195 // then merge it into the same task.
6196 target.task = p.task;
6197 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6198 + " out to bottom task " + p.task);
6199 } else {
6200 mCurTask++;
6201 if (mCurTask <= 0) {
6202 mCurTask = 1;
6203 }
6204 target.task = new TaskRecord(mCurTask, target.info, null,
6205 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6206 target.task.affinityIntent = target.intent;
6207 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6208 + " out to new task " + target.task);
6209 }
6210 mWindowManager.setAppGroupId(target, task.taskId);
6211 if (replyChainEnd < 0) {
6212 replyChainEnd = targetI;
6213 }
6214 int dstPos = 0;
6215 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6216 p = (HistoryRecord)mHistory.get(srcPos);
6217 if (p.finishing) {
6218 continue;
6219 }
6220 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6221 + " out to target's task " + target.task);
6222 task.numActivities--;
6223 p.task = target.task;
6224 target.task.numActivities++;
6225 mHistory.remove(srcPos);
6226 mHistory.add(dstPos, p);
6227 mWindowManager.moveAppToken(dstPos, p);
6228 mWindowManager.setAppGroupId(p, p.task.taskId);
6229 dstPos++;
6230 if (VALIDATE_TOKENS) {
6231 mWindowManager.validateAppTokens(mHistory);
6232 }
6233 i++;
6234 }
6235 if (taskTop == p) {
6236 taskTop = below;
6237 }
6238 if (taskTopI == replyChainEnd) {
6239 taskTopI = -1;
6240 }
6241 replyChainEnd = -1;
6242 addRecentTask(target.task);
6243 } else if (forceReset || finishOnTaskLaunch
6244 || clearWhenTaskReset) {
6245 // If the activity should just be removed -- either
6246 // because it asks for it, or the task should be
6247 // cleared -- then finish it and anything that is
6248 // part of its reply chain.
6249 if (clearWhenTaskReset) {
6250 // In this case, we want to finish this activity
6251 // and everything above it, so be sneaky and pretend
6252 // like these are all in the reply chain.
6253 replyChainEnd = targetI+1;
6254 while (replyChainEnd < mHistory.size() &&
6255 ((HistoryRecord)mHistory.get(
6256 replyChainEnd)).task == task) {
6257 replyChainEnd++;
6258 }
6259 replyChainEnd--;
6260 } else if (replyChainEnd < 0) {
6261 replyChainEnd = targetI;
6262 }
6263 HistoryRecord p = null;
6264 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6265 p = (HistoryRecord)mHistory.get(srcPos);
6266 if (p.finishing) {
6267 continue;
6268 }
6269 if (finishActivityLocked(p, srcPos,
6270 Activity.RESULT_CANCELED, null, "reset")) {
6271 replyChainEnd--;
6272 srcPos--;
6273 }
6274 }
6275 if (taskTop == p) {
6276 taskTop = below;
6277 }
6278 if (taskTopI == replyChainEnd) {
6279 taskTopI = -1;
6280 }
6281 replyChainEnd = -1;
6282 } else {
6283 // If we were in the middle of a chain, well the
6284 // activity that started it all doesn't want anything
6285 // special, so leave it all as-is.
6286 replyChainEnd = -1;
6287 }
6288 } else {
6289 // Reached the bottom of the task -- any reply chain
6290 // should be left as-is.
6291 replyChainEnd = -1;
6292 }
6293
6294 } else if (target.resultTo != null) {
6295 // If this activity is sending a reply to a previous
6296 // activity, we can't do anything with it now until
6297 // we reach the start of the reply chain.
6298 // XXX note that we are assuming the result is always
6299 // to the previous activity, which is almost always
6300 // the case but we really shouldn't count on.
6301 if (replyChainEnd < 0) {
6302 replyChainEnd = targetI;
6303 }
6304
6305 } else if (taskTopI >= 0 && allowTaskReparenting
6306 && task.affinity != null
6307 && task.affinity.equals(target.taskAffinity)) {
6308 // We are inside of another task... if this activity has
6309 // an affinity for our task, then either remove it if we are
6310 // clearing or move it over to our task. Note that
6311 // we currently punt on the case where we are resetting a
6312 // task that is not at the top but who has activities above
6313 // with an affinity to it... this is really not a normal
6314 // case, and we will need to later pull that task to the front
6315 // and usually at that point we will do the reset and pick
6316 // up those remaining activities. (This only happens if
6317 // someone starts an activity in a new task from an activity
6318 // in a task that is not currently on top.)
6319 if (forceReset || finishOnTaskLaunch) {
6320 if (replyChainEnd < 0) {
6321 replyChainEnd = targetI;
6322 }
6323 HistoryRecord p = null;
6324 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6325 p = (HistoryRecord)mHistory.get(srcPos);
6326 if (p.finishing) {
6327 continue;
6328 }
6329 if (finishActivityLocked(p, srcPos,
6330 Activity.RESULT_CANCELED, null, "reset")) {
6331 taskTopI--;
6332 lastReparentPos--;
6333 replyChainEnd--;
6334 srcPos--;
6335 }
6336 }
6337 replyChainEnd = -1;
6338 } else {
6339 if (replyChainEnd < 0) {
6340 replyChainEnd = targetI;
6341 }
6342 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6343 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6344 if (p.finishing) {
6345 continue;
6346 }
6347 if (lastReparentPos < 0) {
6348 lastReparentPos = taskTopI;
6349 taskTop = p;
6350 } else {
6351 lastReparentPos--;
6352 }
6353 mHistory.remove(srcPos);
6354 p.task.numActivities--;
6355 p.task = task;
6356 mHistory.add(lastReparentPos, p);
6357 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6358 + " in to resetting task " + task);
6359 task.numActivities++;
6360 mWindowManager.moveAppToken(lastReparentPos, p);
6361 mWindowManager.setAppGroupId(p, p.task.taskId);
6362 if (VALIDATE_TOKENS) {
6363 mWindowManager.validateAppTokens(mHistory);
6364 }
6365 }
6366 replyChainEnd = -1;
6367
6368 // Now we've moved it in to place... but what if this is
6369 // a singleTop activity and we have put it on top of another
6370 // instance of the same activity? Then we drop the instance
6371 // below so it remains singleTop.
6372 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6373 for (int j=lastReparentPos-1; j>=0; j--) {
6374 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6375 if (p.finishing) {
6376 continue;
6377 }
6378 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6379 if (finishActivityLocked(p, j,
6380 Activity.RESULT_CANCELED, null, "replace")) {
6381 taskTopI--;
6382 lastReparentPos--;
6383 }
6384 }
6385 }
6386 }
6387 }
6388 }
6389
6390 target = below;
6391 targetI = i;
6392 }
6393
6394 return taskTop;
6395 }
6396
6397 /**
6398 * TODO: Add mWatcher hook
6399 */
6400 public void moveTaskToFront(int task) {
6401 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6402 "moveTaskToFront()");
6403
6404 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006405 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6406 Binder.getCallingUid(), "Task to front")) {
6407 return;
6408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006409 final long origId = Binder.clearCallingIdentity();
6410 try {
6411 int N = mRecentTasks.size();
6412 for (int i=0; i<N; i++) {
6413 TaskRecord tr = mRecentTasks.get(i);
6414 if (tr.taskId == task) {
6415 moveTaskToFrontLocked(tr);
6416 return;
6417 }
6418 }
6419 for (int i=mHistory.size()-1; i>=0; i--) {
6420 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6421 if (hr.task.taskId == task) {
6422 moveTaskToFrontLocked(hr.task);
6423 return;
6424 }
6425 }
6426 } finally {
6427 Binder.restoreCallingIdentity(origId);
6428 }
6429 }
6430 }
6431
6432 private final void moveTaskToFrontLocked(TaskRecord tr) {
6433 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6434
6435 final int task = tr.taskId;
6436 int top = mHistory.size()-1;
6437
6438 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6439 // nothing to do!
6440 return;
6441 }
6442
6443 if (DEBUG_TRANSITION) Log.v(TAG,
6444 "Prepare to front transition: task=" + tr);
6445 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6446
6447 ArrayList moved = new ArrayList();
6448
6449 // Applying the affinities may have removed entries from the history,
6450 // so get the size again.
6451 top = mHistory.size()-1;
6452 int pos = top;
6453
6454 // Shift all activities with this task up to the top
6455 // of the stack, keeping them in the same internal order.
6456 while (pos >= 0) {
6457 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6458 if (localLOGV) Log.v(
6459 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6460 boolean first = true;
6461 if (r.task.taskId == task) {
6462 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6463 mHistory.remove(pos);
6464 mHistory.add(top, r);
6465 moved.add(0, r);
6466 top--;
6467 if (first) {
6468 addRecentTask(r.task);
6469 first = false;
6470 }
6471 }
6472 pos--;
6473 }
6474
6475 mWindowManager.moveAppTokensToTop(moved);
6476 if (VALIDATE_TOKENS) {
6477 mWindowManager.validateAppTokens(mHistory);
6478 }
6479
6480 finishTaskMove(task);
6481 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6482 }
6483
6484 private final void finishTaskMove(int task) {
6485 resumeTopActivityLocked(null);
6486 }
6487
6488 public void moveTaskToBack(int task) {
6489 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6490 "moveTaskToBack()");
6491
6492 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006493 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6494 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6495 Binder.getCallingUid(), "Task to back")) {
6496 return;
6497 }
6498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006499 final long origId = Binder.clearCallingIdentity();
6500 moveTaskToBackLocked(task);
6501 Binder.restoreCallingIdentity(origId);
6502 }
6503 }
6504
6505 /**
6506 * Moves an activity, and all of the other activities within the same task, to the bottom
6507 * of the history stack. The activity's order within the task is unchanged.
6508 *
6509 * @param token A reference to the activity we wish to move
6510 * @param nonRoot If false then this only works if the activity is the root
6511 * of a task; if true it will work for any activity in a task.
6512 * @return Returns true if the move completed, false if not.
6513 */
6514 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6515 synchronized(this) {
6516 final long origId = Binder.clearCallingIdentity();
6517 int taskId = getTaskForActivityLocked(token, !nonRoot);
6518 if (taskId >= 0) {
6519 return moveTaskToBackLocked(taskId);
6520 }
6521 Binder.restoreCallingIdentity(origId);
6522 }
6523 return false;
6524 }
6525
6526 /**
6527 * Worker method for rearranging history stack. Implements the function of moving all
6528 * activities for a specific task (gathering them if disjoint) into a single group at the
6529 * bottom of the stack.
6530 *
6531 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6532 * to premeptively cancel the move.
6533 *
6534 * @param task The taskId to collect and move to the bottom.
6535 * @return Returns true if the move completed, false if not.
6536 */
6537 private final boolean moveTaskToBackLocked(int task) {
6538 Log.i(TAG, "moveTaskToBack: " + task);
6539
6540 // If we have a watcher, preflight the move before committing to it. First check
6541 // for *other* available tasks, but if none are available, then try again allowing the
6542 // current task to be selected.
6543 if (mWatcher != null) {
6544 HistoryRecord next = topRunningActivityLocked(null, task);
6545 if (next == null) {
6546 next = topRunningActivityLocked(null, 0);
6547 }
6548 if (next != null) {
6549 // ask watcher if this is allowed
6550 boolean moveOK = true;
6551 try {
6552 moveOK = mWatcher.activityResuming(next.packageName);
6553 } catch (RemoteException e) {
6554 mWatcher = null;
6555 }
6556 if (!moveOK) {
6557 return false;
6558 }
6559 }
6560 }
6561
6562 ArrayList moved = new ArrayList();
6563
6564 if (DEBUG_TRANSITION) Log.v(TAG,
6565 "Prepare to back transition: task=" + task);
6566 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6567
6568 final int N = mHistory.size();
6569 int bottom = 0;
6570 int pos = 0;
6571
6572 // Shift all activities with this task down to the bottom
6573 // of the stack, keeping them in the same internal order.
6574 while (pos < N) {
6575 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6576 if (localLOGV) Log.v(
6577 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6578 if (r.task.taskId == task) {
6579 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6580 mHistory.remove(pos);
6581 mHistory.add(bottom, r);
6582 moved.add(r);
6583 bottom++;
6584 }
6585 pos++;
6586 }
6587
6588 mWindowManager.moveAppTokensToBottom(moved);
6589 if (VALIDATE_TOKENS) {
6590 mWindowManager.validateAppTokens(mHistory);
6591 }
6592
6593 finishTaskMove(task);
6594 return true;
6595 }
6596
6597 public void moveTaskBackwards(int task) {
6598 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6599 "moveTaskBackwards()");
6600
6601 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006602 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6603 Binder.getCallingUid(), "Task backwards")) {
6604 return;
6605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006606 final long origId = Binder.clearCallingIdentity();
6607 moveTaskBackwardsLocked(task);
6608 Binder.restoreCallingIdentity(origId);
6609 }
6610 }
6611
6612 private final void moveTaskBackwardsLocked(int task) {
6613 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6614 }
6615
6616 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6617 synchronized(this) {
6618 return getTaskForActivityLocked(token, onlyRoot);
6619 }
6620 }
6621
6622 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6623 final int N = mHistory.size();
6624 TaskRecord lastTask = null;
6625 for (int i=0; i<N; i++) {
6626 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6627 if (r == token) {
6628 if (!onlyRoot || lastTask != r.task) {
6629 return r.task.taskId;
6630 }
6631 return -1;
6632 }
6633 lastTask = r.task;
6634 }
6635
6636 return -1;
6637 }
6638
6639 /**
6640 * Returns the top activity in any existing task matching the given
6641 * Intent. Returns null if no such task is found.
6642 */
6643 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6644 ComponentName cls = intent.getComponent();
6645 if (info.targetActivity != null) {
6646 cls = new ComponentName(info.packageName, info.targetActivity);
6647 }
6648
6649 TaskRecord cp = null;
6650
6651 final int N = mHistory.size();
6652 for (int i=(N-1); i>=0; i--) {
6653 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6654 if (!r.finishing && r.task != cp
6655 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6656 cp = r.task;
6657 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6658 // + "/aff=" + r.task.affinity + " to new cls="
6659 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6660 if (r.task.affinity != null) {
6661 if (r.task.affinity.equals(info.taskAffinity)) {
6662 //Log.i(TAG, "Found matching affinity!");
6663 return r;
6664 }
6665 } else if (r.task.intent != null
6666 && r.task.intent.getComponent().equals(cls)) {
6667 //Log.i(TAG, "Found matching class!");
6668 //dump();
6669 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6670 return r;
6671 } else if (r.task.affinityIntent != null
6672 && r.task.affinityIntent.getComponent().equals(cls)) {
6673 //Log.i(TAG, "Found matching class!");
6674 //dump();
6675 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6676 return r;
6677 }
6678 }
6679 }
6680
6681 return null;
6682 }
6683
6684 /**
6685 * Returns the first activity (starting from the top of the stack) that
6686 * is the same as the given activity. Returns null if no such activity
6687 * is found.
6688 */
6689 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6690 ComponentName cls = intent.getComponent();
6691 if (info.targetActivity != null) {
6692 cls = new ComponentName(info.packageName, info.targetActivity);
6693 }
6694
6695 final int N = mHistory.size();
6696 for (int i=(N-1); i>=0; i--) {
6697 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6698 if (!r.finishing) {
6699 if (r.intent.getComponent().equals(cls)) {
6700 //Log.i(TAG, "Found matching class!");
6701 //dump();
6702 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6703 return r;
6704 }
6705 }
6706 }
6707
6708 return null;
6709 }
6710
6711 public void finishOtherInstances(IBinder token, ComponentName className) {
6712 synchronized(this) {
6713 final long origId = Binder.clearCallingIdentity();
6714
6715 int N = mHistory.size();
6716 TaskRecord lastTask = null;
6717 for (int i=0; i<N; i++) {
6718 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6719 if (r.realActivity.equals(className)
6720 && r != token && lastTask != r.task) {
6721 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6722 null, "others")) {
6723 i--;
6724 N--;
6725 }
6726 }
6727 lastTask = r.task;
6728 }
6729
6730 Binder.restoreCallingIdentity(origId);
6731 }
6732 }
6733
6734 // =========================================================
6735 // THUMBNAILS
6736 // =========================================================
6737
6738 public void reportThumbnail(IBinder token,
6739 Bitmap thumbnail, CharSequence description) {
6740 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6741 final long origId = Binder.clearCallingIdentity();
6742 sendPendingThumbnail(null, token, thumbnail, description, true);
6743 Binder.restoreCallingIdentity(origId);
6744 }
6745
6746 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6747 Bitmap thumbnail, CharSequence description, boolean always) {
6748 TaskRecord task = null;
6749 ArrayList receivers = null;
6750
6751 //System.out.println("Send pending thumbnail: " + r);
6752
6753 synchronized(this) {
6754 if (r == null) {
6755 int index = indexOfTokenLocked(token, false);
6756 if (index < 0) {
6757 return;
6758 }
6759 r = (HistoryRecord)mHistory.get(index);
6760 }
6761 if (thumbnail == null) {
6762 thumbnail = r.thumbnail;
6763 description = r.description;
6764 }
6765 if (thumbnail == null && !always) {
6766 // If there is no thumbnail, and this entry is not actually
6767 // going away, then abort for now and pick up the next
6768 // thumbnail we get.
6769 return;
6770 }
6771 task = r.task;
6772
6773 int N = mPendingThumbnails.size();
6774 int i=0;
6775 while (i<N) {
6776 PendingThumbnailsRecord pr =
6777 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6778 //System.out.println("Looking in " + pr.pendingRecords);
6779 if (pr.pendingRecords.remove(r)) {
6780 if (receivers == null) {
6781 receivers = new ArrayList();
6782 }
6783 receivers.add(pr);
6784 if (pr.pendingRecords.size() == 0) {
6785 pr.finished = true;
6786 mPendingThumbnails.remove(i);
6787 N--;
6788 continue;
6789 }
6790 }
6791 i++;
6792 }
6793 }
6794
6795 if (receivers != null) {
6796 final int N = receivers.size();
6797 for (int i=0; i<N; i++) {
6798 try {
6799 PendingThumbnailsRecord pr =
6800 (PendingThumbnailsRecord)receivers.get(i);
6801 pr.receiver.newThumbnail(
6802 task != null ? task.taskId : -1, thumbnail, description);
6803 if (pr.finished) {
6804 pr.receiver.finished();
6805 }
6806 } catch (Exception e) {
6807 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6808 }
6809 }
6810 }
6811 }
6812
6813 // =========================================================
6814 // CONTENT PROVIDERS
6815 // =========================================================
6816
6817 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6818 List providers = null;
6819 try {
6820 providers = ActivityThread.getPackageManager().
6821 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006822 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006823 } catch (RemoteException ex) {
6824 }
6825 if (providers != null) {
6826 final int N = providers.size();
6827 for (int i=0; i<N; i++) {
6828 ProviderInfo cpi =
6829 (ProviderInfo)providers.get(i);
6830 ContentProviderRecord cpr =
6831 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6832 if (cpr == null) {
6833 cpr = new ContentProviderRecord(cpi, app.info);
6834 mProvidersByClass.put(cpi.name, cpr);
6835 }
6836 app.pubProviders.put(cpi.name, cpr);
6837 app.addPackage(cpi.applicationInfo.packageName);
6838 }
6839 }
6840 return providers;
6841 }
6842
6843 private final String checkContentProviderPermissionLocked(
6844 ProviderInfo cpi, ProcessRecord r, int mode) {
6845 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6846 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6847 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6848 cpi.exported ? -1 : cpi.applicationInfo.uid)
6849 == PackageManager.PERMISSION_GRANTED
6850 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6851 return null;
6852 }
6853 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6854 cpi.exported ? -1 : cpi.applicationInfo.uid)
6855 == PackageManager.PERMISSION_GRANTED) {
6856 return null;
6857 }
6858 String msg = "Permission Denial: opening provider " + cpi.name
6859 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6860 + ", uid=" + callingUid + ") requires "
6861 + cpi.readPermission + " or " + cpi.writePermission;
6862 Log.w(TAG, msg);
6863 return msg;
6864 }
6865
6866 private final ContentProviderHolder getContentProviderImpl(
6867 IApplicationThread caller, String name) {
6868 ContentProviderRecord cpr;
6869 ProviderInfo cpi = null;
6870
6871 synchronized(this) {
6872 ProcessRecord r = null;
6873 if (caller != null) {
6874 r = getRecordForAppLocked(caller);
6875 if (r == null) {
6876 throw new SecurityException(
6877 "Unable to find app for caller " + caller
6878 + " (pid=" + Binder.getCallingPid()
6879 + ") when getting content provider " + name);
6880 }
6881 }
6882
6883 // First check if this content provider has been published...
6884 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6885 if (cpr != null) {
6886 cpi = cpr.info;
6887 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6888 return new ContentProviderHolder(cpi,
6889 cpi.readPermission != null
6890 ? cpi.readPermission : cpi.writePermission);
6891 }
6892
6893 if (r != null && cpr.canRunHere(r)) {
6894 // This provider has been published or is in the process
6895 // of being published... but it is also allowed to run
6896 // in the caller's process, so don't make a connection
6897 // and just let the caller instantiate its own instance.
6898 if (cpr.provider != null) {
6899 // don't give caller the provider object, it needs
6900 // to make its own.
6901 cpr = new ContentProviderRecord(cpr);
6902 }
6903 return cpr;
6904 }
6905
6906 final long origId = Binder.clearCallingIdentity();
6907
6908 // In this case the provider is a single instance, so we can
6909 // return it right away.
6910 if (r != null) {
6911 r.conProviders.add(cpr);
6912 cpr.clients.add(r);
6913 } else {
6914 cpr.externals++;
6915 }
6916
6917 if (cpr.app != null) {
6918 updateOomAdjLocked(cpr.app);
6919 }
6920
6921 Binder.restoreCallingIdentity(origId);
6922
6923 } else {
6924 try {
6925 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07006926 resolveContentProvider(name,
6927 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006928 } catch (RemoteException ex) {
6929 }
6930 if (cpi == null) {
6931 return null;
6932 }
6933
6934 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6935 return new ContentProviderHolder(cpi,
6936 cpi.readPermission != null
6937 ? cpi.readPermission : cpi.writePermission);
6938 }
6939
6940 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6941 final boolean firstClass = cpr == null;
6942 if (firstClass) {
6943 try {
6944 ApplicationInfo ai =
6945 ActivityThread.getPackageManager().
6946 getApplicationInfo(
6947 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006948 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006949 if (ai == null) {
6950 Log.w(TAG, "No package info for content provider "
6951 + cpi.name);
6952 return null;
6953 }
6954 cpr = new ContentProviderRecord(cpi, ai);
6955 } catch (RemoteException ex) {
6956 // pm is in same process, this will never happen.
6957 }
6958 }
6959
6960 if (r != null && cpr.canRunHere(r)) {
6961 // If this is a multiprocess provider, then just return its
6962 // info and allow the caller to instantiate it. Only do
6963 // this if the provider is the same user as the caller's
6964 // process, or can run as root (so can be in any process).
6965 return cpr;
6966 }
6967
6968 if (false) {
6969 RuntimeException e = new RuntimeException("foo");
6970 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
6971 // + " pruid " + ai.uid + "): " + cpi.className, e);
6972 }
6973
6974 // This is single process, and our app is now connecting to it.
6975 // See if we are already in the process of launching this
6976 // provider.
6977 final int N = mLaunchingProviders.size();
6978 int i;
6979 for (i=0; i<N; i++) {
6980 if (mLaunchingProviders.get(i) == cpr) {
6981 break;
6982 }
6983 if (false) {
6984 final ContentProviderRecord rec =
6985 (ContentProviderRecord)mLaunchingProviders.get(i);
6986 if (rec.info.name.equals(cpr.info.name)) {
6987 cpr = rec;
6988 break;
6989 }
6990 }
6991 }
6992
6993 // If the provider is not already being launched, then get it
6994 // started.
6995 if (i >= N) {
6996 final long origId = Binder.clearCallingIdentity();
6997 ProcessRecord proc = startProcessLocked(cpi.processName,
6998 cpr.appInfo, false, 0, "content provider",
6999 new ComponentName(cpi.applicationInfo.packageName,
7000 cpi.name));
7001 if (proc == null) {
7002 Log.w(TAG, "Unable to launch app "
7003 + cpi.applicationInfo.packageName + "/"
7004 + cpi.applicationInfo.uid + " for provider "
7005 + name + ": process is bad");
7006 return null;
7007 }
7008 cpr.launchingApp = proc;
7009 mLaunchingProviders.add(cpr);
7010 Binder.restoreCallingIdentity(origId);
7011 }
7012
7013 // Make sure the provider is published (the same provider class
7014 // may be published under multiple names).
7015 if (firstClass) {
7016 mProvidersByClass.put(cpi.name, cpr);
7017 }
7018 mProvidersByName.put(name, cpr);
7019
7020 if (r != null) {
7021 r.conProviders.add(cpr);
7022 cpr.clients.add(r);
7023 } else {
7024 cpr.externals++;
7025 }
7026 }
7027 }
7028
7029 // Wait for the provider to be published...
7030 synchronized (cpr) {
7031 while (cpr.provider == null) {
7032 if (cpr.launchingApp == null) {
7033 Log.w(TAG, "Unable to launch app "
7034 + cpi.applicationInfo.packageName + "/"
7035 + cpi.applicationInfo.uid + " for provider "
7036 + name + ": launching app became null");
7037 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7038 cpi.applicationInfo.packageName,
7039 cpi.applicationInfo.uid, name);
7040 return null;
7041 }
7042 try {
7043 cpr.wait();
7044 } catch (InterruptedException ex) {
7045 }
7046 }
7047 }
7048 return cpr;
7049 }
7050
7051 public final ContentProviderHolder getContentProvider(
7052 IApplicationThread caller, String name) {
7053 if (caller == null) {
7054 String msg = "null IApplicationThread when getting content provider "
7055 + name;
7056 Log.w(TAG, msg);
7057 throw new SecurityException(msg);
7058 }
7059
7060 return getContentProviderImpl(caller, name);
7061 }
7062
7063 private ContentProviderHolder getContentProviderExternal(String name) {
7064 return getContentProviderImpl(null, name);
7065 }
7066
7067 /**
7068 * Drop a content provider from a ProcessRecord's bookkeeping
7069 * @param cpr
7070 */
7071 public void removeContentProvider(IApplicationThread caller, String name) {
7072 synchronized (this) {
7073 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7074 if(cpr == null) {
7075 //remove from mProvidersByClass
7076 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7077 return;
7078 }
7079 final ProcessRecord r = getRecordForAppLocked(caller);
7080 if (r == null) {
7081 throw new SecurityException(
7082 "Unable to find app for caller " + caller +
7083 " when removing content provider " + name);
7084 }
7085 //update content provider record entry info
7086 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7087 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7088 r.info.processName+" from process "+localCpr.appInfo.processName);
7089 if(localCpr.appInfo.processName == r.info.processName) {
7090 //should not happen. taken care of as a local provider
7091 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7092 return;
7093 } else {
7094 localCpr.clients.remove(r);
7095 r.conProviders.remove(localCpr);
7096 }
7097 updateOomAdjLocked();
7098 }
7099 }
7100
7101 private void removeContentProviderExternal(String name) {
7102 synchronized (this) {
7103 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7104 if(cpr == null) {
7105 //remove from mProvidersByClass
7106 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7107 return;
7108 }
7109
7110 //update content provider record entry info
7111 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7112 localCpr.externals--;
7113 if (localCpr.externals < 0) {
7114 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7115 }
7116 updateOomAdjLocked();
7117 }
7118 }
7119
7120 public final void publishContentProviders(IApplicationThread caller,
7121 List<ContentProviderHolder> providers) {
7122 if (providers == null) {
7123 return;
7124 }
7125
7126 synchronized(this) {
7127 final ProcessRecord r = getRecordForAppLocked(caller);
7128 if (r == null) {
7129 throw new SecurityException(
7130 "Unable to find app for caller " + caller
7131 + " (pid=" + Binder.getCallingPid()
7132 + ") when publishing content providers");
7133 }
7134
7135 final long origId = Binder.clearCallingIdentity();
7136
7137 final int N = providers.size();
7138 for (int i=0; i<N; i++) {
7139 ContentProviderHolder src = providers.get(i);
7140 if (src == null || src.info == null || src.provider == null) {
7141 continue;
7142 }
7143 ContentProviderRecord dst =
7144 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7145 if (dst != null) {
7146 mProvidersByClass.put(dst.info.name, dst);
7147 String names[] = dst.info.authority.split(";");
7148 for (int j = 0; j < names.length; j++) {
7149 mProvidersByName.put(names[j], dst);
7150 }
7151
7152 int NL = mLaunchingProviders.size();
7153 int j;
7154 for (j=0; j<NL; j++) {
7155 if (mLaunchingProviders.get(j) == dst) {
7156 mLaunchingProviders.remove(j);
7157 j--;
7158 NL--;
7159 }
7160 }
7161 synchronized (dst) {
7162 dst.provider = src.provider;
7163 dst.app = r;
7164 dst.notifyAll();
7165 }
7166 updateOomAdjLocked(r);
7167 }
7168 }
7169
7170 Binder.restoreCallingIdentity(origId);
7171 }
7172 }
7173
7174 public static final void installSystemProviders() {
7175 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7176 List providers = mSelf.generateApplicationProvidersLocked(app);
7177 mSystemThread.installSystemProviders(providers);
7178 }
7179
7180 // =========================================================
7181 // GLOBAL MANAGEMENT
7182 // =========================================================
7183
7184 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7185 ApplicationInfo info, String customProcess) {
7186 String proc = customProcess != null ? customProcess : info.processName;
7187 BatteryStatsImpl.Uid.Proc ps = null;
7188 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7189 synchronized (stats) {
7190 ps = stats.getProcessStatsLocked(info.uid, proc);
7191 }
7192 return new ProcessRecord(ps, thread, info, proc);
7193 }
7194
7195 final ProcessRecord addAppLocked(ApplicationInfo info) {
7196 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7197
7198 if (app == null) {
7199 app = newProcessRecordLocked(null, info, null);
7200 mProcessNames.put(info.processName, info.uid, app);
7201 updateLRUListLocked(app, true);
7202 }
7203
7204 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7205 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7206 app.persistent = true;
7207 app.maxAdj = CORE_SERVER_ADJ;
7208 }
7209 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7210 mPersistentStartingProcesses.add(app);
7211 startProcessLocked(app, "added application", app.processName);
7212 }
7213
7214 return app;
7215 }
7216
7217 public void unhandledBack() {
7218 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7219 "unhandledBack()");
7220
7221 synchronized(this) {
7222 int count = mHistory.size();
7223 if (Config.LOGD) Log.d(
7224 TAG, "Performing unhandledBack(): stack size = " + count);
7225 if (count > 1) {
7226 final long origId = Binder.clearCallingIdentity();
7227 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7228 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7229 Binder.restoreCallingIdentity(origId);
7230 }
7231 }
7232 }
7233
7234 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7235 String name = uri.getAuthority();
7236 ContentProviderHolder cph = getContentProviderExternal(name);
7237 ParcelFileDescriptor pfd = null;
7238 if (cph != null) {
7239 // We record the binder invoker's uid in thread-local storage before
7240 // going to the content provider to open the file. Later, in the code
7241 // that handles all permissions checks, we look for this uid and use
7242 // that rather than the Activity Manager's own uid. The effect is that
7243 // we do the check against the caller's permissions even though it looks
7244 // to the content provider like the Activity Manager itself is making
7245 // the request.
7246 sCallerIdentity.set(new Identity(
7247 Binder.getCallingPid(), Binder.getCallingUid()));
7248 try {
7249 pfd = cph.provider.openFile(uri, "r");
7250 } catch (FileNotFoundException e) {
7251 // do nothing; pfd will be returned null
7252 } finally {
7253 // Ensure that whatever happens, we clean up the identity state
7254 sCallerIdentity.remove();
7255 }
7256
7257 // We've got the fd now, so we're done with the provider.
7258 removeContentProviderExternal(name);
7259 } else {
7260 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7261 }
7262 return pfd;
7263 }
7264
7265 public void goingToSleep() {
7266 synchronized(this) {
7267 mSleeping = true;
7268 mWindowManager.setEventDispatching(false);
7269
7270 if (mResumedActivity != null) {
7271 pauseIfSleepingLocked();
7272 } else {
7273 Log.w(TAG, "goingToSleep with no resumed activity!");
7274 }
7275 }
7276 }
7277
Dianne Hackborn55280a92009-05-07 15:53:46 -07007278 public boolean shutdown(int timeout) {
7279 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7280 != PackageManager.PERMISSION_GRANTED) {
7281 throw new SecurityException("Requires permission "
7282 + android.Manifest.permission.SHUTDOWN);
7283 }
7284
7285 boolean timedout = false;
7286
7287 synchronized(this) {
7288 mShuttingDown = true;
7289 mWindowManager.setEventDispatching(false);
7290
7291 if (mResumedActivity != null) {
7292 pauseIfSleepingLocked();
7293 final long endTime = System.currentTimeMillis() + timeout;
7294 while (mResumedActivity != null || mPausingActivity != null) {
7295 long delay = endTime - System.currentTimeMillis();
7296 if (delay <= 0) {
7297 Log.w(TAG, "Activity manager shutdown timed out");
7298 timedout = true;
7299 break;
7300 }
7301 try {
7302 this.wait();
7303 } catch (InterruptedException e) {
7304 }
7305 }
7306 }
7307 }
7308
7309 mUsageStatsService.shutdown();
7310 mBatteryStatsService.shutdown();
7311
7312 return timedout;
7313 }
7314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007315 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007316 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007317 if (!mGoingToSleep.isHeld()) {
7318 mGoingToSleep.acquire();
7319 if (mLaunchingActivity.isHeld()) {
7320 mLaunchingActivity.release();
7321 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7322 }
7323 }
7324
7325 // If we are not currently pausing an activity, get the current
7326 // one to pause. If we are pausing one, we will just let that stuff
7327 // run and release the wake lock when all done.
7328 if (mPausingActivity == null) {
7329 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7330 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7331 startPausingLocked(false, true);
7332 }
7333 }
7334 }
7335
7336 public void wakingUp() {
7337 synchronized(this) {
7338 if (mGoingToSleep.isHeld()) {
7339 mGoingToSleep.release();
7340 }
7341 mWindowManager.setEventDispatching(true);
7342 mSleeping = false;
7343 resumeTopActivityLocked(null);
7344 }
7345 }
7346
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007347 public void stopAppSwitches() {
7348 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7349 != PackageManager.PERMISSION_GRANTED) {
7350 throw new SecurityException("Requires permission "
7351 + android.Manifest.permission.STOP_APP_SWITCHES);
7352 }
7353
7354 synchronized(this) {
7355 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7356 + APP_SWITCH_DELAY_TIME;
7357 mDidAppSwitch = false;
7358 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7359 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7360 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7361 }
7362 }
7363
7364 public void resumeAppSwitches() {
7365 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7366 != PackageManager.PERMISSION_GRANTED) {
7367 throw new SecurityException("Requires permission "
7368 + android.Manifest.permission.STOP_APP_SWITCHES);
7369 }
7370
7371 synchronized(this) {
7372 // Note that we don't execute any pending app switches... we will
7373 // let those wait until either the timeout, or the next start
7374 // activity request.
7375 mAppSwitchesAllowedTime = 0;
7376 }
7377 }
7378
7379 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7380 String name) {
7381 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7382 return true;
7383 }
7384
7385 final int perm = checkComponentPermission(
7386 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7387 callingUid, -1);
7388 if (perm == PackageManager.PERMISSION_GRANTED) {
7389 return true;
7390 }
7391
7392 Log.w(TAG, name + " request from " + callingUid + " stopped");
7393 return false;
7394 }
7395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007396 public void setDebugApp(String packageName, boolean waitForDebugger,
7397 boolean persistent) {
7398 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7399 "setDebugApp()");
7400
7401 // Note that this is not really thread safe if there are multiple
7402 // callers into it at the same time, but that's not a situation we
7403 // care about.
7404 if (persistent) {
7405 final ContentResolver resolver = mContext.getContentResolver();
7406 Settings.System.putString(
7407 resolver, Settings.System.DEBUG_APP,
7408 packageName);
7409 Settings.System.putInt(
7410 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7411 waitForDebugger ? 1 : 0);
7412 }
7413
7414 synchronized (this) {
7415 if (!persistent) {
7416 mOrigDebugApp = mDebugApp;
7417 mOrigWaitForDebugger = mWaitForDebugger;
7418 }
7419 mDebugApp = packageName;
7420 mWaitForDebugger = waitForDebugger;
7421 mDebugTransient = !persistent;
7422 if (packageName != null) {
7423 final long origId = Binder.clearCallingIdentity();
7424 uninstallPackageLocked(packageName, -1, false);
7425 Binder.restoreCallingIdentity(origId);
7426 }
7427 }
7428 }
7429
7430 public void setAlwaysFinish(boolean enabled) {
7431 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7432 "setAlwaysFinish()");
7433
7434 Settings.System.putInt(
7435 mContext.getContentResolver(),
7436 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7437
7438 synchronized (this) {
7439 mAlwaysFinishActivities = enabled;
7440 }
7441 }
7442
7443 public void setActivityWatcher(IActivityWatcher watcher) {
7444 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7445 "setActivityWatcher()");
7446 synchronized (this) {
7447 mWatcher = watcher;
7448 }
7449 }
7450
7451 public final void enterSafeMode() {
7452 synchronized(this) {
7453 // It only makes sense to do this before the system is ready
7454 // and started launching other packages.
7455 if (!mSystemReady) {
7456 try {
7457 ActivityThread.getPackageManager().enterSafeMode();
7458 } catch (RemoteException e) {
7459 }
7460
7461 View v = LayoutInflater.from(mContext).inflate(
7462 com.android.internal.R.layout.safe_mode, null);
7463 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7464 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7465 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7466 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7467 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7468 lp.format = v.getBackground().getOpacity();
7469 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7470 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7471 ((WindowManager)mContext.getSystemService(
7472 Context.WINDOW_SERVICE)).addView(v, lp);
7473 }
7474 }
7475 }
7476
7477 public void noteWakeupAlarm(IIntentSender sender) {
7478 if (!(sender instanceof PendingIntentRecord)) {
7479 return;
7480 }
7481 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7482 synchronized (stats) {
7483 if (mBatteryStatsService.isOnBattery()) {
7484 mBatteryStatsService.enforceCallingPermission();
7485 PendingIntentRecord rec = (PendingIntentRecord)sender;
7486 int MY_UID = Binder.getCallingUid();
7487 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7488 BatteryStatsImpl.Uid.Pkg pkg =
7489 stats.getPackageStatsLocked(uid, rec.key.packageName);
7490 pkg.incWakeupsLocked();
7491 }
7492 }
7493 }
7494
7495 public boolean killPidsForMemory(int[] pids) {
7496 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7497 throw new SecurityException("killPidsForMemory only available to the system");
7498 }
7499
7500 // XXX Note: don't acquire main activity lock here, because the window
7501 // manager calls in with its locks held.
7502
7503 boolean killed = false;
7504 synchronized (mPidsSelfLocked) {
7505 int[] types = new int[pids.length];
7506 int worstType = 0;
7507 for (int i=0; i<pids.length; i++) {
7508 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7509 if (proc != null) {
7510 int type = proc.setAdj;
7511 types[i] = type;
7512 if (type > worstType) {
7513 worstType = type;
7514 }
7515 }
7516 }
7517
7518 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7519 // then constrain it so we will kill all hidden procs.
7520 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7521 worstType = HIDDEN_APP_MIN_ADJ;
7522 }
7523 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7524 for (int i=0; i<pids.length; i++) {
7525 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7526 if (proc == null) {
7527 continue;
7528 }
7529 int adj = proc.setAdj;
7530 if (adj >= worstType) {
7531 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7532 + adj + ")");
7533 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7534 proc.processName, adj);
7535 killed = true;
7536 Process.killProcess(pids[i]);
7537 }
7538 }
7539 }
7540 return killed;
7541 }
7542
7543 public void reportPss(IApplicationThread caller, int pss) {
7544 Watchdog.PssRequestor req;
7545 String name;
7546 ProcessRecord callerApp;
7547 synchronized (this) {
7548 if (caller == null) {
7549 return;
7550 }
7551 callerApp = getRecordForAppLocked(caller);
7552 if (callerApp == null) {
7553 return;
7554 }
7555 callerApp.lastPss = pss;
7556 req = callerApp;
7557 name = callerApp.processName;
7558 }
7559 Watchdog.getInstance().reportPss(req, name, pss);
7560 if (!callerApp.persistent) {
7561 removeRequestedPss(callerApp);
7562 }
7563 }
7564
7565 public void requestPss(Runnable completeCallback) {
7566 ArrayList<ProcessRecord> procs;
7567 synchronized (this) {
7568 mRequestPssCallback = completeCallback;
7569 mRequestPssList.clear();
7570 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7571 ProcessRecord proc = mLRUProcesses.get(i);
7572 if (!proc.persistent) {
7573 mRequestPssList.add(proc);
7574 }
7575 }
7576 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7577 }
7578
7579 int oldPri = Process.getThreadPriority(Process.myTid());
7580 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7581 for (int i=procs.size()-1; i>=0; i--) {
7582 ProcessRecord proc = procs.get(i);
7583 proc.lastPss = 0;
7584 proc.requestPss();
7585 }
7586 Process.setThreadPriority(oldPri);
7587 }
7588
7589 void removeRequestedPss(ProcessRecord proc) {
7590 Runnable callback = null;
7591 synchronized (this) {
7592 if (mRequestPssList.remove(proc)) {
7593 if (mRequestPssList.size() == 0) {
7594 callback = mRequestPssCallback;
7595 mRequestPssCallback = null;
7596 }
7597 }
7598 }
7599
7600 if (callback != null) {
7601 callback.run();
7602 }
7603 }
7604
7605 public void collectPss(Watchdog.PssStats stats) {
7606 stats.mEmptyPss = 0;
7607 stats.mEmptyCount = 0;
7608 stats.mBackgroundPss = 0;
7609 stats.mBackgroundCount = 0;
7610 stats.mServicePss = 0;
7611 stats.mServiceCount = 0;
7612 stats.mVisiblePss = 0;
7613 stats.mVisibleCount = 0;
7614 stats.mForegroundPss = 0;
7615 stats.mForegroundCount = 0;
7616 stats.mNoPssCount = 0;
7617 synchronized (this) {
7618 int i;
7619 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7620 ? mProcDeaths.length : stats.mProcDeaths.length;
7621 int aggr = 0;
7622 for (i=0; i<NPD; i++) {
7623 aggr += mProcDeaths[i];
7624 stats.mProcDeaths[i] = aggr;
7625 }
7626 while (i<stats.mProcDeaths.length) {
7627 stats.mProcDeaths[i] = 0;
7628 i++;
7629 }
7630
7631 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7632 ProcessRecord proc = mLRUProcesses.get(i);
7633 if (proc.persistent) {
7634 continue;
7635 }
7636 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7637 if (proc.lastPss == 0) {
7638 stats.mNoPssCount++;
7639 continue;
7640 }
7641 if (proc.setAdj == EMPTY_APP_ADJ) {
7642 stats.mEmptyPss += proc.lastPss;
7643 stats.mEmptyCount++;
7644 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7645 stats.mEmptyPss += proc.lastPss;
7646 stats.mEmptyCount++;
7647 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7648 stats.mBackgroundPss += proc.lastPss;
7649 stats.mBackgroundCount++;
7650 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7651 stats.mVisiblePss += proc.lastPss;
7652 stats.mVisibleCount++;
7653 } else {
7654 stats.mForegroundPss += proc.lastPss;
7655 stats.mForegroundCount++;
7656 }
7657 }
7658 }
7659 }
7660
7661 public final void startRunning(String pkg, String cls, String action,
7662 String data) {
7663 synchronized(this) {
7664 if (mStartRunning) {
7665 return;
7666 }
7667 mStartRunning = true;
7668 mTopComponent = pkg != null && cls != null
7669 ? new ComponentName(pkg, cls) : null;
7670 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7671 mTopData = data;
7672 if (!mSystemReady) {
7673 return;
7674 }
7675 }
7676
7677 systemReady();
7678 }
7679
7680 private void retrieveSettings() {
7681 final ContentResolver resolver = mContext.getContentResolver();
7682 String debugApp = Settings.System.getString(
7683 resolver, Settings.System.DEBUG_APP);
7684 boolean waitForDebugger = Settings.System.getInt(
7685 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7686 boolean alwaysFinishActivities = Settings.System.getInt(
7687 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7688
7689 Configuration configuration = new Configuration();
7690 Settings.System.getConfiguration(resolver, configuration);
7691
7692 synchronized (this) {
7693 mDebugApp = mOrigDebugApp = debugApp;
7694 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7695 mAlwaysFinishActivities = alwaysFinishActivities;
7696 // This happens before any activities are started, so we can
7697 // change mConfiguration in-place.
7698 mConfiguration.updateFrom(configuration);
7699 }
7700 }
7701
7702 public boolean testIsSystemReady() {
7703 // no need to synchronize(this) just to read & return the value
7704 return mSystemReady;
7705 }
7706
7707 public void systemReady() {
7708 // In the simulator, startRunning will never have been called, which
7709 // normally sets a few crucial variables. Do it here instead.
7710 if (!Process.supportsProcesses()) {
7711 mStartRunning = true;
7712 mTopAction = Intent.ACTION_MAIN;
7713 }
7714
7715 synchronized(this) {
7716 if (mSystemReady) {
7717 return;
7718 }
7719 mSystemReady = true;
7720 if (!mStartRunning) {
7721 return;
7722 }
7723 }
7724
7725 if (Config.LOGD) Log.d(TAG, "Start running!");
7726 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7727 SystemClock.uptimeMillis());
7728
7729 synchronized(this) {
7730 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7731 ResolveInfo ri = mContext.getPackageManager()
7732 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007733 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007734 CharSequence errorMsg = null;
7735 if (ri != null) {
7736 ActivityInfo ai = ri.activityInfo;
7737 ApplicationInfo app = ai.applicationInfo;
7738 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7739 mTopAction = Intent.ACTION_FACTORY_TEST;
7740 mTopData = null;
7741 mTopComponent = new ComponentName(app.packageName,
7742 ai.name);
7743 } else {
7744 errorMsg = mContext.getResources().getText(
7745 com.android.internal.R.string.factorytest_not_system);
7746 }
7747 } else {
7748 errorMsg = mContext.getResources().getText(
7749 com.android.internal.R.string.factorytest_no_action);
7750 }
7751 if (errorMsg != null) {
7752 mTopAction = null;
7753 mTopData = null;
7754 mTopComponent = null;
7755 Message msg = Message.obtain();
7756 msg.what = SHOW_FACTORY_ERROR_MSG;
7757 msg.getData().putCharSequence("msg", errorMsg);
7758 mHandler.sendMessage(msg);
7759 }
7760 }
7761 }
7762
7763 retrieveSettings();
7764
7765 synchronized (this) {
7766 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7767 try {
7768 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007769 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007770 if (apps != null) {
7771 int N = apps.size();
7772 int i;
7773 for (i=0; i<N; i++) {
7774 ApplicationInfo info
7775 = (ApplicationInfo)apps.get(i);
7776 if (info != null &&
7777 !info.packageName.equals("android")) {
7778 addAppLocked(info);
7779 }
7780 }
7781 }
7782 } catch (RemoteException ex) {
7783 // pm is in same process, this will never happen.
7784 }
7785 }
7786
7787 try {
7788 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7789 Message msg = Message.obtain();
7790 msg.what = SHOW_UID_ERROR_MSG;
7791 mHandler.sendMessage(msg);
7792 }
7793 } catch (RemoteException e) {
7794 }
7795
7796 // Start up initial activity.
7797 mBooting = true;
7798 resumeTopActivityLocked(null);
7799 }
7800 }
7801
7802 boolean makeAppCrashingLocked(ProcessRecord app,
7803 String tag, String shortMsg, String longMsg, byte[] crashData) {
7804 app.crashing = true;
7805 app.crashingReport = generateProcessError(app,
7806 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7807 startAppProblemLocked(app);
7808 app.stopFreezingAllLocked();
7809 return handleAppCrashLocked(app);
7810 }
7811
7812 void makeAppNotRespondingLocked(ProcessRecord app,
7813 String tag, String shortMsg, String longMsg, byte[] crashData) {
7814 app.notResponding = true;
7815 app.notRespondingReport = generateProcessError(app,
7816 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7817 crashData);
7818 startAppProblemLocked(app);
7819 app.stopFreezingAllLocked();
7820 }
7821
7822 /**
7823 * Generate a process error record, suitable for attachment to a ProcessRecord.
7824 *
7825 * @param app The ProcessRecord in which the error occurred.
7826 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7827 * ActivityManager.AppErrorStateInfo
7828 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7829 * @param shortMsg Short message describing the crash.
7830 * @param longMsg Long message describing the crash.
7831 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7832 *
7833 * @return Returns a fully-formed AppErrorStateInfo record.
7834 */
7835 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7836 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7837 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7838
7839 report.condition = condition;
7840 report.processName = app.processName;
7841 report.pid = app.pid;
7842 report.uid = app.info.uid;
7843 report.tag = tag;
7844 report.shortMsg = shortMsg;
7845 report.longMsg = longMsg;
7846 report.crashData = crashData;
7847
7848 return report;
7849 }
7850
7851 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7852 boolean crashed) {
7853 synchronized (this) {
7854 app.crashing = false;
7855 app.crashingReport = null;
7856 app.notResponding = false;
7857 app.notRespondingReport = null;
7858 if (app.anrDialog == fromDialog) {
7859 app.anrDialog = null;
7860 }
7861 if (app.waitDialog == fromDialog) {
7862 app.waitDialog = null;
7863 }
7864 if (app.pid > 0 && app.pid != MY_PID) {
7865 if (crashed) {
7866 handleAppCrashLocked(app);
7867 }
7868 Log.i(ActivityManagerService.TAG, "Killing process "
7869 + app.processName
7870 + " (pid=" + app.pid + ") at user's request");
7871 Process.killProcess(app.pid);
7872 }
7873
7874 }
7875 }
7876
7877 boolean handleAppCrashLocked(ProcessRecord app) {
7878 long now = SystemClock.uptimeMillis();
7879
7880 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7881 app.info.uid);
7882 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7883 // This process loses!
7884 Log.w(TAG, "Process " + app.info.processName
7885 + " has crashed too many times: killing!");
7886 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7887 app.info.processName, app.info.uid);
7888 killServicesLocked(app, false);
7889 for (int i=mHistory.size()-1; i>=0; i--) {
7890 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7891 if (r.app == app) {
7892 if (Config.LOGD) Log.d(
7893 TAG, " Force finishing activity "
7894 + r.intent.getComponent().flattenToShortString());
7895 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
7896 }
7897 }
7898 if (!app.persistent) {
7899 // We don't want to start this process again until the user
7900 // explicitly does so... but for persistent process, we really
7901 // need to keep it running. If a persistent process is actually
7902 // repeatedly crashing, then badness for everyone.
7903 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
7904 app.info.processName);
7905 mBadProcesses.put(app.info.processName, app.info.uid, now);
7906 app.bad = true;
7907 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
7908 app.removed = true;
7909 removeProcessLocked(app, false);
7910 return false;
7911 }
7912 }
7913
7914 // Bump up the crash count of any services currently running in the proc.
7915 if (app.services.size() != 0) {
7916 // Any services running in the application need to be placed
7917 // back in the pending list.
7918 Iterator it = app.services.iterator();
7919 while (it.hasNext()) {
7920 ServiceRecord sr = (ServiceRecord)it.next();
7921 sr.crashCount++;
7922 }
7923 }
7924
7925 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
7926 return true;
7927 }
7928
7929 void startAppProblemLocked(ProcessRecord app) {
7930 skipCurrentReceiverLocked(app);
7931 }
7932
7933 void skipCurrentReceiverLocked(ProcessRecord app) {
7934 boolean reschedule = false;
7935 BroadcastRecord r = app.curReceiver;
7936 if (r != null) {
7937 // The current broadcast is waiting for this app's receiver
7938 // to be finished. Looks like that's not going to happen, so
7939 // let the broadcast continue.
7940 logBroadcastReceiverDiscard(r);
7941 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
7942 r.resultExtras, r.resultAbort, true);
7943 reschedule = true;
7944 }
7945 r = mPendingBroadcast;
7946 if (r != null && r.curApp == app) {
7947 if (DEBUG_BROADCAST) Log.v(TAG,
7948 "skip & discard pending app " + r);
7949 logBroadcastReceiverDiscard(r);
7950 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
7951 r.resultExtras, r.resultAbort, true);
7952 reschedule = true;
7953 }
7954 if (reschedule) {
7955 scheduleBroadcastsLocked();
7956 }
7957 }
7958
7959 public int handleApplicationError(IBinder app, int flags,
7960 String tag, String shortMsg, String longMsg, byte[] crashData) {
7961 AppErrorResult result = new AppErrorResult();
7962
7963 ProcessRecord r = null;
7964 synchronized (this) {
7965 if (app != null) {
7966 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
7967 final int NA = apps.size();
7968 for (int ia=0; ia<NA; ia++) {
7969 ProcessRecord p = apps.valueAt(ia);
7970 if (p.thread != null && p.thread.asBinder() == app) {
7971 r = p;
7972 break;
7973 }
7974 }
7975 }
7976 }
7977
7978 if (r != null) {
7979 // The application has crashed. Send the SIGQUIT to the process so
7980 // that it can dump its state.
7981 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
7982 //Log.i(TAG, "Current system threads:");
7983 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
7984 }
7985
7986 if (mWatcher != null) {
7987 try {
7988 String name = r != null ? r.processName : null;
7989 int pid = r != null ? r.pid : Binder.getCallingPid();
7990 if (!mWatcher.appCrashed(name, pid,
7991 shortMsg, longMsg, crashData)) {
7992 Log.w(TAG, "Force-killing crashed app " + name
7993 + " at watcher's request");
7994 Process.killProcess(pid);
7995 return 0;
7996 }
7997 } catch (RemoteException e) {
7998 mWatcher = null;
7999 }
8000 }
8001
8002 final long origId = Binder.clearCallingIdentity();
8003
8004 // If this process is running instrumentation, finish it.
8005 if (r != null && r.instrumentationClass != null) {
8006 Log.w(TAG, "Error in app " + r.processName
8007 + " running instrumentation " + r.instrumentationClass + ":");
8008 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8009 if (longMsg != null) Log.w(TAG, " " + longMsg);
8010 Bundle info = new Bundle();
8011 info.putString("shortMsg", shortMsg);
8012 info.putString("longMsg", longMsg);
8013 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8014 Binder.restoreCallingIdentity(origId);
8015 return 0;
8016 }
8017
8018 if (r != null) {
8019 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8020 return 0;
8021 }
8022 } else {
8023 Log.w(TAG, "Some application object " + app + " tag " + tag
8024 + " has crashed, but I don't know who it is.");
8025 Log.w(TAG, "ShortMsg:" + shortMsg);
8026 Log.w(TAG, "LongMsg:" + longMsg);
8027 Binder.restoreCallingIdentity(origId);
8028 return 0;
8029 }
8030
8031 Message msg = Message.obtain();
8032 msg.what = SHOW_ERROR_MSG;
8033 HashMap data = new HashMap();
8034 data.put("result", result);
8035 data.put("app", r);
8036 data.put("flags", flags);
8037 data.put("shortMsg", shortMsg);
8038 data.put("longMsg", longMsg);
8039 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8040 // For system processes, submit crash data to the server.
8041 data.put("crashData", crashData);
8042 }
8043 msg.obj = data;
8044 mHandler.sendMessage(msg);
8045
8046 Binder.restoreCallingIdentity(origId);
8047 }
8048
8049 int res = result.get();
8050
8051 synchronized (this) {
8052 if (r != null) {
8053 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8054 SystemClock.uptimeMillis());
8055 }
8056 }
8057
8058 return res;
8059 }
8060
8061 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8062 // assume our apps are happy - lazy create the list
8063 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8064
8065 synchronized (this) {
8066
8067 // iterate across all processes
8068 final int N = mLRUProcesses.size();
8069 for (int i = 0; i < N; i++) {
8070 ProcessRecord app = mLRUProcesses.get(i);
8071 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8072 // This one's in trouble, so we'll generate a report for it
8073 // crashes are higher priority (in case there's a crash *and* an anr)
8074 ActivityManager.ProcessErrorStateInfo report = null;
8075 if (app.crashing) {
8076 report = app.crashingReport;
8077 } else if (app.notResponding) {
8078 report = app.notRespondingReport;
8079 }
8080
8081 if (report != null) {
8082 if (errList == null) {
8083 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8084 }
8085 errList.add(report);
8086 } else {
8087 Log.w(TAG, "Missing app error report, app = " + app.processName +
8088 " crashing = " + app.crashing +
8089 " notResponding = " + app.notResponding);
8090 }
8091 }
8092 }
8093 }
8094
8095 return errList;
8096 }
8097
8098 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8099 // Lazy instantiation of list
8100 List<ActivityManager.RunningAppProcessInfo> runList = null;
8101 synchronized (this) {
8102 // Iterate across all processes
8103 final int N = mLRUProcesses.size();
8104 for (int i = 0; i < N; i++) {
8105 ProcessRecord app = mLRUProcesses.get(i);
8106 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8107 // Generate process state info for running application
8108 ActivityManager.RunningAppProcessInfo currApp =
8109 new ActivityManager.RunningAppProcessInfo(app.processName,
8110 app.pid, app.getPackageList());
8111 int adj = app.curAdj;
8112 if (adj >= CONTENT_PROVIDER_ADJ) {
8113 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8114 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8115 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008116 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8117 } else if (adj >= HOME_APP_ADJ) {
8118 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8119 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008120 } else if (adj >= SECONDARY_SERVER_ADJ) {
8121 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8122 } else if (adj >= VISIBLE_APP_ADJ) {
8123 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8124 } else {
8125 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8126 }
8127 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8128 // + " lru=" + currApp.lru);
8129 if (runList == null) {
8130 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8131 }
8132 runList.add(currApp);
8133 }
8134 }
8135 }
8136 return runList;
8137 }
8138
8139 @Override
8140 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8141 synchronized (this) {
8142 if (checkCallingPermission(android.Manifest.permission.DUMP)
8143 != PackageManager.PERMISSION_GRANTED) {
8144 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8145 + Binder.getCallingPid()
8146 + ", uid=" + Binder.getCallingUid()
8147 + " without permission "
8148 + android.Manifest.permission.DUMP);
8149 return;
8150 }
8151 if (args.length != 0 && "service".equals(args[0])) {
8152 dumpService(fd, pw, args);
8153 return;
8154 }
8155 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008156 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008157 pw.println(" ");
8158 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008159 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008160 if (mWaitingVisibleActivities.size() > 0) {
8161 pw.println(" ");
8162 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008163 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008164 }
8165 if (mStoppingActivities.size() > 0) {
8166 pw.println(" ");
8167 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008168 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008169 }
8170 if (mFinishingActivities.size() > 0) {
8171 pw.println(" ");
8172 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008173 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008174 }
8175
8176 pw.println(" ");
8177 pw.println(" mPausingActivity: " + mPausingActivity);
8178 pw.println(" mResumedActivity: " + mResumedActivity);
8179 pw.println(" mFocusedActivity: " + mFocusedActivity);
8180 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8181
8182 if (mRecentTasks.size() > 0) {
8183 pw.println(" ");
8184 pw.println("Recent tasks in Current Activity Manager State:");
8185
8186 final int N = mRecentTasks.size();
8187 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008188 TaskRecord tr = mRecentTasks.get(i);
8189 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8190 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008191 mRecentTasks.get(i).dump(pw, " ");
8192 }
8193 }
8194
8195 pw.println(" ");
8196 pw.println(" mCurTask: " + mCurTask);
8197
8198 pw.println(" ");
8199 pw.println("Processes in Current Activity Manager State:");
8200
8201 boolean needSep = false;
8202 int numPers = 0;
8203
8204 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8205 final int NA = procs.size();
8206 for (int ia=0; ia<NA; ia++) {
8207 if (!needSep) {
8208 pw.println(" All known processes:");
8209 needSep = true;
8210 }
8211 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008212 pw.print(r.persistent ? " *PERS*" : " *APP*");
8213 pw.print(" UID "); pw.print(procs.keyAt(ia));
8214 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008215 r.dump(pw, " ");
8216 if (r.persistent) {
8217 numPers++;
8218 }
8219 }
8220 }
8221
8222 if (mLRUProcesses.size() > 0) {
8223 if (needSep) pw.println(" ");
8224 needSep = true;
8225 pw.println(" Running processes (most recent first):");
8226 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008227 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008228 needSep = true;
8229 }
8230
8231 synchronized (mPidsSelfLocked) {
8232 if (mPidsSelfLocked.size() > 0) {
8233 if (needSep) pw.println(" ");
8234 needSep = true;
8235 pw.println(" PID mappings:");
8236 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008237 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8238 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008239 }
8240 }
8241 }
8242
8243 if (mForegroundProcesses.size() > 0) {
8244 if (needSep) pw.println(" ");
8245 needSep = true;
8246 pw.println(" Foreground Processes:");
8247 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008248 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8249 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008250 }
8251 }
8252
8253 if (mPersistentStartingProcesses.size() > 0) {
8254 if (needSep) pw.println(" ");
8255 needSep = true;
8256 pw.println(" Persisent processes that are starting:");
8257 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008258 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008259 }
8260
8261 if (mStartingProcesses.size() > 0) {
8262 if (needSep) pw.println(" ");
8263 needSep = true;
8264 pw.println(" Processes that are starting:");
8265 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008266 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008267 }
8268
8269 if (mRemovedProcesses.size() > 0) {
8270 if (needSep) pw.println(" ");
8271 needSep = true;
8272 pw.println(" Processes that are being removed:");
8273 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008274 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008275 }
8276
8277 if (mProcessesOnHold.size() > 0) {
8278 if (needSep) pw.println(" ");
8279 needSep = true;
8280 pw.println(" Processes that are on old until the system is ready:");
8281 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008282 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008283 }
8284
8285 if (mProcessCrashTimes.getMap().size() > 0) {
8286 if (needSep) pw.println(" ");
8287 needSep = true;
8288 pw.println(" Time since processes crashed:");
8289 long now = SystemClock.uptimeMillis();
8290 for (Map.Entry<String, SparseArray<Long>> procs
8291 : mProcessCrashTimes.getMap().entrySet()) {
8292 SparseArray<Long> uids = procs.getValue();
8293 final int N = uids.size();
8294 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008295 pw.print(" Process "); pw.print(procs.getKey());
8296 pw.print(" uid "); pw.print(uids.keyAt(i));
8297 pw.print(": last crashed ");
8298 pw.print((now-uids.valueAt(i)));
8299 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008300 }
8301 }
8302 }
8303
8304 if (mBadProcesses.getMap().size() > 0) {
8305 if (needSep) pw.println(" ");
8306 needSep = true;
8307 pw.println(" Bad processes:");
8308 for (Map.Entry<String, SparseArray<Long>> procs
8309 : mBadProcesses.getMap().entrySet()) {
8310 SparseArray<Long> uids = procs.getValue();
8311 final int N = uids.size();
8312 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008313 pw.print(" Bad process "); pw.print(procs.getKey());
8314 pw.print(" uid "); pw.print(uids.keyAt(i));
8315 pw.print(": crashed at time ");
8316 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008317 }
8318 }
8319 }
8320
8321 pw.println(" ");
8322 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008323 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008324 pw.println(" mConfiguration: " + mConfiguration);
8325 pw.println(" mStartRunning=" + mStartRunning
8326 + " mSystemReady=" + mSystemReady
8327 + " mBooting=" + mBooting
8328 + " mBooted=" + mBooted
8329 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008330 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008331 pw.println(" mGoingToSleep=" + mGoingToSleep);
8332 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8333 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8334 + " mDebugTransient=" + mDebugTransient
8335 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8336 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8337 + " mWatcher=" + mWatcher);
8338 }
8339 }
8340
8341 /**
8342 * There are three ways to call this:
8343 * - no service specified: dump all the services
8344 * - a flattened component name that matched an existing service was specified as the
8345 * first arg: dump that one service
8346 * - the first arg isn't the flattened component name of an existing service:
8347 * dump all services whose component contains the first arg as a substring
8348 */
8349 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8350 String[] newArgs;
8351 String componentNameString;
8352 ServiceRecord r;
8353 if (args.length == 1) {
8354 componentNameString = null;
8355 newArgs = EMPTY_STRING_ARRAY;
8356 r = null;
8357 } else {
8358 componentNameString = args[1];
8359 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8360 r = componentName != null ? mServices.get(componentName) : null;
8361 newArgs = new String[args.length - 2];
8362 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8363 }
8364
8365 if (r != null) {
8366 dumpService(fd, pw, r, newArgs);
8367 } else {
8368 for (ServiceRecord r1 : mServices.values()) {
8369 if (componentNameString == null
8370 || r1.name.flattenToString().contains(componentNameString)) {
8371 dumpService(fd, pw, r1, newArgs);
8372 }
8373 }
8374 }
8375 }
8376
8377 /**
8378 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8379 * there is a thread associated with the service.
8380 */
8381 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8382 pw.println(" Service " + r.name.flattenToString());
8383 if (r.app != null && r.app.thread != null) {
8384 try {
8385 // flush anything that is already in the PrintWriter since the thread is going
8386 // to write to the file descriptor directly
8387 pw.flush();
8388 r.app.thread.dumpService(fd, r, args);
8389 pw.print("\n");
8390 } catch (RemoteException e) {
8391 pw.println("got a RemoteException while dumping the service");
8392 }
8393 }
8394 }
8395
8396 void dumpBroadcasts(PrintWriter pw) {
8397 synchronized (this) {
8398 if (checkCallingPermission(android.Manifest.permission.DUMP)
8399 != PackageManager.PERMISSION_GRANTED) {
8400 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8401 + Binder.getCallingPid()
8402 + ", uid=" + Binder.getCallingUid()
8403 + " without permission "
8404 + android.Manifest.permission.DUMP);
8405 return;
8406 }
8407 pw.println("Broadcasts in Current Activity Manager State:");
8408
8409 if (mRegisteredReceivers.size() > 0) {
8410 pw.println(" ");
8411 pw.println(" Registered Receivers:");
8412 Iterator it = mRegisteredReceivers.values().iterator();
8413 while (it.hasNext()) {
8414 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008415 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008416 r.dump(pw, " ");
8417 }
8418 }
8419
8420 pw.println(" ");
8421 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008422 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008423
8424 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8425 || mPendingBroadcast != null) {
8426 if (mParallelBroadcasts.size() > 0) {
8427 pw.println(" ");
8428 pw.println(" Active broadcasts:");
8429 }
8430 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8431 pw.println(" Broadcast #" + i + ":");
8432 mParallelBroadcasts.get(i).dump(pw, " ");
8433 }
8434 if (mOrderedBroadcasts.size() > 0) {
8435 pw.println(" ");
8436 pw.println(" Active serialized broadcasts:");
8437 }
8438 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8439 pw.println(" Serialized Broadcast #" + i + ":");
8440 mOrderedBroadcasts.get(i).dump(pw, " ");
8441 }
8442 pw.println(" ");
8443 pw.println(" Pending broadcast:");
8444 if (mPendingBroadcast != null) {
8445 mPendingBroadcast.dump(pw, " ");
8446 } else {
8447 pw.println(" (null)");
8448 }
8449 }
8450
8451 pw.println(" ");
8452 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8453 if (mStickyBroadcasts != null) {
8454 pw.println(" ");
8455 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008456 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008457 for (Map.Entry<String, ArrayList<Intent>> ent
8458 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008459 pw.print(" * Sticky action "); pw.print(ent.getKey());
8460 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008461 ArrayList<Intent> intents = ent.getValue();
8462 final int N = intents.size();
8463 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008464 sb.setLength(0);
8465 sb.append(" Intent: ");
8466 intents.get(i).toShortString(sb, true, false);
8467 pw.println(sb.toString());
8468 Bundle bundle = intents.get(i).getExtras();
8469 if (bundle != null) {
8470 pw.print(" ");
8471 pw.println(bundle.toString());
8472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008473 }
8474 }
8475 }
8476
8477 pw.println(" ");
8478 pw.println(" mHandler:");
8479 mHandler.dump(new PrintWriterPrinter(pw), " ");
8480 }
8481 }
8482
8483 void dumpServices(PrintWriter pw) {
8484 synchronized (this) {
8485 if (checkCallingPermission(android.Manifest.permission.DUMP)
8486 != PackageManager.PERMISSION_GRANTED) {
8487 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8488 + Binder.getCallingPid()
8489 + ", uid=" + Binder.getCallingUid()
8490 + " without permission "
8491 + android.Manifest.permission.DUMP);
8492 return;
8493 }
8494 pw.println("Services in Current Activity Manager State:");
8495
8496 boolean needSep = false;
8497
8498 if (mServices.size() > 0) {
8499 pw.println(" Active services:");
8500 Iterator<ServiceRecord> it = mServices.values().iterator();
8501 while (it.hasNext()) {
8502 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008503 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008504 r.dump(pw, " ");
8505 }
8506 needSep = true;
8507 }
8508
8509 if (mPendingServices.size() > 0) {
8510 if (needSep) pw.println(" ");
8511 pw.println(" Pending services:");
8512 for (int i=0; i<mPendingServices.size(); i++) {
8513 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008514 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008515 r.dump(pw, " ");
8516 }
8517 needSep = true;
8518 }
8519
8520 if (mRestartingServices.size() > 0) {
8521 if (needSep) pw.println(" ");
8522 pw.println(" Restarting services:");
8523 for (int i=0; i<mRestartingServices.size(); i++) {
8524 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008525 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008526 r.dump(pw, " ");
8527 }
8528 needSep = true;
8529 }
8530
8531 if (mStoppingServices.size() > 0) {
8532 if (needSep) pw.println(" ");
8533 pw.println(" Stopping services:");
8534 for (int i=0; i<mStoppingServices.size(); i++) {
8535 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008536 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008537 r.dump(pw, " ");
8538 }
8539 needSep = true;
8540 }
8541
8542 if (mServiceConnections.size() > 0) {
8543 if (needSep) pw.println(" ");
8544 pw.println(" Connection bindings to services:");
8545 Iterator<ConnectionRecord> it
8546 = mServiceConnections.values().iterator();
8547 while (it.hasNext()) {
8548 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008549 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008550 r.dump(pw, " ");
8551 }
8552 }
8553 }
8554 }
8555
8556 void dumpProviders(PrintWriter pw) {
8557 synchronized (this) {
8558 if (checkCallingPermission(android.Manifest.permission.DUMP)
8559 != PackageManager.PERMISSION_GRANTED) {
8560 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8561 + Binder.getCallingPid()
8562 + ", uid=" + Binder.getCallingUid()
8563 + " without permission "
8564 + android.Manifest.permission.DUMP);
8565 return;
8566 }
8567
8568 pw.println("Content Providers in Current Activity Manager State:");
8569
8570 boolean needSep = false;
8571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008572 if (mProvidersByClass.size() > 0) {
8573 if (needSep) pw.println(" ");
8574 pw.println(" Published content providers (by class):");
8575 Iterator it = mProvidersByClass.entrySet().iterator();
8576 while (it.hasNext()) {
8577 Map.Entry e = (Map.Entry)it.next();
8578 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008579 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008580 r.dump(pw, " ");
8581 }
8582 needSep = true;
8583 }
8584
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008585 if (mProvidersByName.size() > 0) {
8586 pw.println(" ");
8587 pw.println(" Authority to provider mappings:");
8588 Iterator it = mProvidersByName.entrySet().iterator();
8589 while (it.hasNext()) {
8590 Map.Entry e = (Map.Entry)it.next();
8591 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8592 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8593 pw.println(r);
8594 }
8595 needSep = true;
8596 }
8597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008598 if (mLaunchingProviders.size() > 0) {
8599 if (needSep) pw.println(" ");
8600 pw.println(" Launching content providers:");
8601 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008602 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8603 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008604 }
8605 needSep = true;
8606 }
8607
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008608 if (mGrantedUriPermissions.size() > 0) {
8609 pw.println();
8610 pw.println("Granted Uri Permissions:");
8611 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8612 int uid = mGrantedUriPermissions.keyAt(i);
8613 HashMap<Uri, UriPermission> perms
8614 = mGrantedUriPermissions.valueAt(i);
8615 pw.print(" * UID "); pw.print(uid);
8616 pw.println(" holds:");
8617 for (UriPermission perm : perms.values()) {
8618 pw.print(" "); pw.println(perm);
8619 perm.dump(pw, " ");
8620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008621 }
8622 }
8623 }
8624 }
8625
8626 void dumpSenders(PrintWriter pw) {
8627 synchronized (this) {
8628 if (checkCallingPermission(android.Manifest.permission.DUMP)
8629 != PackageManager.PERMISSION_GRANTED) {
8630 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8631 + Binder.getCallingPid()
8632 + ", uid=" + Binder.getCallingUid()
8633 + " without permission "
8634 + android.Manifest.permission.DUMP);
8635 return;
8636 }
8637
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008638 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008639
8640 if (this.mIntentSenderRecords.size() > 0) {
8641 Iterator<WeakReference<PendingIntentRecord>> it
8642 = mIntentSenderRecords.values().iterator();
8643 while (it.hasNext()) {
8644 WeakReference<PendingIntentRecord> ref = it.next();
8645 PendingIntentRecord rec = ref != null ? ref.get(): null;
8646 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008647 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648 rec.dump(pw, " ");
8649 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008650 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008651 }
8652 }
8653 }
8654 }
8655 }
8656
8657 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008658 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008659 TaskRecord lastTask = null;
8660 for (int i=list.size()-1; i>=0; i--) {
8661 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008662 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008663 if (lastTask != r.task) {
8664 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008665 pw.print(prefix);
8666 pw.print(full ? "* " : " ");
8667 pw.println(lastTask);
8668 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008669 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008671 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008672 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8673 pw.print(" #"); pw.print(i); pw.print(": ");
8674 pw.println(r);
8675 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008676 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008677 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008678 }
8679 }
8680
8681 private static final int dumpProcessList(PrintWriter pw, List list,
8682 String prefix, String normalLabel, String persistentLabel,
8683 boolean inclOomAdj) {
8684 int numPers = 0;
8685 for (int i=list.size()-1; i>=0; i--) {
8686 ProcessRecord r = (ProcessRecord)list.get(i);
8687 if (false) {
8688 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8689 + " #" + i + ":");
8690 r.dump(pw, prefix + " ");
8691 } else if (inclOomAdj) {
8692 pw.println(String.format("%s%s #%2d: oom_adj=%3d %s",
8693 prefix, (r.persistent ? persistentLabel : normalLabel),
8694 i, r.setAdj, r.toString()));
8695 } else {
8696 pw.println(String.format("%s%s #%2d: %s",
8697 prefix, (r.persistent ? persistentLabel : normalLabel),
8698 i, r.toString()));
8699 }
8700 if (r.persistent) {
8701 numPers++;
8702 }
8703 }
8704 return numPers;
8705 }
8706
8707 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8708 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008709 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008710 long uptime = SystemClock.uptimeMillis();
8711 long realtime = SystemClock.elapsedRealtime();
8712
8713 if (isCheckinRequest) {
8714 // short checkin version
8715 pw.println(uptime + "," + realtime);
8716 pw.flush();
8717 } else {
8718 pw.println("Applications Memory Usage (kB):");
8719 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8720 }
8721 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8722 ProcessRecord r = (ProcessRecord)list.get(i);
8723 if (r.thread != null) {
8724 if (!isCheckinRequest) {
8725 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8726 pw.flush();
8727 }
8728 try {
8729 r.thread.asBinder().dump(fd, args);
8730 } catch (RemoteException e) {
8731 if (!isCheckinRequest) {
8732 pw.println("Got RemoteException!");
8733 pw.flush();
8734 }
8735 }
8736 }
8737 }
8738 }
8739
8740 /**
8741 * Searches array of arguments for the specified string
8742 * @param args array of argument strings
8743 * @param value value to search for
8744 * @return true if the value is contained in the array
8745 */
8746 private static boolean scanArgs(String[] args, String value) {
8747 if (args != null) {
8748 for (String arg : args) {
8749 if (value.equals(arg)) {
8750 return true;
8751 }
8752 }
8753 }
8754 return false;
8755 }
8756
8757 private final int indexOfTokenLocked(IBinder token, boolean required) {
8758 int count = mHistory.size();
8759
8760 // convert the token to an entry in the history.
8761 HistoryRecord r = null;
8762 int index = -1;
8763 for (int i=count-1; i>=0; i--) {
8764 Object o = mHistory.get(i);
8765 if (o == token) {
8766 r = (HistoryRecord)o;
8767 index = i;
8768 break;
8769 }
8770 }
8771 if (index < 0 && required) {
8772 RuntimeInit.crash(TAG, new InvalidTokenException(token));
8773 }
8774
8775 return index;
8776 }
8777
8778 static class InvalidTokenException extends Exception {
8779 InvalidTokenException(IBinder token) {
8780 super("Bad activity token: " + token);
8781 }
8782 }
8783
8784 private final void killServicesLocked(ProcessRecord app,
8785 boolean allowRestart) {
8786 // Report disconnected services.
8787 if (false) {
8788 // XXX we are letting the client link to the service for
8789 // death notifications.
8790 if (app.services.size() > 0) {
8791 Iterator it = app.services.iterator();
8792 while (it.hasNext()) {
8793 ServiceRecord r = (ServiceRecord)it.next();
8794 if (r.connections.size() > 0) {
8795 Iterator<ConnectionRecord> jt
8796 = r.connections.values().iterator();
8797 while (jt.hasNext()) {
8798 ConnectionRecord c = jt.next();
8799 if (c.binding.client != app) {
8800 try {
8801 //c.conn.connected(r.className, null);
8802 } catch (Exception e) {
8803 // todo: this should be asynchronous!
8804 Log.w(TAG, "Exception thrown disconnected servce "
8805 + r.shortName
8806 + " from app " + app.processName, e);
8807 }
8808 }
8809 }
8810 }
8811 }
8812 }
8813 }
8814
8815 // Clean up any connections this application has to other services.
8816 if (app.connections.size() > 0) {
8817 Iterator<ConnectionRecord> it = app.connections.iterator();
8818 while (it.hasNext()) {
8819 ConnectionRecord r = it.next();
8820 removeConnectionLocked(r, app, null);
8821 }
8822 }
8823 app.connections.clear();
8824
8825 if (app.services.size() != 0) {
8826 // Any services running in the application need to be placed
8827 // back in the pending list.
8828 Iterator it = app.services.iterator();
8829 while (it.hasNext()) {
8830 ServiceRecord sr = (ServiceRecord)it.next();
8831 synchronized (sr.stats.getBatteryStats()) {
8832 sr.stats.stopLaunchedLocked();
8833 }
8834 sr.app = null;
8835 sr.executeNesting = 0;
8836 mStoppingServices.remove(sr);
8837 if (sr.bindings.size() > 0) {
8838 Iterator<IntentBindRecord> bindings
8839 = sr.bindings.values().iterator();
8840 while (bindings.hasNext()) {
8841 IntentBindRecord b = bindings.next();
8842 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
8843 + ": shouldUnbind=" + b.hasBound);
8844 b.binder = null;
8845 b.requested = b.received = b.hasBound = false;
8846 }
8847 }
8848
8849 if (sr.crashCount >= 2) {
8850 Log.w(TAG, "Service crashed " + sr.crashCount
8851 + " times, stopping: " + sr);
8852 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
8853 sr.crashCount, sr.shortName, app.pid);
8854 bringDownServiceLocked(sr, true);
8855 } else if (!allowRestart) {
8856 bringDownServiceLocked(sr, true);
8857 } else {
8858 scheduleServiceRestartLocked(sr);
8859 }
8860 }
8861
8862 if (!allowRestart) {
8863 app.services.clear();
8864 }
8865 }
8866
8867 app.executingServices.clear();
8868 }
8869
8870 private final void removeDyingProviderLocked(ProcessRecord proc,
8871 ContentProviderRecord cpr) {
8872 synchronized (cpr) {
8873 cpr.launchingApp = null;
8874 cpr.notifyAll();
8875 }
8876
8877 mProvidersByClass.remove(cpr.info.name);
8878 String names[] = cpr.info.authority.split(";");
8879 for (int j = 0; j < names.length; j++) {
8880 mProvidersByName.remove(names[j]);
8881 }
8882
8883 Iterator<ProcessRecord> cit = cpr.clients.iterator();
8884 while (cit.hasNext()) {
8885 ProcessRecord capp = cit.next();
8886 if (!capp.persistent && capp.thread != null
8887 && capp.pid != 0
8888 && capp.pid != MY_PID) {
8889 Log.i(TAG, "Killing app " + capp.processName
8890 + " (pid " + capp.pid
8891 + ") because provider " + cpr.info.name
8892 + " is in dying process " + proc.processName);
8893 Process.killProcess(capp.pid);
8894 }
8895 }
8896
8897 mLaunchingProviders.remove(cpr);
8898 }
8899
8900 /**
8901 * Main code for cleaning up a process when it has gone away. This is
8902 * called both as a result of the process dying, or directly when stopping
8903 * a process when running in single process mode.
8904 */
8905 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
8906 boolean restarting, int index) {
8907 if (index >= 0) {
8908 mLRUProcesses.remove(index);
8909 }
8910
8911 // Dismiss any open dialogs.
8912 if (app.crashDialog != null) {
8913 app.crashDialog.dismiss();
8914 app.crashDialog = null;
8915 }
8916 if (app.anrDialog != null) {
8917 app.anrDialog.dismiss();
8918 app.anrDialog = null;
8919 }
8920 if (app.waitDialog != null) {
8921 app.waitDialog.dismiss();
8922 app.waitDialog = null;
8923 }
8924
8925 app.crashing = false;
8926 app.notResponding = false;
8927
8928 app.resetPackageList();
8929 app.thread = null;
8930 app.forcingToForeground = null;
8931 app.foregroundServices = false;
8932
8933 killServicesLocked(app, true);
8934
8935 boolean restart = false;
8936
8937 int NL = mLaunchingProviders.size();
8938
8939 // Remove published content providers.
8940 if (!app.pubProviders.isEmpty()) {
8941 Iterator it = app.pubProviders.values().iterator();
8942 while (it.hasNext()) {
8943 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
8944 cpr.provider = null;
8945 cpr.app = null;
8946
8947 // See if someone is waiting for this provider... in which
8948 // case we don't remove it, but just let it restart.
8949 int i = 0;
8950 if (!app.bad) {
8951 for (; i<NL; i++) {
8952 if (mLaunchingProviders.get(i) == cpr) {
8953 restart = true;
8954 break;
8955 }
8956 }
8957 } else {
8958 i = NL;
8959 }
8960
8961 if (i >= NL) {
8962 removeDyingProviderLocked(app, cpr);
8963 NL = mLaunchingProviders.size();
8964 }
8965 }
8966 app.pubProviders.clear();
8967 }
8968
8969 // Look through the content providers we are waiting to have launched,
8970 // and if any run in this process then either schedule a restart of
8971 // the process or kill the client waiting for it if this process has
8972 // gone bad.
8973 for (int i=0; i<NL; i++) {
8974 ContentProviderRecord cpr = (ContentProviderRecord)
8975 mLaunchingProviders.get(i);
8976 if (cpr.launchingApp == app) {
8977 if (!app.bad) {
8978 restart = true;
8979 } else {
8980 removeDyingProviderLocked(app, cpr);
8981 NL = mLaunchingProviders.size();
8982 }
8983 }
8984 }
8985
8986 // Unregister from connected content providers.
8987 if (!app.conProviders.isEmpty()) {
8988 Iterator it = app.conProviders.iterator();
8989 while (it.hasNext()) {
8990 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
8991 cpr.clients.remove(app);
8992 }
8993 app.conProviders.clear();
8994 }
8995
8996 skipCurrentReceiverLocked(app);
8997
8998 // Unregister any receivers.
8999 if (app.receivers.size() > 0) {
9000 Iterator<ReceiverList> it = app.receivers.iterator();
9001 while (it.hasNext()) {
9002 removeReceiverLocked(it.next());
9003 }
9004 app.receivers.clear();
9005 }
9006
9007 // If the caller is restarting this app, then leave it in its
9008 // current lists and let the caller take care of it.
9009 if (restarting) {
9010 return;
9011 }
9012
9013 if (!app.persistent) {
9014 if (DEBUG_PROCESSES) Log.v(TAG,
9015 "Removing non-persistent process during cleanup: " + app);
9016 mProcessNames.remove(app.processName, app.info.uid);
9017 } else if (!app.removed) {
9018 // This app is persistent, so we need to keep its record around.
9019 // If it is not already on the pending app list, add it there
9020 // and start a new process for it.
9021 app.thread = null;
9022 app.forcingToForeground = null;
9023 app.foregroundServices = false;
9024 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9025 mPersistentStartingProcesses.add(app);
9026 restart = true;
9027 }
9028 }
9029 mProcessesOnHold.remove(app);
9030
The Android Open Source Project4df24232009-03-05 14:34:35 -08009031 if (app == mHomeProcess) {
9032 mHomeProcess = null;
9033 }
9034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009035 if (restart) {
9036 // We have components that still need to be running in the
9037 // process, so re-launch it.
9038 mProcessNames.put(app.processName, app.info.uid, app);
9039 startProcessLocked(app, "restart", app.processName);
9040 } else if (app.pid > 0 && app.pid != MY_PID) {
9041 // Goodbye!
9042 synchronized (mPidsSelfLocked) {
9043 mPidsSelfLocked.remove(app.pid);
9044 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9045 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009046 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009047 }
9048 }
9049
9050 // =========================================================
9051 // SERVICES
9052 // =========================================================
9053
9054 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9055 ActivityManager.RunningServiceInfo info =
9056 new ActivityManager.RunningServiceInfo();
9057 info.service = r.name;
9058 if (r.app != null) {
9059 info.pid = r.app.pid;
9060 }
9061 info.process = r.processName;
9062 info.foreground = r.isForeground;
9063 info.activeSince = r.createTime;
9064 info.started = r.startRequested;
9065 info.clientCount = r.connections.size();
9066 info.crashCount = r.crashCount;
9067 info.lastActivityTime = r.lastActivity;
9068 return info;
9069 }
9070
9071 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9072 int flags) {
9073 synchronized (this) {
9074 ArrayList<ActivityManager.RunningServiceInfo> res
9075 = new ArrayList<ActivityManager.RunningServiceInfo>();
9076
9077 if (mServices.size() > 0) {
9078 Iterator<ServiceRecord> it = mServices.values().iterator();
9079 while (it.hasNext() && res.size() < maxNum) {
9080 res.add(makeRunningServiceInfoLocked(it.next()));
9081 }
9082 }
9083
9084 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9085 ServiceRecord r = mRestartingServices.get(i);
9086 ActivityManager.RunningServiceInfo info =
9087 makeRunningServiceInfoLocked(r);
9088 info.restarting = r.nextRestartTime;
9089 res.add(info);
9090 }
9091
9092 return res;
9093 }
9094 }
9095
9096 private final ServiceRecord findServiceLocked(ComponentName name,
9097 IBinder token) {
9098 ServiceRecord r = mServices.get(name);
9099 return r == token ? r : null;
9100 }
9101
9102 private final class ServiceLookupResult {
9103 final ServiceRecord record;
9104 final String permission;
9105
9106 ServiceLookupResult(ServiceRecord _record, String _permission) {
9107 record = _record;
9108 permission = _permission;
9109 }
9110 };
9111
9112 private ServiceLookupResult findServiceLocked(Intent service,
9113 String resolvedType) {
9114 ServiceRecord r = null;
9115 if (service.getComponent() != null) {
9116 r = mServices.get(service.getComponent());
9117 }
9118 if (r == null) {
9119 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9120 r = mServicesByIntent.get(filter);
9121 }
9122
9123 if (r == null) {
9124 try {
9125 ResolveInfo rInfo =
9126 ActivityThread.getPackageManager().resolveService(
9127 service, resolvedType, 0);
9128 ServiceInfo sInfo =
9129 rInfo != null ? rInfo.serviceInfo : null;
9130 if (sInfo == null) {
9131 return null;
9132 }
9133
9134 ComponentName name = new ComponentName(
9135 sInfo.applicationInfo.packageName, sInfo.name);
9136 r = mServices.get(name);
9137 } catch (RemoteException ex) {
9138 // pm is in same process, this will never happen.
9139 }
9140 }
9141 if (r != null) {
9142 int callingPid = Binder.getCallingPid();
9143 int callingUid = Binder.getCallingUid();
9144 if (checkComponentPermission(r.permission,
9145 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9146 != PackageManager.PERMISSION_GRANTED) {
9147 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9148 + " from pid=" + callingPid
9149 + ", uid=" + callingUid
9150 + " requires " + r.permission);
9151 return new ServiceLookupResult(null, r.permission);
9152 }
9153 return new ServiceLookupResult(r, null);
9154 }
9155 return null;
9156 }
9157
9158 private class ServiceRestarter implements Runnable {
9159 private ServiceRecord mService;
9160
9161 void setService(ServiceRecord service) {
9162 mService = service;
9163 }
9164
9165 public void run() {
9166 synchronized(ActivityManagerService.this) {
9167 performServiceRestartLocked(mService);
9168 }
9169 }
9170 }
9171
9172 private ServiceLookupResult retrieveServiceLocked(Intent service,
9173 String resolvedType, int callingPid, int callingUid) {
9174 ServiceRecord r = null;
9175 if (service.getComponent() != null) {
9176 r = mServices.get(service.getComponent());
9177 }
9178 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9179 r = mServicesByIntent.get(filter);
9180 if (r == null) {
9181 try {
9182 ResolveInfo rInfo =
9183 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009184 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009185 ServiceInfo sInfo =
9186 rInfo != null ? rInfo.serviceInfo : null;
9187 if (sInfo == null) {
9188 Log.w(TAG, "Unable to start service " + service +
9189 ": not found");
9190 return null;
9191 }
9192
9193 ComponentName name = new ComponentName(
9194 sInfo.applicationInfo.packageName, sInfo.name);
9195 r = mServices.get(name);
9196 if (r == null) {
9197 filter = new Intent.FilterComparison(service.cloneFilter());
9198 ServiceRestarter res = new ServiceRestarter();
9199 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9200 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9201 synchronized (stats) {
9202 ss = stats.getServiceStatsLocked(
9203 sInfo.applicationInfo.uid, sInfo.packageName,
9204 sInfo.name);
9205 }
9206 r = new ServiceRecord(ss, name, filter, sInfo, res);
9207 res.setService(r);
9208 mServices.put(name, r);
9209 mServicesByIntent.put(filter, r);
9210
9211 // Make sure this component isn't in the pending list.
9212 int N = mPendingServices.size();
9213 for (int i=0; i<N; i++) {
9214 ServiceRecord pr = mPendingServices.get(i);
9215 if (pr.name.equals(name)) {
9216 mPendingServices.remove(i);
9217 i--;
9218 N--;
9219 }
9220 }
9221 }
9222 } catch (RemoteException ex) {
9223 // pm is in same process, this will never happen.
9224 }
9225 }
9226 if (r != null) {
9227 if (checkComponentPermission(r.permission,
9228 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9229 != PackageManager.PERMISSION_GRANTED) {
9230 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9231 + " from pid=" + Binder.getCallingPid()
9232 + ", uid=" + Binder.getCallingUid()
9233 + " requires " + r.permission);
9234 return new ServiceLookupResult(null, r.permission);
9235 }
9236 return new ServiceLookupResult(r, null);
9237 }
9238 return null;
9239 }
9240
9241 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9242 long now = SystemClock.uptimeMillis();
9243 if (r.executeNesting == 0 && r.app != null) {
9244 if (r.app.executingServices.size() == 0) {
9245 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9246 msg.obj = r.app;
9247 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9248 }
9249 r.app.executingServices.add(r);
9250 }
9251 r.executeNesting++;
9252 r.executingStart = now;
9253 }
9254
9255 private final void sendServiceArgsLocked(ServiceRecord r,
9256 boolean oomAdjusted) {
9257 final int N = r.startArgs.size();
9258 if (N == 0) {
9259 return;
9260 }
9261
9262 final int BASEID = r.lastStartId - N + 1;
9263 int i = 0;
9264 while (i < N) {
9265 try {
9266 Intent args = r.startArgs.get(i);
9267 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9268 + r.name + " " + r.intent + " args=" + args);
9269 bumpServiceExecutingLocked(r);
9270 if (!oomAdjusted) {
9271 oomAdjusted = true;
9272 updateOomAdjLocked(r.app);
9273 }
9274 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9275 i++;
9276 } catch (Exception e) {
9277 break;
9278 }
9279 }
9280 if (i == N) {
9281 r.startArgs.clear();
9282 } else {
9283 while (i > 0) {
9284 r.startArgs.remove(0);
9285 i--;
9286 }
9287 }
9288 }
9289
9290 private final boolean requestServiceBindingLocked(ServiceRecord r,
9291 IntentBindRecord i, boolean rebind) {
9292 if (r.app == null || r.app.thread == null) {
9293 // If service is not currently running, can't yet bind.
9294 return false;
9295 }
9296 if ((!i.requested || rebind) && i.apps.size() > 0) {
9297 try {
9298 bumpServiceExecutingLocked(r);
9299 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9300 + ": shouldUnbind=" + i.hasBound);
9301 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9302 if (!rebind) {
9303 i.requested = true;
9304 }
9305 i.hasBound = true;
9306 i.doRebind = false;
9307 } catch (RemoteException e) {
9308 return false;
9309 }
9310 }
9311 return true;
9312 }
9313
9314 private final void requestServiceBindingsLocked(ServiceRecord r) {
9315 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9316 while (bindings.hasNext()) {
9317 IntentBindRecord i = bindings.next();
9318 if (!requestServiceBindingLocked(r, i, false)) {
9319 break;
9320 }
9321 }
9322 }
9323
9324 private final void realStartServiceLocked(ServiceRecord r,
9325 ProcessRecord app) throws RemoteException {
9326 if (app.thread == null) {
9327 throw new RemoteException();
9328 }
9329
9330 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009331 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009332
9333 app.services.add(r);
9334 bumpServiceExecutingLocked(r);
9335 updateLRUListLocked(app, true);
9336
9337 boolean created = false;
9338 try {
9339 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9340 + r.name + " " + r.intent);
9341 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9342 System.identityHashCode(r), r.shortName,
9343 r.intent.getIntent().toString(), r.app.pid);
9344 synchronized (r.stats.getBatteryStats()) {
9345 r.stats.startLaunchedLocked();
9346 }
9347 app.thread.scheduleCreateService(r, r.serviceInfo);
9348 created = true;
9349 } finally {
9350 if (!created) {
9351 app.services.remove(r);
9352 scheduleServiceRestartLocked(r);
9353 }
9354 }
9355
9356 requestServiceBindingsLocked(r);
9357 sendServiceArgsLocked(r, true);
9358 }
9359
9360 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9361 r.totalRestartCount++;
9362 if (r.restartDelay == 0) {
9363 r.restartCount++;
9364 r.restartDelay = SERVICE_RESTART_DURATION;
9365 } else {
9366 // If it has been a "reasonably long time" since the service
9367 // was started, then reset our restart duration back to
9368 // the beginning, so we don't infinitely increase the duration
9369 // on a service that just occasionally gets killed (which is
9370 // a normal case, due to process being killed to reclaim memory).
9371 long now = SystemClock.uptimeMillis();
9372 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9373 r.restartCount = 1;
9374 r.restartDelay = SERVICE_RESTART_DURATION;
9375 } else {
9376 r.restartDelay *= 2;
9377 }
9378 }
9379 if (!mRestartingServices.contains(r)) {
9380 mRestartingServices.add(r);
9381 }
9382 mHandler.removeCallbacks(r.restarter);
9383 mHandler.postDelayed(r.restarter, r.restartDelay);
9384 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9385 Log.w(TAG, "Scheduling restart of crashed service "
9386 + r.shortName + " in " + r.restartDelay + "ms");
9387 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9388 r.shortName, r.restartDelay);
9389
9390 Message msg = Message.obtain();
9391 msg.what = SERVICE_ERROR_MSG;
9392 msg.obj = r;
9393 mHandler.sendMessage(msg);
9394 }
9395
9396 final void performServiceRestartLocked(ServiceRecord r) {
9397 if (!mRestartingServices.contains(r)) {
9398 return;
9399 }
9400 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9401 }
9402
9403 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9404 if (r.restartDelay == 0) {
9405 return false;
9406 }
9407 r.resetRestartCounter();
9408 mRestartingServices.remove(r);
9409 mHandler.removeCallbacks(r.restarter);
9410 return true;
9411 }
9412
9413 private final boolean bringUpServiceLocked(ServiceRecord r,
9414 int intentFlags, boolean whileRestarting) {
9415 //Log.i(TAG, "Bring up service:");
9416 //r.dump(" ");
9417
9418 if (r.app != null) {
9419 sendServiceArgsLocked(r, false);
9420 return true;
9421 }
9422
9423 if (!whileRestarting && r.restartDelay > 0) {
9424 // If waiting for a restart, then do nothing.
9425 return true;
9426 }
9427
9428 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9429 + " " + r.intent);
9430
9431 final String appName = r.processName;
9432 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9433 if (app != null && app.thread != null) {
9434 try {
9435 realStartServiceLocked(r, app);
9436 return true;
9437 } catch (RemoteException e) {
9438 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9439 }
9440
9441 // If a dead object exception was thrown -- fall through to
9442 // restart the application.
9443 }
9444
9445 if (!mPendingServices.contains(r)) {
9446 // Not running -- get it started, and enqueue this service record
9447 // to be executed when the app comes up.
9448 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9449 "service", r.name) == null) {
9450 Log.w(TAG, "Unable to launch app "
9451 + r.appInfo.packageName + "/"
9452 + r.appInfo.uid + " for service "
9453 + r.intent.getIntent() + ": process is bad");
9454 bringDownServiceLocked(r, true);
9455 return false;
9456 }
9457 mPendingServices.add(r);
9458 }
9459 return true;
9460 }
9461
9462 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9463 //Log.i(TAG, "Bring down service:");
9464 //r.dump(" ");
9465
9466 // Does it still need to run?
9467 if (!force && r.startRequested) {
9468 return;
9469 }
9470 if (r.connections.size() > 0) {
9471 if (!force) {
9472 // XXX should probably keep a count of the number of auto-create
9473 // connections directly in the service.
9474 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9475 while (it.hasNext()) {
9476 ConnectionRecord cr = it.next();
9477 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9478 return;
9479 }
9480 }
9481 }
9482
9483 // Report to all of the connections that the service is no longer
9484 // available.
9485 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9486 while (it.hasNext()) {
9487 ConnectionRecord c = it.next();
9488 try {
9489 // todo: shouldn't be a synchronous call!
9490 c.conn.connected(r.name, null);
9491 } catch (Exception e) {
9492 Log.w(TAG, "Failure disconnecting service " + r.name +
9493 " to connection " + c.conn.asBinder() +
9494 " (in " + c.binding.client.processName + ")", e);
9495 }
9496 }
9497 }
9498
9499 // Tell the service that it has been unbound.
9500 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9501 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9502 while (it.hasNext()) {
9503 IntentBindRecord ibr = it.next();
9504 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9505 + ": hasBound=" + ibr.hasBound);
9506 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9507 try {
9508 bumpServiceExecutingLocked(r);
9509 updateOomAdjLocked(r.app);
9510 ibr.hasBound = false;
9511 r.app.thread.scheduleUnbindService(r,
9512 ibr.intent.getIntent());
9513 } catch (Exception e) {
9514 Log.w(TAG, "Exception when unbinding service "
9515 + r.shortName, e);
9516 serviceDoneExecutingLocked(r, true);
9517 }
9518 }
9519 }
9520 }
9521
9522 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9523 + " " + r.intent);
9524 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9525 System.identityHashCode(r), r.shortName,
9526 (r.app != null) ? r.app.pid : -1);
9527
9528 mServices.remove(r.name);
9529 mServicesByIntent.remove(r.intent);
9530 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9531 r.totalRestartCount = 0;
9532 unscheduleServiceRestartLocked(r);
9533
9534 // Also make sure it is not on the pending list.
9535 int N = mPendingServices.size();
9536 for (int i=0; i<N; i++) {
9537 if (mPendingServices.get(i) == r) {
9538 mPendingServices.remove(i);
9539 if (DEBUG_SERVICE) Log.v(
9540 TAG, "Removed pending service: " + r.shortName);
9541 i--;
9542 N--;
9543 }
9544 }
9545
9546 if (r.app != null) {
9547 synchronized (r.stats.getBatteryStats()) {
9548 r.stats.stopLaunchedLocked();
9549 }
9550 r.app.services.remove(r);
9551 if (r.app.thread != null) {
9552 updateServiceForegroundLocked(r.app, false);
9553 try {
9554 Log.i(TAG, "Stopping service: " + r.shortName);
9555 bumpServiceExecutingLocked(r);
9556 mStoppingServices.add(r);
9557 updateOomAdjLocked(r.app);
9558 r.app.thread.scheduleStopService(r);
9559 } catch (Exception e) {
9560 Log.w(TAG, "Exception when stopping service "
9561 + r.shortName, e);
9562 serviceDoneExecutingLocked(r, true);
9563 }
9564 } else {
9565 if (DEBUG_SERVICE) Log.v(
9566 TAG, "Removed service that has no process: " + r.shortName);
9567 }
9568 } else {
9569 if (DEBUG_SERVICE) Log.v(
9570 TAG, "Removed service that is not running: " + r.shortName);
9571 }
9572 }
9573
9574 ComponentName startServiceLocked(IApplicationThread caller,
9575 Intent service, String resolvedType,
9576 int callingPid, int callingUid) {
9577 synchronized(this) {
9578 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9579 + " type=" + resolvedType + " args=" + service.getExtras());
9580
9581 if (caller != null) {
9582 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9583 if (callerApp == null) {
9584 throw new SecurityException(
9585 "Unable to find app for caller " + caller
9586 + " (pid=" + Binder.getCallingPid()
9587 + ") when starting service " + service);
9588 }
9589 }
9590
9591 ServiceLookupResult res =
9592 retrieveServiceLocked(service, resolvedType,
9593 callingPid, callingUid);
9594 if (res == null) {
9595 return null;
9596 }
9597 if (res.record == null) {
9598 return new ComponentName("!", res.permission != null
9599 ? res.permission : "private to package");
9600 }
9601 ServiceRecord r = res.record;
9602 if (unscheduleServiceRestartLocked(r)) {
9603 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9604 + r.shortName);
9605 }
9606 r.startRequested = true;
9607 r.startArgs.add(service);
9608 r.lastStartId++;
9609 if (r.lastStartId < 1) {
9610 r.lastStartId = 1;
9611 }
9612 r.lastActivity = SystemClock.uptimeMillis();
9613 synchronized (r.stats.getBatteryStats()) {
9614 r.stats.startRunningLocked();
9615 }
9616 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9617 return new ComponentName("!", "Service process is bad");
9618 }
9619 return r.name;
9620 }
9621 }
9622
9623 public ComponentName startService(IApplicationThread caller, Intent service,
9624 String resolvedType) {
9625 // Refuse possible leaked file descriptors
9626 if (service != null && service.hasFileDescriptors() == true) {
9627 throw new IllegalArgumentException("File descriptors passed in Intent");
9628 }
9629
9630 synchronized(this) {
9631 final int callingPid = Binder.getCallingPid();
9632 final int callingUid = Binder.getCallingUid();
9633 final long origId = Binder.clearCallingIdentity();
9634 ComponentName res = startServiceLocked(caller, service,
9635 resolvedType, callingPid, callingUid);
9636 Binder.restoreCallingIdentity(origId);
9637 return res;
9638 }
9639 }
9640
9641 ComponentName startServiceInPackage(int uid,
9642 Intent service, String resolvedType) {
9643 synchronized(this) {
9644 final long origId = Binder.clearCallingIdentity();
9645 ComponentName res = startServiceLocked(null, service,
9646 resolvedType, -1, uid);
9647 Binder.restoreCallingIdentity(origId);
9648 return res;
9649 }
9650 }
9651
9652 public int stopService(IApplicationThread caller, Intent service,
9653 String resolvedType) {
9654 // Refuse possible leaked file descriptors
9655 if (service != null && service.hasFileDescriptors() == true) {
9656 throw new IllegalArgumentException("File descriptors passed in Intent");
9657 }
9658
9659 synchronized(this) {
9660 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9661 + " type=" + resolvedType);
9662
9663 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9664 if (caller != null && callerApp == null) {
9665 throw new SecurityException(
9666 "Unable to find app for caller " + caller
9667 + " (pid=" + Binder.getCallingPid()
9668 + ") when stopping service " + service);
9669 }
9670
9671 // If this service is active, make sure it is stopped.
9672 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9673 if (r != null) {
9674 if (r.record != null) {
9675 synchronized (r.record.stats.getBatteryStats()) {
9676 r.record.stats.stopRunningLocked();
9677 }
9678 r.record.startRequested = false;
9679 final long origId = Binder.clearCallingIdentity();
9680 bringDownServiceLocked(r.record, false);
9681 Binder.restoreCallingIdentity(origId);
9682 return 1;
9683 }
9684 return -1;
9685 }
9686 }
9687
9688 return 0;
9689 }
9690
9691 public IBinder peekService(Intent service, String resolvedType) {
9692 // Refuse possible leaked file descriptors
9693 if (service != null && service.hasFileDescriptors() == true) {
9694 throw new IllegalArgumentException("File descriptors passed in Intent");
9695 }
9696
9697 IBinder ret = null;
9698
9699 synchronized(this) {
9700 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9701
9702 if (r != null) {
9703 // r.record is null if findServiceLocked() failed the caller permission check
9704 if (r.record == null) {
9705 throw new SecurityException(
9706 "Permission Denial: Accessing service " + r.record.name
9707 + " from pid=" + Binder.getCallingPid()
9708 + ", uid=" + Binder.getCallingUid()
9709 + " requires " + r.permission);
9710 }
9711 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9712 if (ib != null) {
9713 ret = ib.binder;
9714 }
9715 }
9716 }
9717
9718 return ret;
9719 }
9720
9721 public boolean stopServiceToken(ComponentName className, IBinder token,
9722 int startId) {
9723 synchronized(this) {
9724 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9725 + " " + token + " startId=" + startId);
9726 ServiceRecord r = findServiceLocked(className, token);
9727 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9728 synchronized (r.stats.getBatteryStats()) {
9729 r.stats.stopRunningLocked();
9730 r.startRequested = false;
9731 }
9732 final long origId = Binder.clearCallingIdentity();
9733 bringDownServiceLocked(r, false);
9734 Binder.restoreCallingIdentity(origId);
9735 return true;
9736 }
9737 }
9738 return false;
9739 }
9740
9741 public void setServiceForeground(ComponentName className, IBinder token,
9742 boolean isForeground) {
9743 synchronized(this) {
9744 ServiceRecord r = findServiceLocked(className, token);
9745 if (r != null) {
9746 if (r.isForeground != isForeground) {
9747 final long origId = Binder.clearCallingIdentity();
9748 r.isForeground = isForeground;
9749 if (r.app != null) {
9750 updateServiceForegroundLocked(r.app, true);
9751 }
9752 Binder.restoreCallingIdentity(origId);
9753 }
9754 }
9755 }
9756 }
9757
9758 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9759 boolean anyForeground = false;
9760 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9761 if (sr.isForeground) {
9762 anyForeground = true;
9763 break;
9764 }
9765 }
9766 if (anyForeground != proc.foregroundServices) {
9767 proc.foregroundServices = anyForeground;
9768 if (oomAdj) {
9769 updateOomAdjLocked();
9770 }
9771 }
9772 }
9773
9774 public int bindService(IApplicationThread caller, IBinder token,
9775 Intent service, String resolvedType,
9776 IServiceConnection connection, int flags) {
9777 // Refuse possible leaked file descriptors
9778 if (service != null && service.hasFileDescriptors() == true) {
9779 throw new IllegalArgumentException("File descriptors passed in Intent");
9780 }
9781
9782 synchronized(this) {
9783 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9784 + " type=" + resolvedType + " conn=" + connection.asBinder()
9785 + " flags=0x" + Integer.toHexString(flags));
9786 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9787 if (callerApp == null) {
9788 throw new SecurityException(
9789 "Unable to find app for caller " + caller
9790 + " (pid=" + Binder.getCallingPid()
9791 + ") when binding service " + service);
9792 }
9793
9794 HistoryRecord activity = null;
9795 if (token != null) {
9796 int aindex = indexOfTokenLocked(token, false);
9797 if (aindex < 0) {
9798 Log.w(TAG, "Binding with unknown activity: " + token);
9799 return 0;
9800 }
9801 activity = (HistoryRecord)mHistory.get(aindex);
9802 }
9803
9804 ServiceLookupResult res =
9805 retrieveServiceLocked(service, resolvedType,
9806 Binder.getCallingPid(), Binder.getCallingUid());
9807 if (res == null) {
9808 return 0;
9809 }
9810 if (res.record == null) {
9811 return -1;
9812 }
9813 ServiceRecord s = res.record;
9814
9815 final long origId = Binder.clearCallingIdentity();
9816
9817 if (unscheduleServiceRestartLocked(s)) {
9818 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
9819 + s.shortName);
9820 }
9821
9822 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
9823 ConnectionRecord c = new ConnectionRecord(b, activity,
9824 connection, flags);
9825
9826 IBinder binder = connection.asBinder();
9827 s.connections.put(binder, c);
9828 b.connections.add(c);
9829 if (activity != null) {
9830 if (activity.connections == null) {
9831 activity.connections = new HashSet<ConnectionRecord>();
9832 }
9833 activity.connections.add(c);
9834 }
9835 b.client.connections.add(c);
9836 mServiceConnections.put(binder, c);
9837
9838 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
9839 s.lastActivity = SystemClock.uptimeMillis();
9840 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
9841 return 0;
9842 }
9843 }
9844
9845 if (s.app != null) {
9846 // This could have made the service more important.
9847 updateOomAdjLocked(s.app);
9848 }
9849
9850 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
9851 + ": received=" + b.intent.received
9852 + " apps=" + b.intent.apps.size()
9853 + " doRebind=" + b.intent.doRebind);
9854
9855 if (s.app != null && b.intent.received) {
9856 // Service is already running, so we can immediately
9857 // publish the connection.
9858 try {
9859 c.conn.connected(s.name, b.intent.binder);
9860 } catch (Exception e) {
9861 Log.w(TAG, "Failure sending service " + s.shortName
9862 + " to connection " + c.conn.asBinder()
9863 + " (in " + c.binding.client.processName + ")", e);
9864 }
9865
9866 // If this is the first app connected back to this binding,
9867 // and the service had previously asked to be told when
9868 // rebound, then do so.
9869 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
9870 requestServiceBindingLocked(s, b.intent, true);
9871 }
9872 } else if (!b.intent.requested) {
9873 requestServiceBindingLocked(s, b.intent, false);
9874 }
9875
9876 Binder.restoreCallingIdentity(origId);
9877 }
9878
9879 return 1;
9880 }
9881
9882 private void removeConnectionLocked(
9883 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
9884 IBinder binder = c.conn.asBinder();
9885 AppBindRecord b = c.binding;
9886 ServiceRecord s = b.service;
9887 s.connections.remove(binder);
9888 b.connections.remove(c);
9889 if (c.activity != null && c.activity != skipAct) {
9890 if (c.activity.connections != null) {
9891 c.activity.connections.remove(c);
9892 }
9893 }
9894 if (b.client != skipApp) {
9895 b.client.connections.remove(c);
9896 }
9897 mServiceConnections.remove(binder);
9898
9899 if (b.connections.size() == 0) {
9900 b.intent.apps.remove(b.client);
9901 }
9902
9903 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
9904 + ": shouldUnbind=" + b.intent.hasBound);
9905 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
9906 && b.intent.hasBound) {
9907 try {
9908 bumpServiceExecutingLocked(s);
9909 updateOomAdjLocked(s.app);
9910 b.intent.hasBound = false;
9911 // Assume the client doesn't want to know about a rebind;
9912 // we will deal with that later if it asks for one.
9913 b.intent.doRebind = false;
9914 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
9915 } catch (Exception e) {
9916 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
9917 serviceDoneExecutingLocked(s, true);
9918 }
9919 }
9920
9921 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
9922 bringDownServiceLocked(s, false);
9923 }
9924 }
9925
9926 public boolean unbindService(IServiceConnection connection) {
9927 synchronized (this) {
9928 IBinder binder = connection.asBinder();
9929 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
9930 ConnectionRecord r = mServiceConnections.get(binder);
9931 if (r == null) {
9932 Log.w(TAG, "Unbind failed: could not find connection for "
9933 + connection.asBinder());
9934 return false;
9935 }
9936
9937 final long origId = Binder.clearCallingIdentity();
9938
9939 removeConnectionLocked(r, null, null);
9940
9941 if (r.binding.service.app != null) {
9942 // This could have made the service less important.
9943 updateOomAdjLocked(r.binding.service.app);
9944 }
9945
9946 Binder.restoreCallingIdentity(origId);
9947 }
9948
9949 return true;
9950 }
9951
9952 public void publishService(IBinder token, Intent intent, IBinder service) {
9953 // Refuse possible leaked file descriptors
9954 if (intent != null && intent.hasFileDescriptors() == true) {
9955 throw new IllegalArgumentException("File descriptors passed in Intent");
9956 }
9957
9958 synchronized(this) {
9959 if (!(token instanceof ServiceRecord)) {
9960 throw new IllegalArgumentException("Invalid service token");
9961 }
9962 ServiceRecord r = (ServiceRecord)token;
9963
9964 final long origId = Binder.clearCallingIdentity();
9965
9966 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
9967 + " " + intent + ": " + service);
9968 if (r != null) {
9969 Intent.FilterComparison filter
9970 = new Intent.FilterComparison(intent);
9971 IntentBindRecord b = r.bindings.get(filter);
9972 if (b != null && !b.received) {
9973 b.binder = service;
9974 b.requested = true;
9975 b.received = true;
9976 if (r.connections.size() > 0) {
9977 Iterator<ConnectionRecord> it
9978 = r.connections.values().iterator();
9979 while (it.hasNext()) {
9980 ConnectionRecord c = it.next();
9981 if (!filter.equals(c.binding.intent.intent)) {
9982 if (DEBUG_SERVICE) Log.v(
9983 TAG, "Not publishing to: " + c);
9984 if (DEBUG_SERVICE) Log.v(
9985 TAG, "Bound intent: " + c.binding.intent.intent);
9986 if (DEBUG_SERVICE) Log.v(
9987 TAG, "Published intent: " + intent);
9988 continue;
9989 }
9990 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
9991 try {
9992 c.conn.connected(r.name, service);
9993 } catch (Exception e) {
9994 Log.w(TAG, "Failure sending service " + r.name +
9995 " to connection " + c.conn.asBinder() +
9996 " (in " + c.binding.client.processName + ")", e);
9997 }
9998 }
9999 }
10000 }
10001
10002 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10003
10004 Binder.restoreCallingIdentity(origId);
10005 }
10006 }
10007 }
10008
10009 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10010 // Refuse possible leaked file descriptors
10011 if (intent != null && intent.hasFileDescriptors() == true) {
10012 throw new IllegalArgumentException("File descriptors passed in Intent");
10013 }
10014
10015 synchronized(this) {
10016 if (!(token instanceof ServiceRecord)) {
10017 throw new IllegalArgumentException("Invalid service token");
10018 }
10019 ServiceRecord r = (ServiceRecord)token;
10020
10021 final long origId = Binder.clearCallingIdentity();
10022
10023 if (r != null) {
10024 Intent.FilterComparison filter
10025 = new Intent.FilterComparison(intent);
10026 IntentBindRecord b = r.bindings.get(filter);
10027 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10028 + " at " + b + ": apps="
10029 + (b != null ? b.apps.size() : 0));
10030 if (b != null) {
10031 if (b.apps.size() > 0) {
10032 // Applications have already bound since the last
10033 // unbind, so just rebind right here.
10034 requestServiceBindingLocked(r, b, true);
10035 } else {
10036 // Note to tell the service the next time there is
10037 // a new client.
10038 b.doRebind = true;
10039 }
10040 }
10041
10042 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10043
10044 Binder.restoreCallingIdentity(origId);
10045 }
10046 }
10047 }
10048
10049 public void serviceDoneExecuting(IBinder token) {
10050 synchronized(this) {
10051 if (!(token instanceof ServiceRecord)) {
10052 throw new IllegalArgumentException("Invalid service token");
10053 }
10054 ServiceRecord r = (ServiceRecord)token;
10055 boolean inStopping = mStoppingServices.contains(token);
10056 if (r != null) {
10057 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10058 + ": nesting=" + r.executeNesting
10059 + ", inStopping=" + inStopping);
10060 if (r != token) {
10061 Log.w(TAG, "Done executing service " + r.name
10062 + " with incorrect token: given " + token
10063 + ", expected " + r);
10064 return;
10065 }
10066
10067 final long origId = Binder.clearCallingIdentity();
10068 serviceDoneExecutingLocked(r, inStopping);
10069 Binder.restoreCallingIdentity(origId);
10070 } else {
10071 Log.w(TAG, "Done executing unknown service " + r.name
10072 + " with token " + token);
10073 }
10074 }
10075 }
10076
10077 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10078 r.executeNesting--;
10079 if (r.executeNesting <= 0 && r.app != null) {
10080 r.app.executingServices.remove(r);
10081 if (r.app.executingServices.size() == 0) {
10082 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10083 }
10084 if (inStopping) {
10085 mStoppingServices.remove(r);
10086 }
10087 updateOomAdjLocked(r.app);
10088 }
10089 }
10090
10091 void serviceTimeout(ProcessRecord proc) {
10092 synchronized(this) {
10093 if (proc.executingServices.size() == 0 || proc.thread == null) {
10094 return;
10095 }
10096 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10097 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10098 ServiceRecord timeout = null;
10099 long nextTime = 0;
10100 while (it.hasNext()) {
10101 ServiceRecord sr = it.next();
10102 if (sr.executingStart < maxTime) {
10103 timeout = sr;
10104 break;
10105 }
10106 if (sr.executingStart > nextTime) {
10107 nextTime = sr.executingStart;
10108 }
10109 }
10110 if (timeout != null && mLRUProcesses.contains(proc)) {
10111 Log.w(TAG, "Timeout executing service: " + timeout);
10112 appNotRespondingLocked(proc, null, "Executing service "
10113 + timeout.name);
10114 } else {
10115 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10116 msg.obj = proc;
10117 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10118 }
10119 }
10120 }
10121
10122 // =========================================================
10123 // BROADCASTS
10124 // =========================================================
10125
10126 private final List getStickies(String action, IntentFilter filter,
10127 List cur) {
10128 final ContentResolver resolver = mContext.getContentResolver();
10129 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10130 if (list == null) {
10131 return cur;
10132 }
10133 int N = list.size();
10134 for (int i=0; i<N; i++) {
10135 Intent intent = list.get(i);
10136 if (filter.match(resolver, intent, true, TAG) >= 0) {
10137 if (cur == null) {
10138 cur = new ArrayList<Intent>();
10139 }
10140 cur.add(intent);
10141 }
10142 }
10143 return cur;
10144 }
10145
10146 private final void scheduleBroadcastsLocked() {
10147 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10148 + mBroadcastsScheduled);
10149
10150 if (mBroadcastsScheduled) {
10151 return;
10152 }
10153 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10154 mBroadcastsScheduled = true;
10155 }
10156
10157 public Intent registerReceiver(IApplicationThread caller,
10158 IIntentReceiver receiver, IntentFilter filter, String permission) {
10159 synchronized(this) {
10160 ProcessRecord callerApp = null;
10161 if (caller != null) {
10162 callerApp = getRecordForAppLocked(caller);
10163 if (callerApp == null) {
10164 throw new SecurityException(
10165 "Unable to find app for caller " + caller
10166 + " (pid=" + Binder.getCallingPid()
10167 + ") when registering receiver " + receiver);
10168 }
10169 }
10170
10171 List allSticky = null;
10172
10173 // Look for any matching sticky broadcasts...
10174 Iterator actions = filter.actionsIterator();
10175 if (actions != null) {
10176 while (actions.hasNext()) {
10177 String action = (String)actions.next();
10178 allSticky = getStickies(action, filter, allSticky);
10179 }
10180 } else {
10181 allSticky = getStickies(null, filter, allSticky);
10182 }
10183
10184 // The first sticky in the list is returned directly back to
10185 // the client.
10186 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10187
10188 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10189 + ": " + sticky);
10190
10191 if (receiver == null) {
10192 return sticky;
10193 }
10194
10195 ReceiverList rl
10196 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10197 if (rl == null) {
10198 rl = new ReceiverList(this, callerApp,
10199 Binder.getCallingPid(),
10200 Binder.getCallingUid(), receiver);
10201 if (rl.app != null) {
10202 rl.app.receivers.add(rl);
10203 } else {
10204 try {
10205 receiver.asBinder().linkToDeath(rl, 0);
10206 } catch (RemoteException e) {
10207 return sticky;
10208 }
10209 rl.linkedToDeath = true;
10210 }
10211 mRegisteredReceivers.put(receiver.asBinder(), rl);
10212 }
10213 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10214 rl.add(bf);
10215 if (!bf.debugCheck()) {
10216 Log.w(TAG, "==> For Dynamic broadast");
10217 }
10218 mReceiverResolver.addFilter(bf);
10219
10220 // Enqueue broadcasts for all existing stickies that match
10221 // this filter.
10222 if (allSticky != null) {
10223 ArrayList receivers = new ArrayList();
10224 receivers.add(bf);
10225
10226 int N = allSticky.size();
10227 for (int i=0; i<N; i++) {
10228 Intent intent = (Intent)allSticky.get(i);
10229 BroadcastRecord r = new BroadcastRecord(intent, null,
10230 null, -1, -1, null, receivers, null, 0, null, null,
10231 false);
10232 if (mParallelBroadcasts.size() == 0) {
10233 scheduleBroadcastsLocked();
10234 }
10235 mParallelBroadcasts.add(r);
10236 }
10237 }
10238
10239 return sticky;
10240 }
10241 }
10242
10243 public void unregisterReceiver(IIntentReceiver receiver) {
10244 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10245
10246 boolean doNext = false;
10247
10248 synchronized(this) {
10249 ReceiverList rl
10250 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10251 if (rl != null) {
10252 if (rl.curBroadcast != null) {
10253 BroadcastRecord r = rl.curBroadcast;
10254 doNext = finishReceiverLocked(
10255 receiver.asBinder(), r.resultCode, r.resultData,
10256 r.resultExtras, r.resultAbort, true);
10257 }
10258
10259 if (rl.app != null) {
10260 rl.app.receivers.remove(rl);
10261 }
10262 removeReceiverLocked(rl);
10263 if (rl.linkedToDeath) {
10264 rl.linkedToDeath = false;
10265 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10266 }
10267 }
10268 }
10269
10270 if (!doNext) {
10271 return;
10272 }
10273
10274 final long origId = Binder.clearCallingIdentity();
10275 processNextBroadcast(false);
10276 trimApplications();
10277 Binder.restoreCallingIdentity(origId);
10278 }
10279
10280 void removeReceiverLocked(ReceiverList rl) {
10281 mRegisteredReceivers.remove(rl.receiver.asBinder());
10282 int N = rl.size();
10283 for (int i=0; i<N; i++) {
10284 mReceiverResolver.removeFilter(rl.get(i));
10285 }
10286 }
10287
10288 private final int broadcastIntentLocked(ProcessRecord callerApp,
10289 String callerPackage, Intent intent, String resolvedType,
10290 IIntentReceiver resultTo, int resultCode, String resultData,
10291 Bundle map, String requiredPermission,
10292 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10293 intent = new Intent(intent);
10294
10295 if (DEBUG_BROADCAST) Log.v(
10296 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10297 + " ordered=" + ordered);
10298 if ((resultTo != null) && !ordered) {
10299 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10300 }
10301
10302 // Handle special intents: if this broadcast is from the package
10303 // manager about a package being removed, we need to remove all of
10304 // its activities from the history stack.
10305 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10306 intent.getAction());
10307 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10308 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10309 || uidRemoved) {
10310 if (checkComponentPermission(
10311 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10312 callingPid, callingUid, -1)
10313 == PackageManager.PERMISSION_GRANTED) {
10314 if (uidRemoved) {
10315 final Bundle intentExtras = intent.getExtras();
10316 final int uid = intentExtras != null
10317 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10318 if (uid >= 0) {
10319 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10320 synchronized (bs) {
10321 bs.removeUidStatsLocked(uid);
10322 }
10323 }
10324 } else {
10325 Uri data = intent.getData();
10326 String ssp;
10327 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10328 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10329 uninstallPackageLocked(ssp,
10330 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10331 }
10332 }
10333 }
10334 } else {
10335 String msg = "Permission Denial: " + intent.getAction()
10336 + " broadcast from " + callerPackage + " (pid=" + callingPid
10337 + ", uid=" + callingUid + ")"
10338 + " requires "
10339 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10340 Log.w(TAG, msg);
10341 throw new SecurityException(msg);
10342 }
10343 }
10344
10345 /*
10346 * If this is the time zone changed action, queue up a message that will reset the timezone
10347 * of all currently running processes. This message will get queued up before the broadcast
10348 * happens.
10349 */
10350 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10351 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10352 }
10353
10354 // Add to the sticky list if requested.
10355 if (sticky) {
10356 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10357 callingPid, callingUid)
10358 != PackageManager.PERMISSION_GRANTED) {
10359 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10360 + callingPid + ", uid=" + callingUid
10361 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10362 Log.w(TAG, msg);
10363 throw new SecurityException(msg);
10364 }
10365 if (requiredPermission != null) {
10366 Log.w(TAG, "Can't broadcast sticky intent " + intent
10367 + " and enforce permission " + requiredPermission);
10368 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10369 }
10370 if (intent.getComponent() != null) {
10371 throw new SecurityException(
10372 "Sticky broadcasts can't target a specific component");
10373 }
10374 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10375 if (list == null) {
10376 list = new ArrayList<Intent>();
10377 mStickyBroadcasts.put(intent.getAction(), list);
10378 }
10379 int N = list.size();
10380 int i;
10381 for (i=0; i<N; i++) {
10382 if (intent.filterEquals(list.get(i))) {
10383 // This sticky already exists, replace it.
10384 list.set(i, new Intent(intent));
10385 break;
10386 }
10387 }
10388 if (i >= N) {
10389 list.add(new Intent(intent));
10390 }
10391 }
10392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010393 // Figure out who all will receive this broadcast.
10394 List receivers = null;
10395 List<BroadcastFilter> registeredReceivers = null;
10396 try {
10397 if (intent.getComponent() != null) {
10398 // Broadcast is going to one specific receiver class...
10399 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010400 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010401 if (ai != null) {
10402 receivers = new ArrayList();
10403 ResolveInfo ri = new ResolveInfo();
10404 ri.activityInfo = ai;
10405 receivers.add(ri);
10406 }
10407 } else {
10408 // Need to resolve the intent to interested receivers...
10409 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10410 == 0) {
10411 receivers =
10412 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010413 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010414 }
Mihai Preda074edef2009-05-18 17:13:31 +020010415 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010416 }
10417 } catch (RemoteException ex) {
10418 // pm is in same process, this will never happen.
10419 }
10420
10421 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10422 if (!ordered && NR > 0) {
10423 // If we are not serializing this broadcast, then send the
10424 // registered receivers separately so they don't wait for the
10425 // components to be launched.
10426 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10427 callerPackage, callingPid, callingUid, requiredPermission,
10428 registeredReceivers, resultTo, resultCode, resultData, map,
10429 ordered);
10430 if (DEBUG_BROADCAST) Log.v(
10431 TAG, "Enqueueing parallel broadcast " + r
10432 + ": prev had " + mParallelBroadcasts.size());
10433 mParallelBroadcasts.add(r);
10434 scheduleBroadcastsLocked();
10435 registeredReceivers = null;
10436 NR = 0;
10437 }
10438
10439 // Merge into one list.
10440 int ir = 0;
10441 if (receivers != null) {
10442 // A special case for PACKAGE_ADDED: do not allow the package
10443 // being added to see this broadcast. This prevents them from
10444 // using this as a back door to get run as soon as they are
10445 // installed. Maybe in the future we want to have a special install
10446 // broadcast or such for apps, but we'd like to deliberately make
10447 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010448 boolean skip = false;
10449 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010450 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010451 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10452 skip = true;
10453 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10454 skip = true;
10455 }
10456 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010457 ? intent.getData().getSchemeSpecificPart()
10458 : null;
10459 if (skipPackage != null && receivers != null) {
10460 int NT = receivers.size();
10461 for (int it=0; it<NT; it++) {
10462 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10463 if (curt.activityInfo.packageName.equals(skipPackage)) {
10464 receivers.remove(it);
10465 it--;
10466 NT--;
10467 }
10468 }
10469 }
10470
10471 int NT = receivers != null ? receivers.size() : 0;
10472 int it = 0;
10473 ResolveInfo curt = null;
10474 BroadcastFilter curr = null;
10475 while (it < NT && ir < NR) {
10476 if (curt == null) {
10477 curt = (ResolveInfo)receivers.get(it);
10478 }
10479 if (curr == null) {
10480 curr = registeredReceivers.get(ir);
10481 }
10482 if (curr.getPriority() >= curt.priority) {
10483 // Insert this broadcast record into the final list.
10484 receivers.add(it, curr);
10485 ir++;
10486 curr = null;
10487 it++;
10488 NT++;
10489 } else {
10490 // Skip to the next ResolveInfo in the final list.
10491 it++;
10492 curt = null;
10493 }
10494 }
10495 }
10496 while (ir < NR) {
10497 if (receivers == null) {
10498 receivers = new ArrayList();
10499 }
10500 receivers.add(registeredReceivers.get(ir));
10501 ir++;
10502 }
10503
10504 if ((receivers != null && receivers.size() > 0)
10505 || resultTo != null) {
10506 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10507 callerPackage, callingPid, callingUid, requiredPermission,
10508 receivers, resultTo, resultCode, resultData, map, ordered);
10509 if (DEBUG_BROADCAST) Log.v(
10510 TAG, "Enqueueing ordered broadcast " + r
10511 + ": prev had " + mOrderedBroadcasts.size());
10512 if (DEBUG_BROADCAST) {
10513 int seq = r.intent.getIntExtra("seq", -1);
10514 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10515 }
10516 mOrderedBroadcasts.add(r);
10517 scheduleBroadcastsLocked();
10518 }
10519
10520 return BROADCAST_SUCCESS;
10521 }
10522
10523 public final int broadcastIntent(IApplicationThread caller,
10524 Intent intent, String resolvedType, IIntentReceiver resultTo,
10525 int resultCode, String resultData, Bundle map,
10526 String requiredPermission, boolean serialized, boolean sticky) {
10527 // Refuse possible leaked file descriptors
10528 if (intent != null && intent.hasFileDescriptors() == true) {
10529 throw new IllegalArgumentException("File descriptors passed in Intent");
10530 }
10531
10532 synchronized(this) {
10533 if (!mSystemReady) {
10534 // if the caller really truly claims to know what they're doing, go
10535 // ahead and allow the broadcast without launching any receivers
10536 int flags = intent.getFlags();
10537 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10538 intent = new Intent(intent);
10539 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10540 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10541 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10542 + " before boot completion");
10543 throw new IllegalStateException("Cannot broadcast before boot completed");
10544 }
10545 }
10546
10547 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10548 final int callingPid = Binder.getCallingPid();
10549 final int callingUid = Binder.getCallingUid();
10550 final long origId = Binder.clearCallingIdentity();
10551 int res = broadcastIntentLocked(callerApp,
10552 callerApp != null ? callerApp.info.packageName : null,
10553 intent, resolvedType, resultTo,
10554 resultCode, resultData, map, requiredPermission, serialized,
10555 sticky, callingPid, callingUid);
10556 Binder.restoreCallingIdentity(origId);
10557 return res;
10558 }
10559 }
10560
10561 int broadcastIntentInPackage(String packageName, int uid,
10562 Intent intent, String resolvedType, IIntentReceiver resultTo,
10563 int resultCode, String resultData, Bundle map,
10564 String requiredPermission, boolean serialized, boolean sticky) {
10565 synchronized(this) {
10566 final long origId = Binder.clearCallingIdentity();
10567 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10568 resultTo, resultCode, resultData, map, requiredPermission,
10569 serialized, sticky, -1, uid);
10570 Binder.restoreCallingIdentity(origId);
10571 return res;
10572 }
10573 }
10574
10575 public final void unbroadcastIntent(IApplicationThread caller,
10576 Intent intent) {
10577 // Refuse possible leaked file descriptors
10578 if (intent != null && intent.hasFileDescriptors() == true) {
10579 throw new IllegalArgumentException("File descriptors passed in Intent");
10580 }
10581
10582 synchronized(this) {
10583 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10584 != PackageManager.PERMISSION_GRANTED) {
10585 String msg = "Permission Denial: unbroadcastIntent() from pid="
10586 + Binder.getCallingPid()
10587 + ", uid=" + Binder.getCallingUid()
10588 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10589 Log.w(TAG, msg);
10590 throw new SecurityException(msg);
10591 }
10592 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10593 if (list != null) {
10594 int N = list.size();
10595 int i;
10596 for (i=0; i<N; i++) {
10597 if (intent.filterEquals(list.get(i))) {
10598 list.remove(i);
10599 break;
10600 }
10601 }
10602 }
10603 }
10604 }
10605
10606 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10607 String resultData, Bundle resultExtras, boolean resultAbort,
10608 boolean explicit) {
10609 if (mOrderedBroadcasts.size() == 0) {
10610 if (explicit) {
10611 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10612 }
10613 return false;
10614 }
10615 BroadcastRecord r = mOrderedBroadcasts.get(0);
10616 if (r.receiver == null) {
10617 if (explicit) {
10618 Log.w(TAG, "finishReceiver called but none active");
10619 }
10620 return false;
10621 }
10622 if (r.receiver != receiver) {
10623 Log.w(TAG, "finishReceiver called but active receiver is different");
10624 return false;
10625 }
10626 int state = r.state;
10627 r.state = r.IDLE;
10628 if (state == r.IDLE) {
10629 if (explicit) {
10630 Log.w(TAG, "finishReceiver called but state is IDLE");
10631 }
10632 }
10633 r.receiver = null;
10634 r.intent.setComponent(null);
10635 if (r.curApp != null) {
10636 r.curApp.curReceiver = null;
10637 }
10638 if (r.curFilter != null) {
10639 r.curFilter.receiverList.curBroadcast = null;
10640 }
10641 r.curFilter = null;
10642 r.curApp = null;
10643 r.curComponent = null;
10644 r.curReceiver = null;
10645 mPendingBroadcast = null;
10646
10647 r.resultCode = resultCode;
10648 r.resultData = resultData;
10649 r.resultExtras = resultExtras;
10650 r.resultAbort = resultAbort;
10651
10652 // We will process the next receiver right now if this is finishing
10653 // an app receiver (which is always asynchronous) or after we have
10654 // come back from calling a receiver.
10655 return state == BroadcastRecord.APP_RECEIVE
10656 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10657 }
10658
10659 public void finishReceiver(IBinder who, int resultCode, String resultData,
10660 Bundle resultExtras, boolean resultAbort) {
10661 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10662
10663 // Refuse possible leaked file descriptors
10664 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10665 throw new IllegalArgumentException("File descriptors passed in Bundle");
10666 }
10667
10668 boolean doNext;
10669
10670 final long origId = Binder.clearCallingIdentity();
10671
10672 synchronized(this) {
10673 doNext = finishReceiverLocked(
10674 who, resultCode, resultData, resultExtras, resultAbort, true);
10675 }
10676
10677 if (doNext) {
10678 processNextBroadcast(false);
10679 }
10680 trimApplications();
10681
10682 Binder.restoreCallingIdentity(origId);
10683 }
10684
10685 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10686 if (r.nextReceiver > 0) {
10687 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10688 if (curReceiver instanceof BroadcastFilter) {
10689 BroadcastFilter bf = (BroadcastFilter) curReceiver;
10690 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
10691 System.identityHashCode(r),
10692 r.intent.getAction(),
10693 r.nextReceiver - 1,
10694 System.identityHashCode(bf));
10695 } else {
10696 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10697 System.identityHashCode(r),
10698 r.intent.getAction(),
10699 r.nextReceiver - 1,
10700 ((ResolveInfo)curReceiver).toString());
10701 }
10702 } else {
10703 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
10704 + r);
10705 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10706 System.identityHashCode(r),
10707 r.intent.getAction(),
10708 r.nextReceiver,
10709 "NONE");
10710 }
10711 }
10712
10713 private final void broadcastTimeout() {
10714 synchronized (this) {
10715 if (mOrderedBroadcasts.size() == 0) {
10716 return;
10717 }
10718 long now = SystemClock.uptimeMillis();
10719 BroadcastRecord r = mOrderedBroadcasts.get(0);
10720 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
10721 if (DEBUG_BROADCAST) Log.v(TAG,
10722 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
10723 + (r.startTime + BROADCAST_TIMEOUT));
10724 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
10725 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
10726 return;
10727 }
10728
10729 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
10730 r.startTime = now;
10731 r.anrCount++;
10732
10733 // Current receiver has passed its expiration date.
10734 if (r.nextReceiver <= 0) {
10735 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
10736 return;
10737 }
10738
10739 ProcessRecord app = null;
10740
10741 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10742 Log.w(TAG, "Receiver during timeout: " + curReceiver);
10743 logBroadcastReceiverDiscard(r);
10744 if (curReceiver instanceof BroadcastFilter) {
10745 BroadcastFilter bf = (BroadcastFilter)curReceiver;
10746 if (bf.receiverList.pid != 0
10747 && bf.receiverList.pid != MY_PID) {
10748 synchronized (this.mPidsSelfLocked) {
10749 app = this.mPidsSelfLocked.get(
10750 bf.receiverList.pid);
10751 }
10752 }
10753 } else {
10754 app = r.curApp;
10755 }
10756
10757 if (app != null) {
10758 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
10759 }
10760
10761 if (mPendingBroadcast == r) {
10762 mPendingBroadcast = null;
10763 }
10764
10765 // Move on to the next receiver.
10766 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
10767 r.resultExtras, r.resultAbort, true);
10768 scheduleBroadcastsLocked();
10769 }
10770 }
10771
10772 private final void processCurBroadcastLocked(BroadcastRecord r,
10773 ProcessRecord app) throws RemoteException {
10774 if (app.thread == null) {
10775 throw new RemoteException();
10776 }
10777 r.receiver = app.thread.asBinder();
10778 r.curApp = app;
10779 app.curReceiver = r;
10780 updateLRUListLocked(app, true);
10781
10782 // Tell the application to launch this receiver.
10783 r.intent.setComponent(r.curComponent);
10784
10785 boolean started = false;
10786 try {
10787 if (DEBUG_BROADCAST) Log.v(TAG,
10788 "Delivering to component " + r.curComponent
10789 + ": " + r);
10790 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
10791 r.resultCode, r.resultData, r.resultExtras, r.ordered);
10792 started = true;
10793 } finally {
10794 if (!started) {
10795 r.receiver = null;
10796 r.curApp = null;
10797 app.curReceiver = null;
10798 }
10799 }
10800
10801 }
10802
10803 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
10804 Intent intent, int resultCode, String data,
10805 Bundle extras, boolean ordered) throws RemoteException {
10806 if (app != null && app.thread != null) {
10807 // If we have an app thread, do the call through that so it is
10808 // correctly ordered with other one-way calls.
10809 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
10810 data, extras, ordered);
10811 } else {
10812 receiver.performReceive(intent, resultCode, data, extras, ordered);
10813 }
10814 }
10815
10816 private final void deliverToRegisteredReceiver(BroadcastRecord r,
10817 BroadcastFilter filter, boolean ordered) {
10818 boolean skip = false;
10819 if (filter.requiredPermission != null) {
10820 int perm = checkComponentPermission(filter.requiredPermission,
10821 r.callingPid, r.callingUid, -1);
10822 if (perm != PackageManager.PERMISSION_GRANTED) {
10823 Log.w(TAG, "Permission Denial: broadcasting "
10824 + r.intent.toString()
10825 + " from " + r.callerPackage + " (pid="
10826 + r.callingPid + ", uid=" + r.callingUid + ")"
10827 + " requires " + filter.requiredPermission
10828 + " due to registered receiver " + filter);
10829 skip = true;
10830 }
10831 }
10832 if (r.requiredPermission != null) {
10833 int perm = checkComponentPermission(r.requiredPermission,
10834 filter.receiverList.pid, filter.receiverList.uid, -1);
10835 if (perm != PackageManager.PERMISSION_GRANTED) {
10836 Log.w(TAG, "Permission Denial: receiving "
10837 + r.intent.toString()
10838 + " to " + filter.receiverList.app
10839 + " (pid=" + filter.receiverList.pid
10840 + ", uid=" + filter.receiverList.uid + ")"
10841 + " requires " + r.requiredPermission
10842 + " due to sender " + r.callerPackage
10843 + " (uid " + r.callingUid + ")");
10844 skip = true;
10845 }
10846 }
10847
10848 if (!skip) {
10849 // If this is not being sent as an ordered broadcast, then we
10850 // don't want to touch the fields that keep track of the current
10851 // state of ordered broadcasts.
10852 if (ordered) {
10853 r.receiver = filter.receiverList.receiver.asBinder();
10854 r.curFilter = filter;
10855 filter.receiverList.curBroadcast = r;
10856 r.state = BroadcastRecord.CALL_IN_RECEIVE;
10857 }
10858 try {
10859 if (DEBUG_BROADCAST) {
10860 int seq = r.intent.getIntExtra("seq", -1);
10861 Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
10862 + " app=" + filter.receiverList.app);
10863 }
10864 performReceive(filter.receiverList.app, filter.receiverList.receiver,
10865 new Intent(r.intent), r.resultCode,
10866 r.resultData, r.resultExtras, r.ordered);
10867 if (ordered) {
10868 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
10869 }
10870 } catch (RemoteException e) {
10871 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
10872 if (ordered) {
10873 r.receiver = null;
10874 r.curFilter = null;
10875 filter.receiverList.curBroadcast = null;
10876 }
10877 }
10878 }
10879 }
10880
10881 private final void processNextBroadcast(boolean fromMsg) {
10882 synchronized(this) {
10883 BroadcastRecord r;
10884
10885 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
10886 + mParallelBroadcasts.size() + " broadcasts, "
10887 + mOrderedBroadcasts.size() + " serialized broadcasts");
10888
10889 updateCpuStats();
10890
10891 if (fromMsg) {
10892 mBroadcastsScheduled = false;
10893 }
10894
10895 // First, deliver any non-serialized broadcasts right away.
10896 while (mParallelBroadcasts.size() > 0) {
10897 r = mParallelBroadcasts.remove(0);
10898 final int N = r.receivers.size();
10899 for (int i=0; i<N; i++) {
10900 Object target = r.receivers.get(i);
10901 if (DEBUG_BROADCAST) Log.v(TAG,
10902 "Delivering non-serialized to registered "
10903 + target + ": " + r);
10904 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
10905 }
10906 }
10907
10908 // Now take care of the next serialized one...
10909
10910 // If we are waiting for a process to come up to handle the next
10911 // broadcast, then do nothing at this point. Just in case, we
10912 // check that the process we're waiting for still exists.
10913 if (mPendingBroadcast != null) {
10914 Log.i(TAG, "processNextBroadcast: waiting for "
10915 + mPendingBroadcast.curApp);
10916
10917 boolean isDead;
10918 synchronized (mPidsSelfLocked) {
10919 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
10920 }
10921 if (!isDead) {
10922 // It's still alive, so keep waiting
10923 return;
10924 } else {
10925 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
10926 + " died before responding to broadcast");
10927 mPendingBroadcast = null;
10928 }
10929 }
10930
10931 do {
10932 if (mOrderedBroadcasts.size() == 0) {
10933 // No more broadcasts pending, so all done!
10934 scheduleAppGcsLocked();
10935 return;
10936 }
10937 r = mOrderedBroadcasts.get(0);
10938 boolean forceReceive = false;
10939
10940 // Ensure that even if something goes awry with the timeout
10941 // detection, we catch "hung" broadcasts here, discard them,
10942 // and continue to make progress.
10943 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
10944 long now = SystemClock.uptimeMillis();
10945 if (r.dispatchTime > 0) {
10946 if ((numReceivers > 0) &&
10947 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
10948 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
10949 + " now=" + now
10950 + " dispatchTime=" + r.dispatchTime
10951 + " startTime=" + r.startTime
10952 + " intent=" + r.intent
10953 + " numReceivers=" + numReceivers
10954 + " nextReceiver=" + r.nextReceiver
10955 + " state=" + r.state);
10956 broadcastTimeout(); // forcibly finish this broadcast
10957 forceReceive = true;
10958 r.state = BroadcastRecord.IDLE;
10959 }
10960 }
10961
10962 if (r.state != BroadcastRecord.IDLE) {
10963 if (DEBUG_BROADCAST) Log.d(TAG,
10964 "processNextBroadcast() called when not idle (state="
10965 + r.state + ")");
10966 return;
10967 }
10968
10969 if (r.receivers == null || r.nextReceiver >= numReceivers
10970 || r.resultAbort || forceReceive) {
10971 // No more receivers for this broadcast! Send the final
10972 // result if requested...
10973 if (r.resultTo != null) {
10974 try {
10975 if (DEBUG_BROADCAST) {
10976 int seq = r.intent.getIntExtra("seq", -1);
10977 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
10978 + " seq=" + seq + " app=" + r.callerApp);
10979 }
10980 performReceive(r.callerApp, r.resultTo,
10981 new Intent(r.intent), r.resultCode,
10982 r.resultData, r.resultExtras, false);
10983 } catch (RemoteException e) {
10984 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
10985 }
10986 }
10987
10988 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
10989 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
10990
10991 // ... and on to the next...
10992 mOrderedBroadcasts.remove(0);
10993 r = null;
10994 continue;
10995 }
10996 } while (r == null);
10997
10998 // Get the next receiver...
10999 int recIdx = r.nextReceiver++;
11000
11001 // Keep track of when this receiver started, and make sure there
11002 // is a timeout message pending to kill it if need be.
11003 r.startTime = SystemClock.uptimeMillis();
11004 if (recIdx == 0) {
11005 r.dispatchTime = r.startTime;
11006
11007 if (DEBUG_BROADCAST) Log.v(TAG,
11008 "Submitting BROADCAST_TIMEOUT_MSG for "
11009 + (r.startTime + BROADCAST_TIMEOUT));
11010 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11011 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11012 }
11013
11014 Object nextReceiver = r.receivers.get(recIdx);
11015 if (nextReceiver instanceof BroadcastFilter) {
11016 // Simple case: this is a registered receiver who gets
11017 // a direct call.
11018 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11019 if (DEBUG_BROADCAST) Log.v(TAG,
11020 "Delivering serialized to registered "
11021 + filter + ": " + r);
11022 deliverToRegisteredReceiver(r, filter, r.ordered);
11023 if (r.receiver == null || !r.ordered) {
11024 // The receiver has already finished, so schedule to
11025 // process the next one.
11026 r.state = BroadcastRecord.IDLE;
11027 scheduleBroadcastsLocked();
11028 }
11029 return;
11030 }
11031
11032 // Hard case: need to instantiate the receiver, possibly
11033 // starting its application process to host it.
11034
11035 ResolveInfo info =
11036 (ResolveInfo)nextReceiver;
11037
11038 boolean skip = false;
11039 int perm = checkComponentPermission(info.activityInfo.permission,
11040 r.callingPid, r.callingUid,
11041 info.activityInfo.exported
11042 ? -1 : info.activityInfo.applicationInfo.uid);
11043 if (perm != PackageManager.PERMISSION_GRANTED) {
11044 Log.w(TAG, "Permission Denial: broadcasting "
11045 + r.intent.toString()
11046 + " from " + r.callerPackage + " (pid=" + r.callingPid
11047 + ", uid=" + r.callingUid + ")"
11048 + " requires " + info.activityInfo.permission
11049 + " due to receiver " + info.activityInfo.packageName
11050 + "/" + info.activityInfo.name);
11051 skip = true;
11052 }
11053 if (r.callingUid != Process.SYSTEM_UID &&
11054 r.requiredPermission != null) {
11055 try {
11056 perm = ActivityThread.getPackageManager().
11057 checkPermission(r.requiredPermission,
11058 info.activityInfo.applicationInfo.packageName);
11059 } catch (RemoteException e) {
11060 perm = PackageManager.PERMISSION_DENIED;
11061 }
11062 if (perm != PackageManager.PERMISSION_GRANTED) {
11063 Log.w(TAG, "Permission Denial: receiving "
11064 + r.intent + " to "
11065 + info.activityInfo.applicationInfo.packageName
11066 + " requires " + r.requiredPermission
11067 + " due to sender " + r.callerPackage
11068 + " (uid " + r.callingUid + ")");
11069 skip = true;
11070 }
11071 }
11072 if (r.curApp != null && r.curApp.crashing) {
11073 // If the target process is crashing, just skip it.
11074 skip = true;
11075 }
11076
11077 if (skip) {
11078 r.receiver = null;
11079 r.curFilter = null;
11080 r.state = BroadcastRecord.IDLE;
11081 scheduleBroadcastsLocked();
11082 return;
11083 }
11084
11085 r.state = BroadcastRecord.APP_RECEIVE;
11086 String targetProcess = info.activityInfo.processName;
11087 r.curComponent = new ComponentName(
11088 info.activityInfo.applicationInfo.packageName,
11089 info.activityInfo.name);
11090 r.curReceiver = info.activityInfo;
11091
11092 // Is this receiver's application already running?
11093 ProcessRecord app = getProcessRecordLocked(targetProcess,
11094 info.activityInfo.applicationInfo.uid);
11095 if (app != null && app.thread != null) {
11096 try {
11097 processCurBroadcastLocked(r, app);
11098 return;
11099 } catch (RemoteException e) {
11100 Log.w(TAG, "Exception when sending broadcast to "
11101 + r.curComponent, e);
11102 }
11103
11104 // If a dead object exception was thrown -- fall through to
11105 // restart the application.
11106 }
11107
11108 // Not running -- get it started, and enqueue this history record
11109 // to be executed when the app comes up.
11110 if ((r.curApp=startProcessLocked(targetProcess,
11111 info.activityInfo.applicationInfo, true,
11112 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11113 "broadcast", r.curComponent)) == null) {
11114 // Ah, this recipient is unavailable. Finish it if necessary,
11115 // and mark the broadcast record as ready for the next.
11116 Log.w(TAG, "Unable to launch app "
11117 + info.activityInfo.applicationInfo.packageName + "/"
11118 + info.activityInfo.applicationInfo.uid + " for broadcast "
11119 + r.intent + ": process is bad");
11120 logBroadcastReceiverDiscard(r);
11121 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11122 r.resultExtras, r.resultAbort, true);
11123 scheduleBroadcastsLocked();
11124 r.state = BroadcastRecord.IDLE;
11125 return;
11126 }
11127
11128 mPendingBroadcast = r;
11129 }
11130 }
11131
11132 // =========================================================
11133 // INSTRUMENTATION
11134 // =========================================================
11135
11136 public boolean startInstrumentation(ComponentName className,
11137 String profileFile, int flags, Bundle arguments,
11138 IInstrumentationWatcher watcher) {
11139 // Refuse possible leaked file descriptors
11140 if (arguments != null && arguments.hasFileDescriptors()) {
11141 throw new IllegalArgumentException("File descriptors passed in Bundle");
11142 }
11143
11144 synchronized(this) {
11145 InstrumentationInfo ii = null;
11146 ApplicationInfo ai = null;
11147 try {
11148 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011149 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011150 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011151 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011152 } catch (PackageManager.NameNotFoundException e) {
11153 }
11154 if (ii == null) {
11155 reportStartInstrumentationFailure(watcher, className,
11156 "Unable to find instrumentation info for: " + className);
11157 return false;
11158 }
11159 if (ai == null) {
11160 reportStartInstrumentationFailure(watcher, className,
11161 "Unable to find instrumentation target package: " + ii.targetPackage);
11162 return false;
11163 }
11164
11165 int match = mContext.getPackageManager().checkSignatures(
11166 ii.targetPackage, ii.packageName);
11167 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11168 String msg = "Permission Denial: starting instrumentation "
11169 + className + " from pid="
11170 + Binder.getCallingPid()
11171 + ", uid=" + Binder.getCallingPid()
11172 + " not allowed because package " + ii.packageName
11173 + " does not have a signature matching the target "
11174 + ii.targetPackage;
11175 reportStartInstrumentationFailure(watcher, className, msg);
11176 throw new SecurityException(msg);
11177 }
11178
11179 final long origId = Binder.clearCallingIdentity();
11180 uninstallPackageLocked(ii.targetPackage, -1, true);
11181 ProcessRecord app = addAppLocked(ai);
11182 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011183 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011184 app.instrumentationProfileFile = profileFile;
11185 app.instrumentationArguments = arguments;
11186 app.instrumentationWatcher = watcher;
11187 app.instrumentationResultClass = className;
11188 Binder.restoreCallingIdentity(origId);
11189 }
11190
11191 return true;
11192 }
11193
11194 /**
11195 * Report errors that occur while attempting to start Instrumentation. Always writes the
11196 * error to the logs, but if somebody is watching, send the report there too. This enables
11197 * the "am" command to report errors with more information.
11198 *
11199 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11200 * @param cn The component name of the instrumentation.
11201 * @param report The error report.
11202 */
11203 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11204 ComponentName cn, String report) {
11205 Log.w(TAG, report);
11206 try {
11207 if (watcher != null) {
11208 Bundle results = new Bundle();
11209 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11210 results.putString("Error", report);
11211 watcher.instrumentationStatus(cn, -1, results);
11212 }
11213 } catch (RemoteException e) {
11214 Log.w(TAG, e);
11215 }
11216 }
11217
11218 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11219 if (app.instrumentationWatcher != null) {
11220 try {
11221 // NOTE: IInstrumentationWatcher *must* be oneway here
11222 app.instrumentationWatcher.instrumentationFinished(
11223 app.instrumentationClass,
11224 resultCode,
11225 results);
11226 } catch (RemoteException e) {
11227 }
11228 }
11229 app.instrumentationWatcher = null;
11230 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011231 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011232 app.instrumentationProfileFile = null;
11233 app.instrumentationArguments = null;
11234
11235 uninstallPackageLocked(app.processName, -1, false);
11236 }
11237
11238 public void finishInstrumentation(IApplicationThread target,
11239 int resultCode, Bundle results) {
11240 // Refuse possible leaked file descriptors
11241 if (results != null && results.hasFileDescriptors()) {
11242 throw new IllegalArgumentException("File descriptors passed in Intent");
11243 }
11244
11245 synchronized(this) {
11246 ProcessRecord app = getRecordForAppLocked(target);
11247 if (app == null) {
11248 Log.w(TAG, "finishInstrumentation: no app for " + target);
11249 return;
11250 }
11251 final long origId = Binder.clearCallingIdentity();
11252 finishInstrumentationLocked(app, resultCode, results);
11253 Binder.restoreCallingIdentity(origId);
11254 }
11255 }
11256
11257 // =========================================================
11258 // CONFIGURATION
11259 // =========================================================
11260
11261 public ConfigurationInfo getDeviceConfigurationInfo() {
11262 ConfigurationInfo config = new ConfigurationInfo();
11263 synchronized (this) {
11264 config.reqTouchScreen = mConfiguration.touchscreen;
11265 config.reqKeyboardType = mConfiguration.keyboard;
11266 config.reqNavigation = mConfiguration.navigation;
11267 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11268 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11269 }
11270 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11271 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11272 }
11273 }
11274 return config;
11275 }
11276
11277 public Configuration getConfiguration() {
11278 Configuration ci;
11279 synchronized(this) {
11280 ci = new Configuration(mConfiguration);
11281 }
11282 return ci;
11283 }
11284
11285 public void updateConfiguration(Configuration values) {
11286 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11287 "updateConfiguration()");
11288
11289 synchronized(this) {
11290 if (values == null && mWindowManager != null) {
11291 // sentinel: fetch the current configuration from the window manager
11292 values = mWindowManager.computeNewConfiguration();
11293 }
11294
11295 final long origId = Binder.clearCallingIdentity();
11296 updateConfigurationLocked(values, null);
11297 Binder.restoreCallingIdentity(origId);
11298 }
11299 }
11300
11301 /**
11302 * Do either or both things: (1) change the current configuration, and (2)
11303 * make sure the given activity is running with the (now) current
11304 * configuration. Returns true if the activity has been left running, or
11305 * false if <var>starting</var> is being destroyed to match the new
11306 * configuration.
11307 */
11308 public boolean updateConfigurationLocked(Configuration values,
11309 HistoryRecord starting) {
11310 int changes = 0;
11311
11312 boolean kept = true;
11313
11314 if (values != null) {
11315 Configuration newConfig = new Configuration(mConfiguration);
11316 changes = newConfig.updateFrom(values);
11317 if (changes != 0) {
11318 if (DEBUG_SWITCH) {
11319 Log.i(TAG, "Updating configuration to: " + values);
11320 }
11321
11322 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11323
11324 if (values.locale != null) {
11325 saveLocaleLocked(values.locale,
11326 !values.locale.equals(mConfiguration.locale),
11327 values.userSetLocale);
11328 }
11329
11330 mConfiguration = newConfig;
11331
11332 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11333 msg.obj = new Configuration(mConfiguration);
11334 mHandler.sendMessage(msg);
11335
11336 final int N = mLRUProcesses.size();
11337 for (int i=0; i<N; i++) {
11338 ProcessRecord app = mLRUProcesses.get(i);
11339 try {
11340 if (app.thread != null) {
11341 app.thread.scheduleConfigurationChanged(mConfiguration);
11342 }
11343 } catch (Exception e) {
11344 }
11345 }
11346 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11347 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11348 null, false, false, MY_PID, Process.SYSTEM_UID);
11349 }
11350 }
11351
11352 if (changes != 0 && starting == null) {
11353 // If the configuration changed, and the caller is not already
11354 // in the process of starting an activity, then find the top
11355 // activity to check if its configuration needs to change.
11356 starting = topRunningActivityLocked(null);
11357 }
11358
11359 if (starting != null) {
11360 kept = ensureActivityConfigurationLocked(starting, changes);
11361 if (kept) {
11362 // If this didn't result in the starting activity being
11363 // destroyed, then we need to make sure at this point that all
11364 // other activities are made visible.
11365 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11366 + ", ensuring others are correct.");
11367 ensureActivitiesVisibleLocked(starting, changes);
11368 }
11369 }
11370
11371 return kept;
11372 }
11373
11374 private final boolean relaunchActivityLocked(HistoryRecord r,
11375 int changes, boolean andResume) {
11376 List<ResultInfo> results = null;
11377 List<Intent> newIntents = null;
11378 if (andResume) {
11379 results = r.results;
11380 newIntents = r.newIntents;
11381 }
11382 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11383 + " with results=" + results + " newIntents=" + newIntents
11384 + " andResume=" + andResume);
11385 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11386 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11387 r.task.taskId, r.shortComponentName);
11388
11389 r.startFreezingScreenLocked(r.app, 0);
11390
11391 try {
11392 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11393 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11394 changes, !andResume);
11395 // Note: don't need to call pauseIfSleepingLocked() here, because
11396 // the caller will only pass in 'andResume' if this activity is
11397 // currently resumed, which implies we aren't sleeping.
11398 } catch (RemoteException e) {
11399 return false;
11400 }
11401
11402 if (andResume) {
11403 r.results = null;
11404 r.newIntents = null;
11405 }
11406
11407 return true;
11408 }
11409
11410 /**
11411 * Make sure the given activity matches the current configuration. Returns
11412 * false if the activity had to be destroyed. Returns true if the
11413 * configuration is the same, or the activity will remain running as-is
11414 * for whatever reason. Ensures the HistoryRecord is updated with the
11415 * correct configuration and all other bookkeeping is handled.
11416 */
11417 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11418 int globalChanges) {
11419 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11420
11421 // Short circuit: if the two configurations are the exact same
11422 // object (the common case), then there is nothing to do.
11423 Configuration newConfig = mConfiguration;
11424 if (r.configuration == newConfig) {
11425 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11426 return true;
11427 }
11428
11429 // We don't worry about activities that are finishing.
11430 if (r.finishing) {
11431 if (DEBUG_SWITCH) Log.i(TAG,
11432 "Configuration doesn't matter in finishing " + r);
11433 r.stopFreezingScreenLocked(false);
11434 return true;
11435 }
11436
11437 // Okay we now are going to make this activity have the new config.
11438 // But then we need to figure out how it needs to deal with that.
11439 Configuration oldConfig = r.configuration;
11440 r.configuration = newConfig;
11441
11442 // If the activity isn't currently running, just leave the new
11443 // configuration and it will pick that up next time it starts.
11444 if (r.app == null || r.app.thread == null) {
11445 if (DEBUG_SWITCH) Log.i(TAG,
11446 "Configuration doesn't matter not running " + r);
11447 r.stopFreezingScreenLocked(false);
11448 return true;
11449 }
11450
11451 // If the activity isn't persistent, there is a chance we will
11452 // need to restart it.
11453 if (!r.persistent) {
11454
11455 // Figure out what has changed between the two configurations.
11456 int changes = oldConfig.diff(newConfig);
11457 if (DEBUG_SWITCH) {
11458 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11459 + Integer.toHexString(changes) + ", handles=0x"
11460 + Integer.toHexString(r.info.configChanges));
11461 }
11462 if ((changes&(~r.info.configChanges)) != 0) {
11463 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11464 r.configChangeFlags |= changes;
11465 r.startFreezingScreenLocked(r.app, globalChanges);
11466 if (r.app == null || r.app.thread == null) {
11467 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11468 destroyActivityLocked(r, true);
11469 } else if (r.state == ActivityState.PAUSING) {
11470 // A little annoying: we are waiting for this activity to
11471 // finish pausing. Let's not do anything now, but just
11472 // flag that it needs to be restarted when done pausing.
11473 r.configDestroy = true;
11474 return true;
11475 } else if (r.state == ActivityState.RESUMED) {
11476 // Try to optimize this case: the configuration is changing
11477 // and we need to restart the top, resumed activity.
11478 // Instead of doing the normal handshaking, just say
11479 // "restart!".
11480 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11481 relaunchActivityLocked(r, r.configChangeFlags, true);
11482 r.configChangeFlags = 0;
11483 } else {
11484 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11485 relaunchActivityLocked(r, r.configChangeFlags, false);
11486 r.configChangeFlags = 0;
11487 }
11488
11489 // All done... tell the caller we weren't able to keep this
11490 // activity around.
11491 return false;
11492 }
11493 }
11494
11495 // Default case: the activity can handle this new configuration, so
11496 // hand it over. Note that we don't need to give it the new
11497 // configuration, since we always send configuration changes to all
11498 // process when they happen so it can just use whatever configuration
11499 // it last got.
11500 if (r.app != null && r.app.thread != null) {
11501 try {
11502 r.app.thread.scheduleActivityConfigurationChanged(r);
11503 } catch (RemoteException e) {
11504 // If process died, whatever.
11505 }
11506 }
11507 r.stopFreezingScreenLocked(false);
11508
11509 return true;
11510 }
11511
11512 /**
11513 * Save the locale. You must be inside a synchronized (this) block.
11514 */
11515 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11516 if(isDiff) {
11517 SystemProperties.set("user.language", l.getLanguage());
11518 SystemProperties.set("user.region", l.getCountry());
11519 }
11520
11521 if(isPersist) {
11522 SystemProperties.set("persist.sys.language", l.getLanguage());
11523 SystemProperties.set("persist.sys.country", l.getCountry());
11524 SystemProperties.set("persist.sys.localevar", l.getVariant());
11525 }
11526 }
11527
11528 // =========================================================
11529 // LIFETIME MANAGEMENT
11530 // =========================================================
11531
11532 private final int computeOomAdjLocked(
11533 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11534 if (mAdjSeq == app.adjSeq) {
11535 // This adjustment has already been computed.
11536 return app.curAdj;
11537 }
11538
11539 if (app.thread == null) {
11540 app.adjSeq = mAdjSeq;
11541 return (app.curAdj=EMPTY_APP_ADJ);
11542 }
11543
11544 app.isForeground = false;
11545
The Android Open Source Project4df24232009-03-05 14:34:35 -080011546 // Determine the importance of the process, starting with most
11547 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011548 int adj;
11549 int N;
11550 if (app == TOP_APP || app.instrumentationClass != null
11551 || app.persistentActivities > 0) {
11552 // The last app on the list is the foreground app.
11553 adj = FOREGROUND_APP_ADJ;
11554 app.isForeground = true;
11555 } else if (app.curReceiver != null ||
11556 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11557 // An app that is currently receiving a broadcast also
11558 // counts as being in the foreground.
11559 adj = FOREGROUND_APP_ADJ;
11560 } else if (app.executingServices.size() > 0) {
11561 // An app that is currently executing a service callback also
11562 // counts as being in the foreground.
11563 adj = FOREGROUND_APP_ADJ;
11564 } else if (app.foregroundServices || app.forcingToForeground != null) {
11565 // The user is aware of this app, so make it visible.
11566 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011567 } else if (app == mHomeProcess) {
11568 // This process is hosting what we currently consider to be the
11569 // home app, so we don't want to let it go into the background.
11570 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011571 } else if ((N=app.activities.size()) != 0) {
11572 // This app is in the background with paused activities.
11573 adj = hiddenAdj;
11574 for (int j=0; j<N; j++) {
11575 if (((HistoryRecord)app.activities.get(j)).visible) {
11576 // This app has a visible activity!
11577 adj = VISIBLE_APP_ADJ;
11578 break;
11579 }
11580 }
11581 } else {
11582 // A very not-needed process.
11583 adj = EMPTY_APP_ADJ;
11584 }
11585
The Android Open Source Project4df24232009-03-05 14:34:35 -080011586 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011587 // there are applications dependent on our services or providers, but
11588 // this gives us a baseline and makes sure we don't get into an
11589 // infinite recursion.
11590 app.adjSeq = mAdjSeq;
11591 app.curRawAdj = adj;
11592 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11593
11594 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11595 // If this process has active services running in it, we would
11596 // like to avoid killing it unless it would prevent the current
11597 // application from running.
11598 if (adj > hiddenAdj) {
11599 adj = hiddenAdj;
11600 }
11601 final long now = SystemClock.uptimeMillis();
11602 // This process is more important if the top activity is
11603 // bound to the service.
11604 Iterator jt = app.services.iterator();
11605 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11606 ServiceRecord s = (ServiceRecord)jt.next();
11607 if (s.startRequested) {
11608 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11609 // This service has seen some activity within
11610 // recent memory, so we will keep its process ahead
11611 // of the background processes.
11612 if (adj > SECONDARY_SERVER_ADJ) {
11613 adj = SECONDARY_SERVER_ADJ;
11614 }
11615 } else {
11616 // This service has been inactive for too long, just
11617 // put it with the rest of the background processes.
11618 if (adj > hiddenAdj) {
11619 adj = hiddenAdj;
11620 }
11621 }
11622 }
11623 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11624 Iterator<ConnectionRecord> kt
11625 = s.connections.values().iterator();
11626 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11627 // XXX should compute this based on the max of
11628 // all connected clients.
11629 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011630 if (cr.binding.client == app) {
11631 // Binding to ourself is not interesting.
11632 continue;
11633 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011634 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11635 ProcessRecord client = cr.binding.client;
11636 int myHiddenAdj = hiddenAdj;
11637 if (myHiddenAdj > client.hiddenAdj) {
11638 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11639 myHiddenAdj = client.hiddenAdj;
11640 } else {
11641 myHiddenAdj = VISIBLE_APP_ADJ;
11642 }
11643 }
11644 int clientAdj = computeOomAdjLocked(
11645 client, myHiddenAdj, TOP_APP);
11646 if (adj > clientAdj) {
11647 adj = clientAdj > VISIBLE_APP_ADJ
11648 ? clientAdj : VISIBLE_APP_ADJ;
11649 }
11650 }
11651 HistoryRecord a = cr.activity;
11652 //if (a != null) {
11653 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11654 //}
11655 if (a != null && adj > FOREGROUND_APP_ADJ &&
11656 (a.state == ActivityState.RESUMED
11657 || a.state == ActivityState.PAUSING)) {
11658 adj = FOREGROUND_APP_ADJ;
11659 }
11660 }
11661 }
11662 }
11663 }
11664
11665 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11666 // If this process has published any content providers, then
11667 // its adjustment makes it at least as important as any of the
11668 // processes using those providers, and no less important than
11669 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
11670 if (adj > CONTENT_PROVIDER_ADJ) {
11671 adj = CONTENT_PROVIDER_ADJ;
11672 }
11673 Iterator jt = app.pubProviders.values().iterator();
11674 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11675 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
11676 if (cpr.clients.size() != 0) {
11677 Iterator<ProcessRecord> kt = cpr.clients.iterator();
11678 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11679 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011680 if (client == app) {
11681 // Being our own client is not interesting.
11682 continue;
11683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011684 int myHiddenAdj = hiddenAdj;
11685 if (myHiddenAdj > client.hiddenAdj) {
11686 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
11687 myHiddenAdj = client.hiddenAdj;
11688 } else {
11689 myHiddenAdj = FOREGROUND_APP_ADJ;
11690 }
11691 }
11692 int clientAdj = computeOomAdjLocked(
11693 client, myHiddenAdj, TOP_APP);
11694 if (adj > clientAdj) {
11695 adj = clientAdj > FOREGROUND_APP_ADJ
11696 ? clientAdj : FOREGROUND_APP_ADJ;
11697 }
11698 }
11699 }
11700 // If the provider has external (non-framework) process
11701 // dependencies, ensure that its adjustment is at least
11702 // FOREGROUND_APP_ADJ.
11703 if (cpr.externals != 0) {
11704 if (adj > FOREGROUND_APP_ADJ) {
11705 adj = FOREGROUND_APP_ADJ;
11706 }
11707 }
11708 }
11709 }
11710
11711 app.curRawAdj = adj;
11712
11713 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
11714 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
11715 if (adj > app.maxAdj) {
11716 adj = app.maxAdj;
11717 }
11718
11719 app.curAdj = adj;
11720
11721 return adj;
11722 }
11723
11724 /**
11725 * Ask a given process to GC right now.
11726 */
11727 final void performAppGcLocked(ProcessRecord app) {
11728 try {
11729 app.lastRequestedGc = SystemClock.uptimeMillis();
11730 if (app.thread != null) {
11731 app.thread.processInBackground();
11732 }
11733 } catch (Exception e) {
11734 // whatever.
11735 }
11736 }
11737
11738 /**
11739 * Returns true if things are idle enough to perform GCs.
11740 */
11741 private final boolean canGcNow() {
11742 return mParallelBroadcasts.size() == 0
11743 && mOrderedBroadcasts.size() == 0
11744 && (mSleeping || (mResumedActivity != null &&
11745 mResumedActivity.idle));
11746 }
11747
11748 /**
11749 * Perform GCs on all processes that are waiting for it, but only
11750 * if things are idle.
11751 */
11752 final void performAppGcsLocked() {
11753 final int N = mProcessesToGc.size();
11754 if (N <= 0) {
11755 return;
11756 }
11757 if (canGcNow()) {
11758 while (mProcessesToGc.size() > 0) {
11759 ProcessRecord proc = mProcessesToGc.remove(0);
11760 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
11761 // To avoid spamming the system, we will GC processes one
11762 // at a time, waiting a few seconds between each.
11763 performAppGcLocked(proc);
11764 scheduleAppGcsLocked();
11765 return;
11766 }
11767 }
11768 }
11769 }
11770
11771 /**
11772 * If all looks good, perform GCs on all processes waiting for them.
11773 */
11774 final void performAppGcsIfAppropriateLocked() {
11775 if (canGcNow()) {
11776 performAppGcsLocked();
11777 return;
11778 }
11779 // Still not idle, wait some more.
11780 scheduleAppGcsLocked();
11781 }
11782
11783 /**
11784 * Schedule the execution of all pending app GCs.
11785 */
11786 final void scheduleAppGcsLocked() {
11787 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
11788 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
11789 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
11790 }
11791
11792 /**
11793 * Set up to ask a process to GC itself. This will either do it
11794 * immediately, or put it on the list of processes to gc the next
11795 * time things are idle.
11796 */
11797 final void scheduleAppGcLocked(ProcessRecord app) {
11798 long now = SystemClock.uptimeMillis();
11799 if ((app.lastRequestedGc+5000) > now) {
11800 return;
11801 }
11802 if (!mProcessesToGc.contains(app)) {
11803 mProcessesToGc.add(app);
11804 scheduleAppGcsLocked();
11805 }
11806 }
11807
11808 private final boolean updateOomAdjLocked(
11809 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11810 app.hiddenAdj = hiddenAdj;
11811
11812 if (app.thread == null) {
11813 return true;
11814 }
11815
11816 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
11817
11818 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
11819 //Thread priority adjustment is disabled out to see
11820 //how the kernel scheduler performs.
11821 if (false) {
11822 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
11823 app.setIsForeground = app.isForeground;
11824 if (app.pid != MY_PID) {
11825 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
11826 + " to " + (app.isForeground
11827 ? Process.THREAD_PRIORITY_FOREGROUND
11828 : Process.THREAD_PRIORITY_DEFAULT));
11829 try {
11830 Process.setThreadPriority(app.pid, app.isForeground
11831 ? Process.THREAD_PRIORITY_FOREGROUND
11832 : Process.THREAD_PRIORITY_DEFAULT);
11833 } catch (RuntimeException e) {
11834 Log.w(TAG, "Exception trying to set priority of application thread "
11835 + app.pid, e);
11836 }
11837 }
11838 }
11839 }
11840 if (app.pid != 0 && app.pid != MY_PID) {
11841 if (app.curRawAdj != app.setRawAdj) {
11842 if (app.curRawAdj > FOREGROUND_APP_ADJ
11843 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
11844 // If this app is transitioning from foreground to
11845 // non-foreground, have it do a gc.
11846 scheduleAppGcLocked(app);
11847 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
11848 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
11849 // Likewise do a gc when an app is moving in to the
11850 // background (such as a service stopping).
11851 scheduleAppGcLocked(app);
11852 }
11853 app.setRawAdj = app.curRawAdj;
11854 }
11855 if (adj != app.setAdj) {
11856 if (Process.setOomAdj(app.pid, adj)) {
11857 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
11858 TAG, "Set app " + app.processName +
11859 " oom adj to " + adj);
11860 app.setAdj = adj;
11861 } else {
11862 return false;
11863 }
11864 }
11865 }
11866
11867 return true;
11868 }
11869
11870 private final HistoryRecord resumedAppLocked() {
11871 HistoryRecord resumedActivity = mResumedActivity;
11872 if (resumedActivity == null || resumedActivity.app == null) {
11873 resumedActivity = mPausingActivity;
11874 if (resumedActivity == null || resumedActivity.app == null) {
11875 resumedActivity = topRunningActivityLocked(null);
11876 }
11877 }
11878 return resumedActivity;
11879 }
11880
11881 private final boolean updateOomAdjLocked(ProcessRecord app) {
11882 final HistoryRecord TOP_ACT = resumedAppLocked();
11883 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
11884 int curAdj = app.curAdj;
11885 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
11886 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
11887
11888 mAdjSeq++;
11889
11890 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
11891 if (res) {
11892 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
11893 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
11894 if (nowHidden != wasHidden) {
11895 // Changed to/from hidden state, so apps after it in the LRU
11896 // list may also be changed.
11897 updateOomAdjLocked();
11898 }
11899 }
11900 return res;
11901 }
11902
11903 private final boolean updateOomAdjLocked() {
11904 boolean didOomAdj = true;
11905 final HistoryRecord TOP_ACT = resumedAppLocked();
11906 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
11907
11908 if (false) {
11909 RuntimeException e = new RuntimeException();
11910 e.fillInStackTrace();
11911 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
11912 }
11913
11914 mAdjSeq++;
11915
11916 // First try updating the OOM adjustment for each of the
11917 // application processes based on their current state.
11918 int i = mLRUProcesses.size();
11919 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
11920 while (i > 0) {
11921 i--;
11922 ProcessRecord app = mLRUProcesses.get(i);
11923 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
11924 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
11925 && app.curAdj == curHiddenAdj) {
11926 curHiddenAdj++;
11927 }
11928 } else {
11929 didOomAdj = false;
11930 }
11931 }
11932
11933 // todo: for now pretend like OOM ADJ didn't work, because things
11934 // aren't behaving as expected on Linux -- it's not killing processes.
11935 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
11936 }
11937
11938 private final void trimApplications() {
11939 synchronized (this) {
11940 int i;
11941
11942 // First remove any unused application processes whose package
11943 // has been removed.
11944 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
11945 final ProcessRecord app = mRemovedProcesses.get(i);
11946 if (app.activities.size() == 0
11947 && app.curReceiver == null && app.services.size() == 0) {
11948 Log.i(
11949 TAG, "Exiting empty application process "
11950 + app.processName + " ("
11951 + (app.thread != null ? app.thread.asBinder() : null)
11952 + ")\n");
11953 if (app.pid > 0 && app.pid != MY_PID) {
11954 Process.killProcess(app.pid);
11955 } else {
11956 try {
11957 app.thread.scheduleExit();
11958 } catch (Exception e) {
11959 // Ignore exceptions.
11960 }
11961 }
11962 cleanUpApplicationRecordLocked(app, false, -1);
11963 mRemovedProcesses.remove(i);
11964
11965 if (app.persistent) {
11966 if (app.persistent) {
11967 addAppLocked(app.info);
11968 }
11969 }
11970 }
11971 }
11972
11973 // Now try updating the OOM adjustment for each of the
11974 // application processes based on their current state.
11975 // If the setOomAdj() API is not supported, then go with our
11976 // back-up plan...
11977 if (!updateOomAdjLocked()) {
11978
11979 // Count how many processes are running services.
11980 int numServiceProcs = 0;
11981 for (i=mLRUProcesses.size()-1; i>=0; i--) {
11982 final ProcessRecord app = mLRUProcesses.get(i);
11983
11984 if (app.persistent || app.services.size() != 0
11985 || app.curReceiver != null
11986 || app.persistentActivities > 0) {
11987 // Don't count processes holding services against our
11988 // maximum process count.
11989 if (localLOGV) Log.v(
11990 TAG, "Not trimming app " + app + " with services: "
11991 + app.services);
11992 numServiceProcs++;
11993 }
11994 }
11995
11996 int curMaxProcs = mProcessLimit;
11997 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
11998 if (mAlwaysFinishActivities) {
11999 curMaxProcs = 1;
12000 }
12001 curMaxProcs += numServiceProcs;
12002
12003 // Quit as many processes as we can to get down to the desired
12004 // process count. First remove any processes that no longer
12005 // have activites running in them.
12006 for ( i=0;
12007 i<mLRUProcesses.size()
12008 && mLRUProcesses.size() > curMaxProcs;
12009 i++) {
12010 final ProcessRecord app = mLRUProcesses.get(i);
12011 // Quit an application only if it is not currently
12012 // running any activities.
12013 if (!app.persistent && app.activities.size() == 0
12014 && app.curReceiver == null && app.services.size() == 0) {
12015 Log.i(
12016 TAG, "Exiting empty application process "
12017 + app.processName + " ("
12018 + (app.thread != null ? app.thread.asBinder() : null)
12019 + ")\n");
12020 if (app.pid > 0 && app.pid != MY_PID) {
12021 Process.killProcess(app.pid);
12022 } else {
12023 try {
12024 app.thread.scheduleExit();
12025 } catch (Exception e) {
12026 // Ignore exceptions.
12027 }
12028 }
12029 // todo: For now we assume the application is not buggy
12030 // or evil, and will quit as a result of our request.
12031 // Eventually we need to drive this off of the death
12032 // notification, and kill the process if it takes too long.
12033 cleanUpApplicationRecordLocked(app, false, i);
12034 i--;
12035 }
12036 }
12037
12038 // If we still have too many processes, now from the least
12039 // recently used process we start finishing activities.
12040 if (Config.LOGV) Log.v(
12041 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12042 " of " + curMaxProcs + " processes");
12043 for ( i=0;
12044 i<mLRUProcesses.size()
12045 && mLRUProcesses.size() > curMaxProcs;
12046 i++) {
12047 final ProcessRecord app = mLRUProcesses.get(i);
12048 // Quit the application only if we have a state saved for
12049 // all of its activities.
12050 boolean canQuit = !app.persistent && app.curReceiver == null
12051 && app.services.size() == 0
12052 && app.persistentActivities == 0;
12053 int NUMA = app.activities.size();
12054 int j;
12055 if (Config.LOGV) Log.v(
12056 TAG, "Looking to quit " + app.processName);
12057 for (j=0; j<NUMA && canQuit; j++) {
12058 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12059 if (Config.LOGV) Log.v(
12060 TAG, " " + r.intent.getComponent().flattenToShortString()
12061 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12062 canQuit = (r.haveState || !r.stateNotNeeded)
12063 && !r.visible && r.stopped;
12064 }
12065 if (canQuit) {
12066 // Finish all of the activities, and then the app itself.
12067 for (j=0; j<NUMA; j++) {
12068 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12069 if (!r.finishing) {
12070 destroyActivityLocked(r, false);
12071 }
12072 r.resultTo = null;
12073 }
12074 Log.i(TAG, "Exiting application process "
12075 + app.processName + " ("
12076 + (app.thread != null ? app.thread.asBinder() : null)
12077 + ")\n");
12078 if (app.pid > 0 && app.pid != MY_PID) {
12079 Process.killProcess(app.pid);
12080 } else {
12081 try {
12082 app.thread.scheduleExit();
12083 } catch (Exception e) {
12084 // Ignore exceptions.
12085 }
12086 }
12087 // todo: For now we assume the application is not buggy
12088 // or evil, and will quit as a result of our request.
12089 // Eventually we need to drive this off of the death
12090 // notification, and kill the process if it takes too long.
12091 cleanUpApplicationRecordLocked(app, false, i);
12092 i--;
12093 //dump();
12094 }
12095 }
12096
12097 }
12098
12099 int curMaxActivities = MAX_ACTIVITIES;
12100 if (mAlwaysFinishActivities) {
12101 curMaxActivities = 1;
12102 }
12103
12104 // Finally, if there are too many activities now running, try to
12105 // finish as many as we can to get back down to the limit.
12106 for ( i=0;
12107 i<mLRUActivities.size()
12108 && mLRUActivities.size() > curMaxActivities;
12109 i++) {
12110 final HistoryRecord r
12111 = (HistoryRecord)mLRUActivities.get(i);
12112
12113 // We can finish this one if we have its icicle saved and
12114 // it is not persistent.
12115 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12116 && r.stopped && !r.persistent && !r.finishing) {
12117 final int origSize = mLRUActivities.size();
12118 destroyActivityLocked(r, true);
12119
12120 // This will remove it from the LRU list, so keep
12121 // our index at the same value. Note that this check to
12122 // see if the size changes is just paranoia -- if
12123 // something unexpected happens, we don't want to end up
12124 // in an infinite loop.
12125 if (origSize > mLRUActivities.size()) {
12126 i--;
12127 }
12128 }
12129 }
12130 }
12131 }
12132
12133 /** This method sends the specified signal to each of the persistent apps */
12134 public void signalPersistentProcesses(int sig) throws RemoteException {
12135 if (sig != Process.SIGNAL_USR1) {
12136 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12137 }
12138
12139 synchronized (this) {
12140 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12141 != PackageManager.PERMISSION_GRANTED) {
12142 throw new SecurityException("Requires permission "
12143 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12144 }
12145
12146 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12147 ProcessRecord r = mLRUProcesses.get(i);
12148 if (r.thread != null && r.persistent) {
12149 Process.sendSignal(r.pid, sig);
12150 }
12151 }
12152 }
12153 }
12154
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012155 public boolean profileControl(String process, boolean start,
12156 String path) throws RemoteException {
12157
12158 synchronized (this) {
12159 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12160 // its own permission.
12161 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12162 != PackageManager.PERMISSION_GRANTED) {
12163 throw new SecurityException("Requires permission "
12164 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12165 }
12166
12167 ProcessRecord proc = null;
12168 try {
12169 int pid = Integer.parseInt(process);
12170 synchronized (mPidsSelfLocked) {
12171 proc = mPidsSelfLocked.get(pid);
12172 }
12173 } catch (NumberFormatException e) {
12174 }
12175
12176 if (proc == null) {
12177 HashMap<String, SparseArray<ProcessRecord>> all
12178 = mProcessNames.getMap();
12179 SparseArray<ProcessRecord> procs = all.get(process);
12180 if (procs != null && procs.size() > 0) {
12181 proc = procs.valueAt(0);
12182 }
12183 }
12184
12185 if (proc == null || proc.thread == null) {
12186 throw new IllegalArgumentException("Unknown process: " + process);
12187 }
12188
12189 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12190 if (isSecure) {
12191 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12192 throw new SecurityException("Process not debuggable: " + proc);
12193 }
12194 }
12195
12196 try {
12197 proc.thread.profilerControl(start, path);
12198 return true;
12199 } catch (RemoteException e) {
12200 throw new IllegalStateException("Process disappeared");
12201 }
12202 }
12203 }
12204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012205 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12206 public void monitor() {
12207 synchronized (this) { }
12208 }
12209}