blob: f2959e375ae0b5caff063271baac43eacc2ccfd8 [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;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
35import android.app.IActivityWatcher;
36import android.app.IApplicationThread;
37import android.app.IInstrumentationWatcher;
38import android.app.IIntentReceiver;
39import android.app.IIntentSender;
40import android.app.IServiceConnection;
41import android.app.IThumbnailReceiver;
42import android.app.Instrumentation;
43import android.app.PendingIntent;
44import android.app.ResultInfo;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020045import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
47import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
51import android.content.pm.ActivityInfo;
52import android.content.pm.ApplicationInfo;
53import android.content.pm.ConfigurationInfo;
54import android.content.pm.IPackageDataObserver;
55import android.content.pm.IPackageManager;
56import android.content.pm.InstrumentationInfo;
57import android.content.pm.PackageManager;
58import android.content.pm.ProviderInfo;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
61import android.content.res.Configuration;
62import android.graphics.Bitmap;
63import android.net.Uri;
64import android.os.Binder;
65import android.os.Bundle;
66import android.os.Environment;
67import android.os.FileUtils;
68import android.os.Handler;
69import android.os.IBinder;
70import android.os.IPermissionController;
71import android.os.Looper;
72import android.os.Message;
73import android.os.Parcel;
74import android.os.ParcelFileDescriptor;
75import android.os.PowerManager;
76import android.os.Process;
77import android.os.RemoteException;
78import android.os.ServiceManager;
79import android.os.SystemClock;
80import android.os.SystemProperties;
81import android.provider.Checkin;
82import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020083import android.server.data.CrashData;
84import android.server.data.StackTraceElementData;
85import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.text.TextUtils;
87import android.util.Config;
88import android.util.EventLog;
89import android.util.Log;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020090import android.util.LogPrinter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.util.PrintWriterPrinter;
92import android.util.SparseArray;
93import android.view.Gravity;
94import android.view.LayoutInflater;
95import android.view.View;
96import android.view.WindowManager;
97import android.view.WindowManagerPolicy;
98
99import dalvik.system.Zygote;
100
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200101import java.io.ByteArrayInputStream;
102import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import java.io.File;
104import java.io.FileDescriptor;
105import java.io.FileInputStream;
106import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200107import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.PrintWriter;
109import java.lang.IllegalStateException;
110import java.lang.ref.WeakReference;
111import java.util.ArrayList;
112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.Iterator;
115import java.util.List;
116import java.util.Locale;
117import java.util.Map;
118
119public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
120 static final String TAG = "ActivityManager";
121 static final boolean DEBUG = false;
122 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
123 static final boolean DEBUG_SWITCH = localLOGV || false;
124 static final boolean DEBUG_TASKS = localLOGV || false;
125 static final boolean DEBUG_PAUSE = localLOGV || false;
126 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
127 static final boolean DEBUG_TRANSITION = localLOGV || false;
128 static final boolean DEBUG_BROADCAST = localLOGV || false;
129 static final boolean DEBUG_SERVICE = localLOGV || false;
130 static final boolean DEBUG_VISBILITY = localLOGV || false;
131 static final boolean DEBUG_PROCESSES = localLOGV || false;
132 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700133 static final boolean DEBUG_RESULTS = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 static final boolean VALIDATE_TOKENS = false;
135 static final boolean SHOW_ACTIVITY_START_TIME = true;
136
137 // Control over CPU and battery monitoring.
138 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
139 static final boolean MONITOR_CPU_USAGE = true;
140 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
141 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
142 static final boolean MONITOR_THREAD_CPU_USAGE = false;
143
144 // Event log tags
145 static final int LOG_CONFIGURATION_CHANGED = 2719;
146 static final int LOG_CPU = 2721;
147 static final int LOG_AM_FINISH_ACTIVITY = 30001;
148 static final int LOG_TASK_TO_FRONT = 30002;
149 static final int LOG_AM_NEW_INTENT = 30003;
150 static final int LOG_AM_CREATE_TASK = 30004;
151 static final int LOG_AM_CREATE_ACTIVITY = 30005;
152 static final int LOG_AM_RESTART_ACTIVITY = 30006;
153 static final int LOG_AM_RESUME_ACTIVITY = 30007;
154 static final int LOG_ANR = 30008;
155 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
156 static final int LOG_AM_PROCESS_BOUND = 30010;
157 static final int LOG_AM_PROCESS_DIED = 30011;
158 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
159 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
160 static final int LOG_AM_PROCESS_START = 30014;
161 static final int LOG_AM_PROCESS_BAD = 30015;
162 static final int LOG_AM_PROCESS_GOOD = 30016;
163 static final int LOG_AM_LOW_MEMORY = 30017;
164 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
165 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
166 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
167 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
168 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
169 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
170 static final int LOG_AM_CREATE_SERVICE = 30030;
171 static final int LOG_AM_DESTROY_SERVICE = 30031;
172 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
173 static final int LOG_AM_DROP_PROCESS = 30033;
174 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
175 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
176 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
177
178 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
179 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
180
Dianne Hackborn1655be42009-05-08 14:29:01 -0700181 // The flags that are set for all calls we make to the package manager.
182 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
183 | PackageManager.GET_SUPPORTS_DENSITIES;
184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 private static final String SYSTEM_SECURE = "ro.secure";
186
187 // This is the maximum number of application processes we would like
188 // to have running. Due to the asynchronous nature of things, we can
189 // temporarily go beyond this limit.
190 static final int MAX_PROCESSES = 2;
191
192 // Set to false to leave processes running indefinitely, relying on
193 // the kernel killing them as resources are required.
194 static final boolean ENFORCE_PROCESS_LIMIT = false;
195
196 // This is the maximum number of activities that we would like to have
197 // running at a given time.
198 static final int MAX_ACTIVITIES = 20;
199
200 // Maximum number of recent tasks that we can remember.
201 static final int MAX_RECENT_TASKS = 20;
202
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700203 // Amount of time after a call to stopAppSwitches() during which we will
204 // prevent further untrusted switches from happening.
205 static final long APP_SWITCH_DELAY_TIME = 5*1000;
206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 // How long until we reset a task when the user returns to it. Currently
208 // 30 minutes.
209 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
210
211 // Set to true to disable the icon that is shown while a new activity
212 // is being started.
213 static final boolean SHOW_APP_STARTING_ICON = true;
214
215 // How long we wait until giving up on the last activity to pause. This
216 // is short because it directly impacts the responsiveness of starting the
217 // next activity.
218 static final int PAUSE_TIMEOUT = 500;
219
220 /**
221 * How long we can hold the launch wake lock before giving up.
222 */
223 static final int LAUNCH_TIMEOUT = 10*1000;
224
225 // How long we wait for a launched process to attach to the activity manager
226 // before we decide it's never going to come up for real.
227 static final int PROC_START_TIMEOUT = 10*1000;
228
229 // How long we wait until giving up on the last activity telling us it
230 // is idle.
231 static final int IDLE_TIMEOUT = 10*1000;
232
233 // How long to wait after going idle before forcing apps to GC.
234 static final int GC_TIMEOUT = 5*1000;
235
236 // How long we wait until giving up on an activity telling us it has
237 // finished destroying itself.
238 static final int DESTROY_TIMEOUT = 10*1000;
239
240 // How long we allow a receiver to run before giving up on it.
241 static final int BROADCAST_TIMEOUT = 10*1000;
242
243 // How long we wait for a service to finish executing.
244 static final int SERVICE_TIMEOUT = 20*1000;
245
246 // How long a service needs to be running until restarting its process
247 // is no longer considered to be a relaunch of the service.
248 static final int SERVICE_RESTART_DURATION = 5*1000;
249
250 // Maximum amount of time for there to be no activity on a service before
251 // we consider it non-essential and allow its process to go on the
252 // LRU background list.
253 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
254
255 // How long we wait until we timeout on key dispatching.
256 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
257
258 // The minimum time we allow between crashes, for us to consider this
259 // application to be bad and stop and its services and reject broadcasts.
260 static final int MIN_CRASH_INTERVAL = 60*1000;
261
262 // How long we wait until we timeout on key dispatching during instrumentation.
263 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
264
265 // OOM adjustments for processes in various states:
266
267 // This is a process without anything currently running in it. Definitely
268 // the first to go! Value set in system/rootdir/init.rc on startup.
269 // This value is initalized in the constructor, careful when refering to
270 // this static variable externally.
271 static int EMPTY_APP_ADJ;
272
273 // This is a process with a content provider that does not have any clients
274 // attached to it. If it did have any clients, its adjustment would be the
275 // one for the highest-priority of those processes.
276 static int CONTENT_PROVIDER_ADJ;
277
278 // This is a process only hosting activities that are not visible,
279 // so it can be killed without any disruption. Value set in
280 // system/rootdir/init.rc on startup.
281 final int HIDDEN_APP_MAX_ADJ;
282 static int HIDDEN_APP_MIN_ADJ;
283
The Android Open Source Project4df24232009-03-05 14:34:35 -0800284 // This is a process holding the home application -- we want to try
285 // avoiding killing it, even if it would normally be in the background,
286 // because the user interacts with it so much.
287 final int HOME_APP_ADJ;
288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 // This is a process holding a secondary server -- killing it will not
290 // have much of an impact as far as the user is concerned. Value set in
291 // system/rootdir/init.rc on startup.
292 final int SECONDARY_SERVER_ADJ;
293
294 // This is a process only hosting activities that are visible to the
295 // user, so we'd prefer they don't disappear. Value set in
296 // system/rootdir/init.rc on startup.
297 final int VISIBLE_APP_ADJ;
298
299 // This is the process running the current foreground app. We'd really
300 // rather not kill it! Value set in system/rootdir/init.rc on startup.
301 final int FOREGROUND_APP_ADJ;
302
303 // This is a process running a core server, such as telephony. Definitely
304 // don't want to kill it, but doing so is not completely fatal.
305 static final int CORE_SERVER_ADJ = -12;
306
307 // The system process runs at the default adjustment.
308 static final int SYSTEM_ADJ = -16;
309
310 // Memory pages are 4K.
311 static final int PAGE_SIZE = 4*1024;
312
313 // Corresponding memory levels for above adjustments.
314 final int EMPTY_APP_MEM;
315 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800316 final int HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 final int SECONDARY_SERVER_MEM;
318 final int VISIBLE_APP_MEM;
319 final int FOREGROUND_APP_MEM;
320
321 final int MY_PID;
322
323 static final String[] EMPTY_STRING_ARRAY = new String[0];
324
325 enum ActivityState {
326 INITIALIZING,
327 RESUMED,
328 PAUSING,
329 PAUSED,
330 STOPPING,
331 STOPPED,
332 FINISHING,
333 DESTROYING,
334 DESTROYED
335 }
336
337 /**
338 * The back history of all previous (and possibly still
339 * running) activities. It contains HistoryRecord objects.
340 */
341 final ArrayList mHistory = new ArrayList();
342
343 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700344 * Description of a request to start a new activity, which has been held
345 * due to app switches being disabled.
346 */
347 class PendingActivityLaunch {
348 HistoryRecord r;
349 HistoryRecord sourceRecord;
350 Uri[] grantedUriPermissions;
351 int grantedMode;
352 boolean onlyIfNeeded;
353 }
354
355 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
356 = new ArrayList<PendingActivityLaunch>();
357
358 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 * List of all active broadcasts that are to be executed immediately
360 * (without waiting for another broadcast to finish). Currently this only
361 * contains broadcasts to registered receivers, to avoid spinning up
362 * a bunch of processes to execute IntentReceiver components.
363 */
364 final ArrayList<BroadcastRecord> mParallelBroadcasts
365 = new ArrayList<BroadcastRecord>();
366
367 /**
368 * List of all active broadcasts that are to be executed one at a time.
369 * The object at the top of the list is the currently activity broadcasts;
370 * those after it are waiting for the top to finish..
371 */
372 final ArrayList<BroadcastRecord> mOrderedBroadcasts
373 = new ArrayList<BroadcastRecord>();
374
375 /**
376 * Set when we current have a BROADCAST_INTENT_MSG in flight.
377 */
378 boolean mBroadcastsScheduled = false;
379
380 /**
381 * Set to indicate whether to issue an onUserLeaving callback when a
382 * newly launched activity is being brought in front of us.
383 */
384 boolean mUserLeaving = false;
385
386 /**
387 * When we are in the process of pausing an activity, before starting the
388 * next one, this variable holds the activity that is currently being paused.
389 */
390 HistoryRecord mPausingActivity = null;
391
392 /**
393 * Current activity that is resumed, or null if there is none.
394 */
395 HistoryRecord mResumedActivity = null;
396
397 /**
398 * Activity we have told the window manager to have key focus.
399 */
400 HistoryRecord mFocusedActivity = null;
401
402 /**
403 * This is the last activity that we put into the paused state. This is
404 * used to determine if we need to do an activity transition while sleeping,
405 * when we normally hold the top activity paused.
406 */
407 HistoryRecord mLastPausedActivity = null;
408
409 /**
410 * List of activities that are waiting for a new activity
411 * to become visible before completing whatever operation they are
412 * supposed to do.
413 */
414 final ArrayList mWaitingVisibleActivities = new ArrayList();
415
416 /**
417 * List of activities that are ready to be stopped, but waiting
418 * for the next activity to settle down before doing so. It contains
419 * HistoryRecord objects.
420 */
421 final ArrayList<HistoryRecord> mStoppingActivities
422 = new ArrayList<HistoryRecord>();
423
424 /**
425 * List of intents that were used to start the most recent tasks.
426 */
427 final ArrayList<TaskRecord> mRecentTasks
428 = new ArrayList<TaskRecord>();
429
430 /**
431 * List of activities that are ready to be finished, but waiting
432 * for the previous activity to settle down before doing so. It contains
433 * HistoryRecord objects.
434 */
435 final ArrayList mFinishingActivities = new ArrayList();
436
437 /**
438 * All of the applications we currently have running organized by name.
439 * The keys are strings of the application package name (as
440 * returned by the package manager), and the keys are ApplicationRecord
441 * objects.
442 */
443 final ProcessMap<ProcessRecord> mProcessNames
444 = new ProcessMap<ProcessRecord>();
445
446 /**
447 * The last time that various processes have crashed.
448 */
449 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
450
451 /**
452 * Set of applications that we consider to be bad, and will reject
453 * incoming broadcasts from (which the user has no control over).
454 * Processes are added to this set when they have crashed twice within
455 * a minimum amount of time; they are removed from it when they are
456 * later restarted (hopefully due to some user action). The value is the
457 * time it was added to the list.
458 */
459 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
460
461 /**
462 * All of the processes we currently have running organized by pid.
463 * The keys are the pid running the application.
464 *
465 * <p>NOTE: This object is protected by its own lock, NOT the global
466 * activity manager lock!
467 */
468 final SparseArray<ProcessRecord> mPidsSelfLocked
469 = new SparseArray<ProcessRecord>();
470
471 /**
472 * All of the processes that have been forced to be foreground. The key
473 * is the pid of the caller who requested it (we hold a death
474 * link on it).
475 */
476 abstract class ForegroundToken implements IBinder.DeathRecipient {
477 int pid;
478 IBinder token;
479 }
480 final SparseArray<ForegroundToken> mForegroundProcesses
481 = new SparseArray<ForegroundToken>();
482
483 /**
484 * List of records for processes that someone had tried to start before the
485 * system was ready. We don't start them at that point, but ensure they
486 * are started by the time booting is complete.
487 */
488 final ArrayList<ProcessRecord> mProcessesOnHold
489 = new ArrayList<ProcessRecord>();
490
491 /**
492 * List of records for processes that we have started and are waiting
493 * for them to call back. This is really only needed when running in
494 * single processes mode, in which case we do not have a unique pid for
495 * each process.
496 */
497 final ArrayList<ProcessRecord> mStartingProcesses
498 = new ArrayList<ProcessRecord>();
499
500 /**
501 * List of persistent applications that are in the process
502 * of being started.
503 */
504 final ArrayList<ProcessRecord> mPersistentStartingProcesses
505 = new ArrayList<ProcessRecord>();
506
507 /**
508 * Processes that are being forcibly torn down.
509 */
510 final ArrayList<ProcessRecord> mRemovedProcesses
511 = new ArrayList<ProcessRecord>();
512
513 /**
514 * List of running applications, sorted by recent usage.
515 * The first entry in the list is the least recently used.
516 * It contains ApplicationRecord objects. This list does NOT include
517 * any persistent application records (since we never want to exit them).
518 */
519 final ArrayList<ProcessRecord> mLRUProcesses
520 = new ArrayList<ProcessRecord>();
521
522 /**
523 * List of processes that should gc as soon as things are idle.
524 */
525 final ArrayList<ProcessRecord> mProcessesToGc
526 = new ArrayList<ProcessRecord>();
527
528 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800529 * This is the process holding what we currently consider to be
530 * the "home" activity.
531 */
532 private ProcessRecord mHomeProcess;
533
534 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 * List of running activities, sorted by recent usage.
536 * The first entry in the list is the least recently used.
537 * It contains HistoryRecord objects.
538 */
539 private final ArrayList mLRUActivities = new ArrayList();
540
541 /**
542 * Set of PendingResultRecord objects that are currently active.
543 */
544 final HashSet mPendingResultRecords = new HashSet();
545
546 /**
547 * Set of IntentSenderRecord objects that are currently active.
548 */
549 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
550 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
551
552 /**
553 * Intent broadcast that we have tried to start, but are
554 * waiting for its application's process to be created. We only
555 * need one (instead of a list) because we always process broadcasts
556 * one at a time, so no others can be started while waiting for this
557 * one.
558 */
559 BroadcastRecord mPendingBroadcast = null;
560
561 /**
562 * Keeps track of all IIntentReceivers that have been registered for
563 * broadcasts. Hash keys are the receiver IBinder, hash value is
564 * a ReceiverList.
565 */
566 final HashMap mRegisteredReceivers = new HashMap();
567
568 /**
569 * Resolver for broadcast intents to registered receivers.
570 * Holds BroadcastFilter (subclass of IntentFilter).
571 */
572 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
573 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
574 @Override
575 protected boolean allowFilterResult(
576 BroadcastFilter filter, List<BroadcastFilter> dest) {
577 IBinder target = filter.receiverList.receiver.asBinder();
578 for (int i=dest.size()-1; i>=0; i--) {
579 if (dest.get(i).receiverList.receiver.asBinder() == target) {
580 return false;
581 }
582 }
583 return true;
584 }
585 };
586
587 /**
588 * State of all active sticky broadcasts. Keys are the action of the
589 * sticky Intent, values are an ArrayList of all broadcasted intents with
590 * that action (which should usually be one).
591 */
592 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
593 new HashMap<String, ArrayList<Intent>>();
594
595 /**
596 * All currently running services.
597 */
598 final HashMap<ComponentName, ServiceRecord> mServices =
599 new HashMap<ComponentName, ServiceRecord>();
600
601 /**
602 * All currently running services indexed by the Intent used to start them.
603 */
604 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
605 new HashMap<Intent.FilterComparison, ServiceRecord>();
606
607 /**
608 * All currently bound service connections. Keys are the IBinder of
609 * the client's IServiceConnection.
610 */
611 final HashMap<IBinder, ConnectionRecord> mServiceConnections
612 = new HashMap<IBinder, ConnectionRecord>();
613
614 /**
615 * List of services that we have been asked to start,
616 * but haven't yet been able to. It is used to hold start requests
617 * while waiting for their corresponding application thread to get
618 * going.
619 */
620 final ArrayList<ServiceRecord> mPendingServices
621 = new ArrayList<ServiceRecord>();
622
623 /**
624 * List of services that are scheduled to restart following a crash.
625 */
626 final ArrayList<ServiceRecord> mRestartingServices
627 = new ArrayList<ServiceRecord>();
628
629 /**
630 * List of services that are in the process of being stopped.
631 */
632 final ArrayList<ServiceRecord> mStoppingServices
633 = new ArrayList<ServiceRecord>();
634
635 /**
636 * List of PendingThumbnailsRecord objects of clients who are still
637 * waiting to receive all of the thumbnails for a task.
638 */
639 final ArrayList mPendingThumbnails = new ArrayList();
640
641 /**
642 * List of HistoryRecord objects that have been finished and must
643 * still report back to a pending thumbnail receiver.
644 */
645 final ArrayList mCancelledThumbnails = new ArrayList();
646
647 /**
648 * All of the currently running global content providers. Keys are a
649 * string containing the provider name and values are a
650 * ContentProviderRecord object containing the data about it. Note
651 * that a single provider may be published under multiple names, so
652 * there may be multiple entries here for a single one in mProvidersByClass.
653 */
654 final HashMap mProvidersByName = new HashMap();
655
656 /**
657 * All of the currently running global content providers. Keys are a
658 * string containing the provider's implementation class and values are a
659 * ContentProviderRecord object containing the data about it.
660 */
661 final HashMap mProvidersByClass = new HashMap();
662
663 /**
664 * List of content providers who have clients waiting for them. The
665 * application is currently being launched and the provider will be
666 * removed from this list once it is published.
667 */
668 final ArrayList mLaunchingProviders = new ArrayList();
669
670 /**
671 * Global set of specific Uri permissions that have been granted.
672 */
673 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
674 = new SparseArray<HashMap<Uri, UriPermission>>();
675
676 /**
677 * Thread-local storage used to carry caller permissions over through
678 * indirect content-provider access.
679 * @see #ActivityManagerService.openContentUri()
680 */
681 private class Identity {
682 public int pid;
683 public int uid;
684
685 Identity(int _pid, int _uid) {
686 pid = _pid;
687 uid = _uid;
688 }
689 }
690 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
691
692 /**
693 * All information we have collected about the runtime performance of
694 * any user id that can impact battery performance.
695 */
696 final BatteryStatsService mBatteryStatsService;
697
698 /**
699 * information about component usage
700 */
701 final UsageStatsService mUsageStatsService;
702
703 /**
704 * Current configuration information. HistoryRecord objects are given
705 * a reference to this object to indicate which configuration they are
706 * currently running in, so this object must be kept immutable.
707 */
708 Configuration mConfiguration = new Configuration();
709
710 /**
711 * List of initialization arguments to pass to all processes when binding applications to them.
712 * For example, references to the commonly used services.
713 */
714 HashMap<String, IBinder> mAppBindArgs;
715
716 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700717 * Temporary to avoid allocations. Protected by main lock.
718 */
719 final StringBuilder mStringBuilder = new StringBuilder(256);
720
721 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 * Used to control how we initialize the service.
723 */
724 boolean mStartRunning = false;
725 ComponentName mTopComponent;
726 String mTopAction;
727 String mTopData;
728 boolean mSystemReady = false;
729 boolean mBooting = false;
730
731 Context mContext;
732
733 int mFactoryTest;
734
735 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700736 * The time at which we will allow normal application switches again,
737 * after a call to {@link #stopAppSwitches()}.
738 */
739 long mAppSwitchesAllowedTime;
740
741 /**
742 * This is set to true after the first switch after mAppSwitchesAllowedTime
743 * is set; any switches after that will clear the time.
744 */
745 boolean mDidAppSwitch;
746
747 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 * Set while we are wanting to sleep, to prevent any
749 * activities from being started/resumed.
750 */
751 boolean mSleeping = false;
752
753 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700754 * Set if we are shutting down the system, similar to sleeping.
755 */
756 boolean mShuttingDown = false;
757
758 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 * Set when the system is going to sleep, until we have
760 * successfully paused the current activity and released our wake lock.
761 * At that point the system is allowed to actually sleep.
762 */
763 PowerManager.WakeLock mGoingToSleep;
764
765 /**
766 * We don't want to allow the device to go to sleep while in the process
767 * of launching an activity. This is primarily to allow alarm intent
768 * receivers to launch an activity and get that to run before the device
769 * goes back to sleep.
770 */
771 PowerManager.WakeLock mLaunchingActivity;
772
773 /**
774 * Task identifier that activities are currently being started
775 * in. Incremented each time a new task is created.
776 * todo: Replace this with a TokenSpace class that generates non-repeating
777 * integers that won't wrap.
778 */
779 int mCurTask = 1;
780
781 /**
782 * Current sequence id for oom_adj computation traversal.
783 */
784 int mAdjSeq = 0;
785
786 /**
787 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
788 * is set, indicating the user wants processes started in such a way
789 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
790 * running in each process (thus no pre-initialized process, etc).
791 */
792 boolean mSimpleProcessManagement = false;
793
794 /**
795 * System monitoring: number of processes that died since the last
796 * N procs were started.
797 */
798 int[] mProcDeaths = new int[20];
799
800 String mDebugApp = null;
801 boolean mWaitForDebugger = false;
802 boolean mDebugTransient = false;
803 String mOrigDebugApp = null;
804 boolean mOrigWaitForDebugger = false;
805 boolean mAlwaysFinishActivities = false;
806 IActivityWatcher mWatcher = null;
807
808 /**
809 * Callback of last caller to {@link #requestPss}.
810 */
811 Runnable mRequestPssCallback;
812
813 /**
814 * Remaining processes for which we are waiting results from the last
815 * call to {@link #requestPss}.
816 */
817 final ArrayList<ProcessRecord> mRequestPssList
818 = new ArrayList<ProcessRecord>();
819
820 /**
821 * Runtime statistics collection thread. This object's lock is used to
822 * protect all related state.
823 */
824 final Thread mProcessStatsThread;
825
826 /**
827 * Used to collect process stats when showing not responding dialog.
828 * Protected by mProcessStatsThread.
829 */
830 final ProcessStats mProcessStats = new ProcessStats(
831 MONITOR_THREAD_CPU_USAGE);
832 long mLastCpuTime = 0;
833 long mLastWriteTime = 0;
834
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700835 long mInitialStartTime = 0;
836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 /**
838 * Set to true after the system has finished booting.
839 */
840 boolean mBooted = false;
841
842 int mProcessLimit = 0;
843
844 WindowManagerService mWindowManager;
845
846 static ActivityManagerService mSelf;
847 static ActivityThread mSystemThread;
848
849 private final class AppDeathRecipient implements IBinder.DeathRecipient {
850 final ProcessRecord mApp;
851 final int mPid;
852 final IApplicationThread mAppThread;
853
854 AppDeathRecipient(ProcessRecord app, int pid,
855 IApplicationThread thread) {
856 if (localLOGV) Log.v(
857 TAG, "New death recipient " + this
858 + " for thread " + thread.asBinder());
859 mApp = app;
860 mPid = pid;
861 mAppThread = thread;
862 }
863
864 public void binderDied() {
865 if (localLOGV) Log.v(
866 TAG, "Death received in " + this
867 + " for thread " + mAppThread.asBinder());
868 removeRequestedPss(mApp);
869 synchronized(ActivityManagerService.this) {
870 appDiedLocked(mApp, mPid, mAppThread);
871 }
872 }
873 }
874
875 static final int SHOW_ERROR_MSG = 1;
876 static final int SHOW_NOT_RESPONDING_MSG = 2;
877 static final int SHOW_FACTORY_ERROR_MSG = 3;
878 static final int UPDATE_CONFIGURATION_MSG = 4;
879 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
880 static final int WAIT_FOR_DEBUGGER_MSG = 6;
881 static final int BROADCAST_INTENT_MSG = 7;
882 static final int BROADCAST_TIMEOUT_MSG = 8;
883 static final int PAUSE_TIMEOUT_MSG = 9;
884 static final int IDLE_TIMEOUT_MSG = 10;
885 static final int IDLE_NOW_MSG = 11;
886 static final int SERVICE_TIMEOUT_MSG = 12;
887 static final int UPDATE_TIME_ZONE = 13;
888 static final int SHOW_UID_ERROR_MSG = 14;
889 static final int IM_FEELING_LUCKY_MSG = 15;
890 static final int LAUNCH_TIMEOUT_MSG = 16;
891 static final int DESTROY_TIMEOUT_MSG = 17;
892 static final int SERVICE_ERROR_MSG = 18;
893 static final int RESUME_TOP_ACTIVITY_MSG = 19;
894 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700895 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896
897 AlertDialog mUidAlert;
898
899 final Handler mHandler = new Handler() {
900 //public Handler() {
901 // if (localLOGV) Log.v(TAG, "Handler started!");
902 //}
903
904 public void handleMessage(Message msg) {
905 switch (msg.what) {
906 case SHOW_ERROR_MSG: {
907 HashMap data = (HashMap) msg.obj;
908 byte[] crashData = (byte[])data.get("crashData");
909 if (crashData != null) {
910 // This needs to be *un*synchronized to avoid deadlock.
911 ContentResolver resolver = mContext.getContentResolver();
912 Checkin.reportCrash(resolver, crashData);
913 }
914 synchronized (ActivityManagerService.this) {
915 ProcessRecord proc = (ProcessRecord)data.get("app");
916 if (proc != null && proc.crashDialog != null) {
917 Log.e(TAG, "App already has crash dialog: " + proc);
918 return;
919 }
920 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700921 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 Dialog d = new AppErrorDialog(
923 mContext, res, proc,
924 (Integer)data.get("flags"),
925 (String)data.get("shortMsg"),
926 (String)data.get("longMsg"));
927 d.show();
928 proc.crashDialog = d;
929 } else {
930 // The device is asleep, so just pretend that the user
931 // saw a crash dialog and hit "force quit".
932 res.set(0);
933 }
934 }
935 } break;
936 case SHOW_NOT_RESPONDING_MSG: {
937 synchronized (ActivityManagerService.this) {
938 HashMap data = (HashMap) msg.obj;
939 ProcessRecord proc = (ProcessRecord)data.get("app");
940 if (proc != null && proc.anrDialog != null) {
941 Log.e(TAG, "App already has anr dialog: " + proc);
942 return;
943 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800944
945 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
946 null, null, 0, null, null, null,
947 false, false, MY_PID, Process.SYSTEM_UID);
948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
950 mContext, proc, (HistoryRecord)data.get("activity"));
951 d.show();
952 proc.anrDialog = d;
953 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700954
955 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 } break;
957 case SHOW_FACTORY_ERROR_MSG: {
958 Dialog d = new FactoryErrorDialog(
959 mContext, msg.getData().getCharSequence("msg"));
960 d.show();
961 enableScreenAfterBoot();
962 } break;
963 case UPDATE_CONFIGURATION_MSG: {
964 final ContentResolver resolver = mContext.getContentResolver();
965 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
966 } break;
967 case GC_BACKGROUND_PROCESSES_MSG: {
968 synchronized (ActivityManagerService.this) {
969 performAppGcsIfAppropriateLocked();
970 }
971 } break;
972 case WAIT_FOR_DEBUGGER_MSG: {
973 synchronized (ActivityManagerService.this) {
974 ProcessRecord app = (ProcessRecord)msg.obj;
975 if (msg.arg1 != 0) {
976 if (!app.waitedForDebugger) {
977 Dialog d = new AppWaitingForDebuggerDialog(
978 ActivityManagerService.this,
979 mContext, app);
980 app.waitDialog = d;
981 app.waitedForDebugger = true;
982 d.show();
983 }
984 } else {
985 if (app.waitDialog != null) {
986 app.waitDialog.dismiss();
987 app.waitDialog = null;
988 }
989 }
990 }
991 } break;
992 case BROADCAST_INTENT_MSG: {
993 if (DEBUG_BROADCAST) Log.v(
994 TAG, "Received BROADCAST_INTENT_MSG");
995 processNextBroadcast(true);
996 } break;
997 case BROADCAST_TIMEOUT_MSG: {
998 broadcastTimeout();
999 } break;
1000 case PAUSE_TIMEOUT_MSG: {
1001 IBinder token = (IBinder)msg.obj;
1002 // We don't at this point know if the activity is fullscreen,
1003 // so we need to be conservative and assume it isn't.
1004 Log.w(TAG, "Activity pause timeout for " + token);
1005 activityPaused(token, null, true);
1006 } break;
1007 case IDLE_TIMEOUT_MSG: {
1008 IBinder token = (IBinder)msg.obj;
1009 // We don't at this point know if the activity is fullscreen,
1010 // so we need to be conservative and assume it isn't.
1011 Log.w(TAG, "Activity idle timeout for " + token);
1012 activityIdleInternal(token, true);
1013 } break;
1014 case DESTROY_TIMEOUT_MSG: {
1015 IBinder token = (IBinder)msg.obj;
1016 // We don't at this point know if the activity is fullscreen,
1017 // so we need to be conservative and assume it isn't.
1018 Log.w(TAG, "Activity destroy timeout for " + token);
1019 activityDestroyed(token);
1020 } break;
1021 case IDLE_NOW_MSG: {
1022 IBinder token = (IBinder)msg.obj;
1023 activityIdle(token);
1024 } break;
1025 case SERVICE_TIMEOUT_MSG: {
1026 serviceTimeout((ProcessRecord)msg.obj);
1027 } break;
1028 case UPDATE_TIME_ZONE: {
1029 synchronized (ActivityManagerService.this) {
1030 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1031 ProcessRecord r = mLRUProcesses.get(i);
1032 if (r.thread != null) {
1033 try {
1034 r.thread.updateTimeZone();
1035 } catch (RemoteException ex) {
1036 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1037 }
1038 }
1039 }
1040 }
1041 break;
1042 }
1043 case SHOW_UID_ERROR_MSG: {
1044 // XXX This is a temporary dialog, no need to localize.
1045 AlertDialog d = new BaseErrorDialog(mContext);
1046 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1047 d.setCancelable(false);
1048 d.setTitle("System UIDs Inconsistent");
1049 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1050 d.setButton("I'm Feeling Lucky",
1051 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1052 mUidAlert = d;
1053 d.show();
1054 } break;
1055 case IM_FEELING_LUCKY_MSG: {
1056 if (mUidAlert != null) {
1057 mUidAlert.dismiss();
1058 mUidAlert = null;
1059 }
1060 } break;
1061 case LAUNCH_TIMEOUT_MSG: {
1062 synchronized (ActivityManagerService.this) {
1063 if (mLaunchingActivity.isHeld()) {
1064 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1065 mLaunchingActivity.release();
1066 }
1067 }
1068 } break;
1069 case SERVICE_ERROR_MSG: {
1070 ServiceRecord srv = (ServiceRecord)msg.obj;
1071 // This needs to be *un*synchronized to avoid deadlock.
1072 Checkin.logEvent(mContext.getContentResolver(),
1073 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1074 srv.name.toShortString());
1075 } break;
1076 case RESUME_TOP_ACTIVITY_MSG: {
1077 synchronized (ActivityManagerService.this) {
1078 resumeTopActivityLocked(null);
1079 }
1080 }
1081 case PROC_START_TIMEOUT_MSG: {
1082 ProcessRecord app = (ProcessRecord)msg.obj;
1083 synchronized (ActivityManagerService.this) {
1084 processStartTimedOutLocked(app);
1085 }
1086 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001087 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1088 synchronized (ActivityManagerService.this) {
1089 doPendingActivityLaunchesLocked(true);
1090 }
1091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093 }
1094 };
1095
1096 public static void setSystemProcess() {
1097 try {
1098 ActivityManagerService m = mSelf;
1099
1100 ServiceManager.addService("activity", m);
1101 ServiceManager.addService("meminfo", new MemBinder(m));
1102 if (MONITOR_CPU_USAGE) {
1103 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1104 }
1105 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1106 ServiceManager.addService("activity.services", new ServicesBinder(m));
1107 ServiceManager.addService("activity.senders", new SendersBinder(m));
1108 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1109 ServiceManager.addService("permission", new PermissionController(m));
1110
1111 ApplicationInfo info =
1112 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001113 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 synchronized (mSelf) {
1115 ProcessRecord app = mSelf.newProcessRecordLocked(
1116 mSystemThread.getApplicationThread(), info,
1117 info.processName);
1118 app.persistent = true;
1119 app.pid = Process.myPid();
1120 app.maxAdj = SYSTEM_ADJ;
1121 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1122 synchronized (mSelf.mPidsSelfLocked) {
1123 mSelf.mPidsSelfLocked.put(app.pid, app);
1124 }
1125 mSelf.updateLRUListLocked(app, true);
1126 }
1127 } catch (PackageManager.NameNotFoundException e) {
1128 throw new RuntimeException(
1129 "Unable to find android system package", e);
1130 }
1131 }
1132
1133 public void setWindowManager(WindowManagerService wm) {
1134 mWindowManager = wm;
1135 }
1136
1137 public static final Context main(int factoryTest) {
1138 AThread thr = new AThread();
1139 thr.start();
1140
1141 synchronized (thr) {
1142 while (thr.mService == null) {
1143 try {
1144 thr.wait();
1145 } catch (InterruptedException e) {
1146 }
1147 }
1148 }
1149
1150 ActivityManagerService m = thr.mService;
1151 mSelf = m;
1152 ActivityThread at = ActivityThread.systemMain();
1153 mSystemThread = at;
1154 Context context = at.getSystemContext();
1155 m.mContext = context;
1156 m.mFactoryTest = factoryTest;
1157 PowerManager pm =
1158 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1159 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1160 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1161 m.mLaunchingActivity.setReferenceCounted(false);
1162
1163 m.mBatteryStatsService.publish(context);
1164 m.mUsageStatsService.publish(context);
1165
1166 synchronized (thr) {
1167 thr.mReady = true;
1168 thr.notifyAll();
1169 }
1170
1171 m.startRunning(null, null, null, null);
1172
1173 return context;
1174 }
1175
1176 public static ActivityManagerService self() {
1177 return mSelf;
1178 }
1179
1180 static class AThread extends Thread {
1181 ActivityManagerService mService;
1182 boolean mReady = false;
1183
1184 public AThread() {
1185 super("ActivityManager");
1186 }
1187
1188 public void run() {
1189 Looper.prepare();
1190
1191 android.os.Process.setThreadPriority(
1192 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1193
1194 ActivityManagerService m = new ActivityManagerService();
1195
1196 synchronized (this) {
1197 mService = m;
1198 notifyAll();
1199 }
1200
1201 synchronized (this) {
1202 while (!mReady) {
1203 try {
1204 wait();
1205 } catch (InterruptedException e) {
1206 }
1207 }
1208 }
1209
1210 Looper.loop();
1211 }
1212 }
1213
1214 static class BroadcastsBinder extends Binder {
1215 ActivityManagerService mActivityManagerService;
1216 BroadcastsBinder(ActivityManagerService activityManagerService) {
1217 mActivityManagerService = activityManagerService;
1218 }
1219
1220 @Override
1221 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1222 mActivityManagerService.dumpBroadcasts(pw);
1223 }
1224 }
1225
1226 static class ServicesBinder extends Binder {
1227 ActivityManagerService mActivityManagerService;
1228 ServicesBinder(ActivityManagerService activityManagerService) {
1229 mActivityManagerService = activityManagerService;
1230 }
1231
1232 @Override
1233 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1234 mActivityManagerService.dumpServices(pw);
1235 }
1236 }
1237
1238 static class SendersBinder extends Binder {
1239 ActivityManagerService mActivityManagerService;
1240 SendersBinder(ActivityManagerService activityManagerService) {
1241 mActivityManagerService = activityManagerService;
1242 }
1243
1244 @Override
1245 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1246 mActivityManagerService.dumpSenders(pw);
1247 }
1248 }
1249
1250 static class ProvidersBinder extends Binder {
1251 ActivityManagerService mActivityManagerService;
1252 ProvidersBinder(ActivityManagerService activityManagerService) {
1253 mActivityManagerService = activityManagerService;
1254 }
1255
1256 @Override
1257 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1258 mActivityManagerService.dumpProviders(pw);
1259 }
1260 }
1261
1262 static class MemBinder extends Binder {
1263 ActivityManagerService mActivityManagerService;
1264 MemBinder(ActivityManagerService activityManagerService) {
1265 mActivityManagerService = activityManagerService;
1266 }
1267
1268 @Override
1269 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1270 ActivityManagerService service = mActivityManagerService;
1271 ArrayList<ProcessRecord> procs;
1272 synchronized (mActivityManagerService) {
1273 if (args != null && args.length > 0
1274 && args[0].charAt(0) != '-') {
1275 procs = new ArrayList<ProcessRecord>();
1276 int pid = -1;
1277 try {
1278 pid = Integer.parseInt(args[0]);
1279 } catch (NumberFormatException e) {
1280
1281 }
1282 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1283 ProcessRecord proc = service.mLRUProcesses.get(i);
1284 if (proc.pid == pid) {
1285 procs.add(proc);
1286 } else if (proc.processName.equals(args[0])) {
1287 procs.add(proc);
1288 }
1289 }
1290 if (procs.size() <= 0) {
1291 pw.println("No process found for: " + args[0]);
1292 return;
1293 }
1294 } else {
1295 procs = service.mLRUProcesses;
1296 }
1297 }
1298 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1299 }
1300 }
1301
1302 static class CpuBinder extends Binder {
1303 ActivityManagerService mActivityManagerService;
1304 CpuBinder(ActivityManagerService activityManagerService) {
1305 mActivityManagerService = activityManagerService;
1306 }
1307
1308 @Override
1309 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1310 synchronized (mActivityManagerService.mProcessStatsThread) {
1311 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1312 }
1313 }
1314 }
1315
1316 private ActivityManagerService() {
1317 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1318 if (v != null && Integer.getInteger(v) != 0) {
1319 mSimpleProcessManagement = true;
1320 }
1321 v = System.getenv("ANDROID_DEBUG_APP");
1322 if (v != null) {
1323 mSimpleProcessManagement = true;
1324 }
1325
1326 MY_PID = Process.myPid();
1327
1328 File dataDir = Environment.getDataDirectory();
1329 File systemDir = new File(dataDir, "system");
1330 systemDir.mkdirs();
1331 mBatteryStatsService = new BatteryStatsService(new File(
1332 systemDir, "batterystats.bin").toString());
1333 mBatteryStatsService.getActiveStatistics().readLocked();
1334 mBatteryStatsService.getActiveStatistics().writeLocked();
1335
1336 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001337 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338
1339 mConfiguration.makeDefault();
1340 mProcessStats.init();
1341
1342 // Add ourself to the Watchdog monitors.
1343 Watchdog.getInstance().addMonitor(this);
1344
1345 // These values are set in system/rootdir/init.rc on startup.
1346 FOREGROUND_APP_ADJ =
1347 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1348 VISIBLE_APP_ADJ =
1349 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1350 SECONDARY_SERVER_ADJ =
1351 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001352 HOME_APP_ADJ =
1353 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 HIDDEN_APP_MIN_ADJ =
1355 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1356 CONTENT_PROVIDER_ADJ =
1357 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1358 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1359 EMPTY_APP_ADJ =
1360 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1361 FOREGROUND_APP_MEM =
1362 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1363 VISIBLE_APP_MEM =
1364 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1365 SECONDARY_SERVER_MEM =
1366 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001367 HOME_APP_MEM =
1368 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 HIDDEN_APP_MEM =
1370 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1371 EMPTY_APP_MEM =
1372 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1373
1374 mProcessStatsThread = new Thread("ProcessStats") {
1375 public void run() {
1376 while (true) {
1377 try {
1378 try {
1379 synchronized(this) {
1380 final long now = SystemClock.uptimeMillis();
1381 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1382 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1383 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1384 // + ", write delay=" + nextWriteDelay);
1385 if (nextWriteDelay < nextCpuDelay) {
1386 nextCpuDelay = nextWriteDelay;
1387 }
1388 if (nextCpuDelay > 0) {
1389 this.wait(nextCpuDelay);
1390 }
1391 }
1392 } catch (InterruptedException e) {
1393 }
1394
1395 updateCpuStatsNow();
1396 } catch (Exception e) {
1397 Log.e(TAG, "Unexpected exception collecting process stats", e);
1398 }
1399 }
1400 }
1401 };
1402 mProcessStatsThread.start();
1403 }
1404
1405 @Override
1406 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1407 throws RemoteException {
1408 try {
1409 return super.onTransact(code, data, reply, flags);
1410 } catch (RuntimeException e) {
1411 // The activity manager only throws security exceptions, so let's
1412 // log all others.
1413 if (!(e instanceof SecurityException)) {
1414 Log.e(TAG, "Activity Manager Crash", e);
1415 }
1416 throw e;
1417 }
1418 }
1419
1420 void updateCpuStats() {
1421 synchronized (mProcessStatsThread) {
1422 final long now = SystemClock.uptimeMillis();
1423 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1424 mProcessStatsThread.notify();
1425 }
1426 }
1427 }
1428
1429 void updateCpuStatsNow() {
1430 synchronized (mProcessStatsThread) {
1431 final long now = SystemClock.uptimeMillis();
1432 boolean haveNewCpuStats = false;
1433
1434 if (MONITOR_CPU_USAGE &&
1435 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1436 mLastCpuTime = now;
1437 haveNewCpuStats = true;
1438 mProcessStats.update();
1439 //Log.i(TAG, mProcessStats.printCurrentState());
1440 //Log.i(TAG, "Total CPU usage: "
1441 // + mProcessStats.getTotalCpuPercent() + "%");
1442
1443 // Log the cpu usage if the property is set.
1444 if ("true".equals(SystemProperties.get("events.cpu"))) {
1445 int user = mProcessStats.getLastUserTime();
1446 int system = mProcessStats.getLastSystemTime();
1447 int iowait = mProcessStats.getLastIoWaitTime();
1448 int irq = mProcessStats.getLastIrqTime();
1449 int softIrq = mProcessStats.getLastSoftIrqTime();
1450 int idle = mProcessStats.getLastIdleTime();
1451
1452 int total = user + system + iowait + irq + softIrq + idle;
1453 if (total == 0) total = 1;
1454
1455 EventLog.writeEvent(LOG_CPU,
1456 ((user+system+iowait+irq+softIrq) * 100) / total,
1457 (user * 100) / total,
1458 (system * 100) / total,
1459 (iowait * 100) / total,
1460 (irq * 100) / total,
1461 (softIrq * 100) / total);
1462 }
1463 }
1464
1465 synchronized(mBatteryStatsService.getActiveStatistics()) {
1466 synchronized(mPidsSelfLocked) {
1467 if (haveNewCpuStats) {
1468 if (mBatteryStatsService.isOnBattery()) {
1469 final int N = mProcessStats.countWorkingStats();
1470 for (int i=0; i<N; i++) {
1471 ProcessStats.Stats st
1472 = mProcessStats.getWorkingStats(i);
1473 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1474 if (pr != null) {
1475 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1476 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1477 }
1478 }
1479 }
1480 }
1481 }
1482
1483 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1484 mLastWriteTime = now;
1485 mBatteryStatsService.getActiveStatistics().writeLocked();
1486 }
1487 }
1488 }
1489 }
1490
1491 /**
1492 * Initialize the application bind args. These are passed to each
1493 * process when the bindApplication() IPC is sent to the process. They're
1494 * lazily setup to make sure the services are running when they're asked for.
1495 */
1496 private HashMap<String, IBinder> getCommonServicesLocked() {
1497 if (mAppBindArgs == null) {
1498 mAppBindArgs = new HashMap<String, IBinder>();
1499
1500 // Setup the application init args
1501 mAppBindArgs.put("package", ServiceManager.getService("package"));
1502 mAppBindArgs.put("window", ServiceManager.getService("window"));
1503 mAppBindArgs.put(Context.ALARM_SERVICE,
1504 ServiceManager.getService(Context.ALARM_SERVICE));
1505 }
1506 return mAppBindArgs;
1507 }
1508
1509 private final void setFocusedActivityLocked(HistoryRecord r) {
1510 if (mFocusedActivity != r) {
1511 mFocusedActivity = r;
1512 mWindowManager.setFocusedApp(r, true);
1513 }
1514 }
1515
1516 private final void updateLRUListLocked(ProcessRecord app,
1517 boolean oomAdj) {
1518 // put it on the LRU to keep track of when it should be exited.
1519 int lrui = mLRUProcesses.indexOf(app);
1520 if (lrui >= 0) mLRUProcesses.remove(lrui);
1521 mLRUProcesses.add(app);
1522 //Log.i(TAG, "Putting proc to front: " + app.processName);
1523 if (oomAdj) {
1524 updateOomAdjLocked();
1525 }
1526 }
1527
1528 private final boolean updateLRUListLocked(HistoryRecord r) {
1529 final boolean hadit = mLRUActivities.remove(r);
1530 mLRUActivities.add(r);
1531 return hadit;
1532 }
1533
1534 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1535 int i = mHistory.size()-1;
1536 while (i >= 0) {
1537 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1538 if (!r.finishing && r != notTop) {
1539 return r;
1540 }
1541 i--;
1542 }
1543 return null;
1544 }
1545
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001546 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1547 int i = mHistory.size()-1;
1548 while (i >= 0) {
1549 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1550 if (!r.finishing && !r.delayedResume && r != notTop) {
1551 return r;
1552 }
1553 i--;
1554 }
1555 return null;
1556 }
1557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 /**
1559 * This is a simplified version of topRunningActivityLocked that provides a number of
1560 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1561 *
1562 * @param token If non-null, any history records matching this token will be skipped.
1563 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1564 *
1565 * @return Returns the HistoryRecord of the next activity on the stack.
1566 */
1567 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1568 int i = mHistory.size()-1;
1569 while (i >= 0) {
1570 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1571 // Note: the taskId check depends on real taskId fields being non-zero
1572 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1573 return r;
1574 }
1575 i--;
1576 }
1577 return null;
1578 }
1579
1580 private final ProcessRecord getProcessRecordLocked(
1581 String processName, int uid) {
1582 if (uid == Process.SYSTEM_UID) {
1583 // The system gets to run in any process. If there are multiple
1584 // processes with the same uid, just pick the first (this
1585 // should never happen).
1586 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1587 processName);
1588 return procs != null ? procs.valueAt(0) : null;
1589 }
1590 ProcessRecord proc = mProcessNames.get(processName, uid);
1591 return proc;
1592 }
1593
1594 private boolean isNextTransitionForward() {
1595 int transit = mWindowManager.getPendingAppTransition();
1596 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1597 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1598 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1599 }
1600
1601 private final boolean realStartActivityLocked(HistoryRecord r,
1602 ProcessRecord app, boolean andResume, boolean checkConfig)
1603 throws RemoteException {
1604
1605 r.startFreezingScreenLocked(app, 0);
1606 mWindowManager.setAppVisibility(r, true);
1607
1608 // Have the window manager re-evaluate the orientation of
1609 // the screen based on the new activity order. Note that
1610 // as a result of this, it can call back into the activity
1611 // manager with a new orientation. We don't care about that,
1612 // because the activity is not currently running so we are
1613 // just restarting it anyway.
1614 if (checkConfig) {
1615 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001616 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 r.mayFreezeScreenLocked(app) ? r : null);
1618 updateConfigurationLocked(config, r);
1619 }
1620
1621 r.app = app;
1622
1623 if (localLOGV) Log.v(TAG, "Launching: " + r);
1624
1625 int idx = app.activities.indexOf(r);
1626 if (idx < 0) {
1627 app.activities.add(r);
1628 }
1629 updateLRUListLocked(app, true);
1630
1631 try {
1632 if (app.thread == null) {
1633 throw new RemoteException();
1634 }
1635 List<ResultInfo> results = null;
1636 List<Intent> newIntents = null;
1637 if (andResume) {
1638 results = r.results;
1639 newIntents = r.newIntents;
1640 }
1641 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1642 + " icicle=" + r.icicle
1643 + " with results=" + results + " newIntents=" + newIntents
1644 + " andResume=" + andResume);
1645 if (andResume) {
1646 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1647 System.identityHashCode(r),
1648 r.task.taskId, r.shortComponentName);
1649 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001650 if (r.isHomeActivity) {
1651 mHomeProcess = app;
1652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1654 r.info, r.icicle, results, newIntents, !andResume,
1655 isNextTransitionForward());
1656 // Update usage stats for launched activity
1657 updateUsageStats(r, true);
1658 } catch (RemoteException e) {
1659 if (r.launchFailed) {
1660 // This is the second time we failed -- finish activity
1661 // and give up.
1662 Log.e(TAG, "Second failure launching "
1663 + r.intent.getComponent().flattenToShortString()
1664 + ", giving up", e);
1665 appDiedLocked(app, app.pid, app.thread);
1666 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1667 "2nd-crash");
1668 return false;
1669 }
1670
1671 // This is the first time we failed -- restart process and
1672 // retry.
1673 app.activities.remove(r);
1674 throw e;
1675 }
1676
1677 r.launchFailed = false;
1678 if (updateLRUListLocked(r)) {
1679 Log.w(TAG, "Activity " + r
1680 + " being launched, but already in LRU list");
1681 }
1682
1683 if (andResume) {
1684 // As part of the process of launching, ActivityThread also performs
1685 // a resume.
1686 r.state = ActivityState.RESUMED;
1687 r.icicle = null;
1688 r.haveState = false;
1689 r.stopped = false;
1690 mResumedActivity = r;
1691 r.task.touchActiveTime();
1692 completeResumeLocked(r);
1693 pauseIfSleepingLocked();
1694 } else {
1695 // This activity is not starting in the resumed state... which
1696 // should look like we asked it to pause+stop (but remain visible),
1697 // and it has done so and reported back the current icicle and
1698 // other state.
1699 r.state = ActivityState.STOPPED;
1700 r.stopped = true;
1701 }
1702
1703 return true;
1704 }
1705
1706 private final void startSpecificActivityLocked(HistoryRecord r,
1707 boolean andResume, boolean checkConfig) {
1708 // Is this activity's application already running?
1709 ProcessRecord app = getProcessRecordLocked(r.processName,
1710 r.info.applicationInfo.uid);
1711
1712 if (r.startTime == 0) {
1713 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001714 if (mInitialStartTime == 0) {
1715 mInitialStartTime = r.startTime;
1716 }
1717 } else if (mInitialStartTime == 0) {
1718 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 }
1720
1721 if (app != null && app.thread != null) {
1722 try {
1723 realStartActivityLocked(r, app, andResume, checkConfig);
1724 return;
1725 } catch (RemoteException e) {
1726 Log.w(TAG, "Exception when starting activity "
1727 + r.intent.getComponent().flattenToShortString(), e);
1728 }
1729
1730 // If a dead object exception was thrown -- fall through to
1731 // restart the application.
1732 }
1733
1734 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1735 "activity", r.intent.getComponent());
1736 }
1737
1738 private final ProcessRecord startProcessLocked(String processName,
1739 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1740 String hostingType, ComponentName hostingName) {
1741 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1742 // We don't have to do anything more if:
1743 // (1) There is an existing application record; and
1744 // (2) The caller doesn't think it is dead, OR there is no thread
1745 // object attached to it so we know it couldn't have crashed; and
1746 // (3) There is a pid assigned to it, so it is either starting or
1747 // already running.
1748 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1749 + " app=" + app + " knownToBeDead=" + knownToBeDead
1750 + " thread=" + (app != null ? app.thread : null)
1751 + " pid=" + (app != null ? app.pid : -1));
1752 if (app != null &&
1753 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1754 return app;
1755 }
1756
1757 String hostingNameStr = hostingName != null
1758 ? hostingName.flattenToShortString() : null;
1759
1760 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1761 // If we are in the background, then check to see if this process
1762 // is bad. If so, we will just silently fail.
1763 if (mBadProcesses.get(info.processName, info.uid) != null) {
1764 return null;
1765 }
1766 } else {
1767 // When the user is explicitly starting a process, then clear its
1768 // crash count so that we won't make it bad until they see at
1769 // least one crash dialog again, and make the process good again
1770 // if it had been bad.
1771 mProcessCrashTimes.remove(info.processName, info.uid);
1772 if (mBadProcesses.get(info.processName, info.uid) != null) {
1773 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1774 info.processName);
1775 mBadProcesses.remove(info.processName, info.uid);
1776 if (app != null) {
1777 app.bad = false;
1778 }
1779 }
1780 }
1781
1782 if (app == null) {
1783 app = newProcessRecordLocked(null, info, processName);
1784 mProcessNames.put(processName, info.uid, app);
1785 } else {
1786 // If this is a new package in the process, add the package to the list
1787 app.addPackage(info.packageName);
1788 }
1789
1790 // If the system is not ready yet, then hold off on starting this
1791 // process until it is.
1792 if (!mSystemReady
1793 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1794 if (!mProcessesOnHold.contains(app)) {
1795 mProcessesOnHold.add(app);
1796 }
1797 return app;
1798 }
1799
1800 startProcessLocked(app, hostingType, hostingNameStr);
1801 return (app.pid != 0) ? app : null;
1802 }
1803
1804 private final void startProcessLocked(ProcessRecord app,
1805 String hostingType, String hostingNameStr) {
1806 if (app.pid > 0 && app.pid != MY_PID) {
1807 synchronized (mPidsSelfLocked) {
1808 mPidsSelfLocked.remove(app.pid);
1809 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1810 }
1811 app.pid = 0;
1812 }
1813
1814 mProcessesOnHold.remove(app);
1815
1816 updateCpuStats();
1817
1818 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1819 mProcDeaths[0] = 0;
1820
1821 try {
1822 int uid = app.info.uid;
1823 int[] gids = null;
1824 try {
1825 gids = mContext.getPackageManager().getPackageGids(
1826 app.info.packageName);
1827 } catch (PackageManager.NameNotFoundException e) {
1828 Log.w(TAG, "Unable to retrieve gids", e);
1829 }
1830 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1831 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1832 && mTopComponent != null
1833 && app.processName.equals(mTopComponent.getPackageName())) {
1834 uid = 0;
1835 }
1836 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1837 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1838 uid = 0;
1839 }
1840 }
1841 int debugFlags = 0;
1842 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1843 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1844 }
1845 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1846 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1847 }
1848 if ("1".equals(SystemProperties.get("debug.assert"))) {
1849 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1850 }
1851 int pid = Process.start("android.app.ActivityThread",
1852 mSimpleProcessManagement ? app.processName : null, uid, uid,
1853 gids, debugFlags, null);
1854 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1855 synchronized (bs) {
1856 if (bs.isOnBattery()) {
1857 app.batteryStats.incStartsLocked();
1858 }
1859 }
1860
1861 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1862 app.processName, hostingType,
1863 hostingNameStr != null ? hostingNameStr : "");
1864
1865 if (app.persistent) {
1866 Watchdog.getInstance().processStarted(app, app.processName, pid);
1867 }
1868
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001869 StringBuilder buf = mStringBuilder;
1870 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 buf.append("Start proc ");
1872 buf.append(app.processName);
1873 buf.append(" for ");
1874 buf.append(hostingType);
1875 if (hostingNameStr != null) {
1876 buf.append(" ");
1877 buf.append(hostingNameStr);
1878 }
1879 buf.append(": pid=");
1880 buf.append(pid);
1881 buf.append(" uid=");
1882 buf.append(uid);
1883 buf.append(" gids={");
1884 if (gids != null) {
1885 for (int gi=0; gi<gids.length; gi++) {
1886 if (gi != 0) buf.append(", ");
1887 buf.append(gids[gi]);
1888
1889 }
1890 }
1891 buf.append("}");
1892 Log.i(TAG, buf.toString());
1893 if (pid == 0 || pid == MY_PID) {
1894 // Processes are being emulated with threads.
1895 app.pid = MY_PID;
1896 app.removed = false;
1897 mStartingProcesses.add(app);
1898 } else if (pid > 0) {
1899 app.pid = pid;
1900 app.removed = false;
1901 synchronized (mPidsSelfLocked) {
1902 this.mPidsSelfLocked.put(pid, app);
1903 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1904 msg.obj = app;
1905 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1906 }
1907 } else {
1908 app.pid = 0;
1909 RuntimeException e = new RuntimeException(
1910 "Failure starting process " + app.processName
1911 + ": returned pid=" + pid);
1912 Log.e(TAG, e.getMessage(), e);
1913 }
1914 } catch (RuntimeException e) {
1915 // XXX do better error recovery.
1916 app.pid = 0;
1917 Log.e(TAG, "Failure starting process " + app.processName, e);
1918 }
1919 }
1920
1921 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1922 if (mPausingActivity != null) {
1923 RuntimeException e = new RuntimeException();
1924 Log.e(TAG, "Trying to pause when pause is already pending for "
1925 + mPausingActivity, e);
1926 }
1927 HistoryRecord prev = mResumedActivity;
1928 if (prev == null) {
1929 RuntimeException e = new RuntimeException();
1930 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1931 resumeTopActivityLocked(null);
1932 return;
1933 }
1934 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
1935 mResumedActivity = null;
1936 mPausingActivity = prev;
1937 mLastPausedActivity = prev;
1938 prev.state = ActivityState.PAUSING;
1939 prev.task.touchActiveTime();
1940
1941 updateCpuStats();
1942
1943 if (prev.app != null && prev.app.thread != null) {
1944 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
1945 try {
1946 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
1947 System.identityHashCode(prev),
1948 prev.shortComponentName);
1949 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
1950 prev.configChangeFlags);
1951 updateUsageStats(prev, false);
1952 } catch (Exception e) {
1953 // Ignore exception, if process died other code will cleanup.
1954 Log.w(TAG, "Exception thrown during pause", e);
1955 mPausingActivity = null;
1956 mLastPausedActivity = null;
1957 }
1958 } else {
1959 mPausingActivity = null;
1960 mLastPausedActivity = null;
1961 }
1962
1963 // If we are not going to sleep, we want to ensure the device is
1964 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07001965 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 mLaunchingActivity.acquire();
1967 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
1968 // To be safe, don't allow the wake lock to be held for too long.
1969 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1970 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
1971 }
1972 }
1973
1974
1975 if (mPausingActivity != null) {
1976 // Have the window manager pause its key dispatching until the new
1977 // activity has started. If we're pausing the activity just because
1978 // the screen is being turned off and the UI is sleeping, don't interrupt
1979 // key dispatch; the same activity will pick it up again on wakeup.
1980 if (!uiSleeping) {
1981 prev.pauseKeyDispatchingLocked();
1982 } else {
1983 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
1984 }
1985
1986 // Schedule a pause timeout in case the app doesn't respond.
1987 // We don't give it much time because this directly impacts the
1988 // responsiveness seen by the user.
1989 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
1990 msg.obj = prev;
1991 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
1992 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
1993 } else {
1994 // This activity failed to schedule the
1995 // pause, so just treat it as being paused now.
1996 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
1997 resumeTopActivityLocked(null);
1998 }
1999 }
2000
2001 private final void completePauseLocked() {
2002 HistoryRecord prev = mPausingActivity;
2003 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2004
2005 if (prev != null) {
2006 if (prev.finishing) {
2007 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2008 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2009 } else if (prev.app != null) {
2010 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2011 if (prev.waitingVisible) {
2012 prev.waitingVisible = false;
2013 mWaitingVisibleActivities.remove(prev);
2014 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2015 TAG, "Complete pause, no longer waiting: " + prev);
2016 }
2017 if (prev.configDestroy) {
2018 // The previous is being paused because the configuration
2019 // is changing, which means it is actually stopping...
2020 // To juggle the fact that we are also starting a new
2021 // instance right now, we need to first completely stop
2022 // the current instance before starting the new one.
2023 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2024 destroyActivityLocked(prev, true);
2025 } else {
2026 mStoppingActivities.add(prev);
2027 if (mStoppingActivities.size() > 3) {
2028 // If we already have a few activities waiting to stop,
2029 // then give up on things going idle and start clearing
2030 // them out.
2031 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2032 Message msg = Message.obtain();
2033 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2034 mHandler.sendMessage(msg);
2035 }
2036 }
2037 } else {
2038 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2039 prev = null;
2040 }
2041 mPausingActivity = null;
2042 }
2043
Dianne Hackborn55280a92009-05-07 15:53:46 -07002044 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 resumeTopActivityLocked(prev);
2046 } else {
2047 if (mGoingToSleep.isHeld()) {
2048 mGoingToSleep.release();
2049 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002050 if (mShuttingDown) {
2051 notifyAll();
2052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 }
2054
2055 if (prev != null) {
2056 prev.resumeKeyDispatchingLocked();
2057 }
2058 }
2059
2060 /**
2061 * Once we know that we have asked an application to put an activity in
2062 * the resumed state (either by launching it or explicitly telling it),
2063 * this function updates the rest of our state to match that fact.
2064 */
2065 private final void completeResumeLocked(HistoryRecord next) {
2066 next.idle = false;
2067 next.results = null;
2068 next.newIntents = null;
2069
2070 // schedule an idle timeout in case the app doesn't do it for us.
2071 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2072 msg.obj = next;
2073 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2074
2075 if (false) {
2076 // The activity was never told to pause, so just keep
2077 // things going as-is. To maintain our own state,
2078 // we need to emulate it coming back and saying it is
2079 // idle.
2080 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2081 msg.obj = next;
2082 mHandler.sendMessage(msg);
2083 }
2084
2085 next.thumbnail = null;
2086 setFocusedActivityLocked(next);
2087 next.resumeKeyDispatchingLocked();
2088 ensureActivitiesVisibleLocked(null, 0);
2089 mWindowManager.executeAppTransition();
2090 }
2091
2092 /**
2093 * Make sure that all activities that need to be visible (that is, they
2094 * currently can be seen by the user) actually are.
2095 */
2096 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2097 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2098 if (DEBUG_VISBILITY) Log.v(
2099 TAG, "ensureActivitiesVisible behind " + top
2100 + " configChanges=0x" + Integer.toHexString(configChanges));
2101
2102 // If the top activity is not fullscreen, then we need to
2103 // make sure any activities under it are now visible.
2104 final int count = mHistory.size();
2105 int i = count-1;
2106 while (mHistory.get(i) != top) {
2107 i--;
2108 }
2109 HistoryRecord r;
2110 boolean behindFullscreen = false;
2111 for (; i>=0; i--) {
2112 r = (HistoryRecord)mHistory.get(i);
2113 if (DEBUG_VISBILITY) Log.v(
2114 TAG, "Make visible? " + r + " finishing=" + r.finishing
2115 + " state=" + r.state);
2116 if (r.finishing) {
2117 continue;
2118 }
2119
2120 final boolean doThisProcess = onlyThisProcess == null
2121 || onlyThisProcess.equals(r.processName);
2122
2123 // First: if this is not the current activity being started, make
2124 // sure it matches the current configuration.
2125 if (r != starting && doThisProcess) {
2126 ensureActivityConfigurationLocked(r, 0);
2127 }
2128
2129 if (r.app == null || r.app.thread == null) {
2130 if (onlyThisProcess == null
2131 || onlyThisProcess.equals(r.processName)) {
2132 // This activity needs to be visible, but isn't even
2133 // running... get it started, but don't resume it
2134 // at this point.
2135 if (DEBUG_VISBILITY) Log.v(
2136 TAG, "Start and freeze screen for " + r);
2137 if (r != starting) {
2138 r.startFreezingScreenLocked(r.app, configChanges);
2139 }
2140 if (!r.visible) {
2141 if (DEBUG_VISBILITY) Log.v(
2142 TAG, "Starting and making visible: " + r);
2143 mWindowManager.setAppVisibility(r, true);
2144 }
2145 if (r != starting) {
2146 startSpecificActivityLocked(r, false, false);
2147 }
2148 }
2149
2150 } else if (r.visible) {
2151 // If this activity is already visible, then there is nothing
2152 // else to do here.
2153 if (DEBUG_VISBILITY) Log.v(
2154 TAG, "Skipping: already visible at " + r);
2155 r.stopFreezingScreenLocked(false);
2156
2157 } else if (onlyThisProcess == null) {
2158 // This activity is not currently visible, but is running.
2159 // Tell it to become visible.
2160 r.visible = true;
2161 if (r.state != ActivityState.RESUMED && r != starting) {
2162 // If this activity is paused, tell it
2163 // to now show its window.
2164 if (DEBUG_VISBILITY) Log.v(
2165 TAG, "Making visible and scheduling visibility: " + r);
2166 try {
2167 mWindowManager.setAppVisibility(r, true);
2168 r.app.thread.scheduleWindowVisibility(r, true);
2169 r.stopFreezingScreenLocked(false);
2170 } catch (Exception e) {
2171 // Just skip on any failure; we'll make it
2172 // visible when it next restarts.
2173 Log.w(TAG, "Exception thrown making visibile: "
2174 + r.intent.getComponent(), e);
2175 }
2176 }
2177 }
2178
2179 // Aggregate current change flags.
2180 configChanges |= r.configChangeFlags;
2181
2182 if (r.fullscreen) {
2183 // At this point, nothing else needs to be shown
2184 if (DEBUG_VISBILITY) Log.v(
2185 TAG, "Stopping: fullscreen at " + r);
2186 behindFullscreen = true;
2187 i--;
2188 break;
2189 }
2190 }
2191
2192 // Now for any activities that aren't visible to the user, make
2193 // sure they no longer are keeping the screen frozen.
2194 while (i >= 0) {
2195 r = (HistoryRecord)mHistory.get(i);
2196 if (DEBUG_VISBILITY) Log.v(
2197 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2198 + " state=" + r.state
2199 + " behindFullscreen=" + behindFullscreen);
2200 if (!r.finishing) {
2201 if (behindFullscreen) {
2202 if (r.visible) {
2203 if (DEBUG_VISBILITY) Log.v(
2204 TAG, "Making invisible: " + r);
2205 r.visible = false;
2206 try {
2207 mWindowManager.setAppVisibility(r, false);
2208 if ((r.state == ActivityState.STOPPING
2209 || r.state == ActivityState.STOPPED)
2210 && r.app != null && r.app.thread != null) {
2211 if (DEBUG_VISBILITY) Log.v(
2212 TAG, "Scheduling invisibility: " + r);
2213 r.app.thread.scheduleWindowVisibility(r, false);
2214 }
2215 } catch (Exception e) {
2216 // Just skip on any failure; we'll make it
2217 // visible when it next restarts.
2218 Log.w(TAG, "Exception thrown making hidden: "
2219 + r.intent.getComponent(), e);
2220 }
2221 } else {
2222 if (DEBUG_VISBILITY) Log.v(
2223 TAG, "Already invisible: " + r);
2224 }
2225 } else if (r.fullscreen) {
2226 if (DEBUG_VISBILITY) Log.v(
2227 TAG, "Now behindFullscreen: " + r);
2228 behindFullscreen = true;
2229 }
2230 }
2231 i--;
2232 }
2233 }
2234
2235 /**
2236 * Version of ensureActivitiesVisible that can easily be called anywhere.
2237 */
2238 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2239 int configChanges) {
2240 HistoryRecord r = topRunningActivityLocked(null);
2241 if (r != null) {
2242 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2243 }
2244 }
2245
2246 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2247 if (resumed) {
2248 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2249 } else {
2250 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2251 }
2252 }
2253
2254 /**
2255 * Ensure that the top activity in the stack is resumed.
2256 *
2257 * @param prev The previously resumed activity, for when in the process
2258 * of pausing; can be null to call from elsewhere.
2259 *
2260 * @return Returns true if something is being resumed, or false if
2261 * nothing happened.
2262 */
2263 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2264 // Find the first activity that is not finishing.
2265 HistoryRecord next = topRunningActivityLocked(null);
2266
2267 // Remember how we'll process this pause/resume situation, and ensure
2268 // that the state is reset however we wind up proceeding.
2269 final boolean userLeaving = mUserLeaving;
2270 mUserLeaving = false;
2271
2272 if (next == null) {
2273 // There are no more activities! Let's just start up the
2274 // Launcher...
2275 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2276 && mTopAction == null) {
2277 // We are running in factory test mode, but unable to find
2278 // the factory test app, so just sit around displaying the
2279 // error message and don't try to start anything.
2280 return false;
2281 }
2282 Intent intent = new Intent(
2283 mTopAction,
2284 mTopData != null ? Uri.parse(mTopData) : null);
2285 intent.setComponent(mTopComponent);
2286 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2287 intent.addCategory(Intent.CATEGORY_HOME);
2288 }
2289 ActivityInfo aInfo =
2290 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002291 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292 if (aInfo != null) {
2293 intent.setComponent(new ComponentName(
2294 aInfo.applicationInfo.packageName, aInfo.name));
2295 // Don't do this if the home app is currently being
2296 // instrumented.
2297 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2298 aInfo.applicationInfo.uid);
2299 if (app == null || app.instrumentationClass == null) {
2300 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2301 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002302 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 }
2304 }
2305 return true;
2306 }
2307
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002308 next.delayedResume = false;
2309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 // If the top activity is the resumed one, nothing to do.
2311 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2312 // Make sure we have executed any pending transitions, since there
2313 // should be nothing left to do at this point.
2314 mWindowManager.executeAppTransition();
2315 return false;
2316 }
2317
2318 // If we are sleeping, and there is no resumed activity, and the top
2319 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002320 if ((mSleeping || mShuttingDown)
2321 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 // Make sure we have executed any pending transitions, since there
2323 // should be nothing left to do at this point.
2324 mWindowManager.executeAppTransition();
2325 return false;
2326 }
2327
2328 // The activity may be waiting for stop, but that is no longer
2329 // appropriate for it.
2330 mStoppingActivities.remove(next);
2331 mWaitingVisibleActivities.remove(next);
2332
2333 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2334
2335 // If we are currently pausing an activity, then don't do anything
2336 // until that is done.
2337 if (mPausingActivity != null) {
2338 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2339 return false;
2340 }
2341
2342 // We need to start pausing the current activity so the top one
2343 // can be resumed...
2344 if (mResumedActivity != null) {
2345 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2346 startPausingLocked(userLeaving, false);
2347 return true;
2348 }
2349
2350 if (prev != null && prev != next) {
2351 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2352 prev.waitingVisible = true;
2353 mWaitingVisibleActivities.add(prev);
2354 if (DEBUG_SWITCH) Log.v(
2355 TAG, "Resuming top, waiting visible to hide: " + prev);
2356 } else {
2357 // The next activity is already visible, so hide the previous
2358 // activity's windows right now so we can show the new one ASAP.
2359 // We only do this if the previous is finishing, which should mean
2360 // it is on top of the one being resumed so hiding it quickly
2361 // is good. Otherwise, we want to do the normal route of allowing
2362 // the resumed activity to be shown so we can decide if the
2363 // previous should actually be hidden depending on whether the
2364 // new one is found to be full-screen or not.
2365 if (prev.finishing) {
2366 mWindowManager.setAppVisibility(prev, false);
2367 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2368 + prev + ", waitingVisible="
2369 + (prev != null ? prev.waitingVisible : null)
2370 + ", nowVisible=" + next.nowVisible);
2371 } else {
2372 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2373 + prev + ", waitingVisible="
2374 + (prev != null ? prev.waitingVisible : null)
2375 + ", nowVisible=" + next.nowVisible);
2376 }
2377 }
2378 }
2379
2380 // We are starting up the next activity, so tell the window manager
2381 // that the previous one will be hidden soon. This way it can know
2382 // to ignore it when computing the desired screen orientation.
2383 if (prev != null) {
2384 if (prev.finishing) {
2385 if (DEBUG_TRANSITION) Log.v(TAG,
2386 "Prepare close transition: prev=" + prev);
2387 mWindowManager.prepareAppTransition(prev.task == next.task
2388 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2389 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2390 mWindowManager.setAppWillBeHidden(prev);
2391 mWindowManager.setAppVisibility(prev, false);
2392 } else {
2393 if (DEBUG_TRANSITION) Log.v(TAG,
2394 "Prepare open transition: prev=" + prev);
2395 mWindowManager.prepareAppTransition(prev.task == next.task
2396 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2397 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2398 }
2399 if (false) {
2400 mWindowManager.setAppWillBeHidden(prev);
2401 mWindowManager.setAppVisibility(prev, false);
2402 }
2403 } else if (mHistory.size() > 1) {
2404 if (DEBUG_TRANSITION) Log.v(TAG,
2405 "Prepare open transition: no previous");
2406 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2407 }
2408
2409 if (next.app != null && next.app.thread != null) {
2410 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2411
2412 // This activity is now becoming visible.
2413 mWindowManager.setAppVisibility(next, true);
2414
2415 HistoryRecord lastResumedActivity = mResumedActivity;
2416 ActivityState lastState = next.state;
2417
2418 updateCpuStats();
2419
2420 next.state = ActivityState.RESUMED;
2421 mResumedActivity = next;
2422 next.task.touchActiveTime();
2423 updateLRUListLocked(next.app, true);
2424 updateLRUListLocked(next);
2425
2426 // Have the window manager re-evaluate the orientation of
2427 // the screen based on the new activity order.
2428 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002429 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 next.mayFreezeScreenLocked(next.app) ? next : null);
2431 if (config != null) {
2432 next.frozenBeforeDestroy = true;
2433 }
2434 if (!updateConfigurationLocked(config, next)) {
2435 // The configuration update wasn't able to keep the existing
2436 // instance of the activity, and instead started a new one.
2437 // We should be all done, but let's just make sure our activity
2438 // is still at the top and schedule another run if something
2439 // weird happened.
2440 HistoryRecord nextNext = topRunningActivityLocked(null);
2441 if (DEBUG_SWITCH) Log.i(TAG,
2442 "Activity config changed during resume: " + next
2443 + ", new next: " + nextNext);
2444 if (nextNext != next) {
2445 // Do over!
2446 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2447 }
2448 mWindowManager.executeAppTransition();
2449 return true;
2450 }
2451
2452 try {
2453 // Deliver all pending results.
2454 ArrayList a = next.results;
2455 if (a != null) {
2456 final int N = a.size();
2457 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002458 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459 TAG, "Delivering results to " + next
2460 + ": " + a);
2461 next.app.thread.scheduleSendResult(next, a);
2462 }
2463 }
2464
2465 if (next.newIntents != null) {
2466 next.app.thread.scheduleNewIntent(next.newIntents, next);
2467 }
2468
2469 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2470 System.identityHashCode(next),
2471 next.task.taskId, next.shortComponentName);
2472 updateUsageStats(next, true);
2473
2474 next.app.thread.scheduleResumeActivity(next,
2475 isNextTransitionForward());
2476 pauseIfSleepingLocked();
2477
2478 } catch (Exception e) {
2479 // Whoops, need to restart this activity!
2480 next.state = lastState;
2481 mResumedActivity = lastResumedActivity;
2482 if (Config.LOGD) Log.d(TAG,
2483 "Restarting because process died: " + next);
2484 if (!next.hasBeenLaunched) {
2485 next.hasBeenLaunched = true;
2486 } else {
2487 if (SHOW_APP_STARTING_ICON) {
2488 mWindowManager.setAppStartingWindow(
2489 next, next.packageName, next.theme,
2490 next.nonLocalizedLabel,
2491 next.labelRes, next.icon, null, true);
2492 }
2493 }
2494 startSpecificActivityLocked(next, true, false);
2495 return true;
2496 }
2497
2498 // From this point on, if something goes wrong there is no way
2499 // to recover the activity.
2500 try {
2501 next.visible = true;
2502 completeResumeLocked(next);
2503 } catch (Exception e) {
2504 // If any exception gets thrown, toss away this
2505 // activity and try the next one.
2506 Log.w(TAG, "Exception thrown during resume of " + next, e);
2507 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2508 "resume-exception");
2509 return true;
2510 }
2511
2512 // Didn't need to use the icicle, and it is now out of date.
2513 next.icicle = null;
2514 next.haveState = false;
2515 next.stopped = false;
2516
2517 } else {
2518 // Whoops, need to restart this activity!
2519 if (!next.hasBeenLaunched) {
2520 next.hasBeenLaunched = true;
2521 } else {
2522 if (SHOW_APP_STARTING_ICON) {
2523 mWindowManager.setAppStartingWindow(
2524 next, next.packageName, next.theme,
2525 next.nonLocalizedLabel,
2526 next.labelRes, next.icon, null, true);
2527 }
2528 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2529 }
2530 startSpecificActivityLocked(next, true, true);
2531 }
2532
2533 return true;
2534 }
2535
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002536 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2537 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002538 final int NH = mHistory.size();
2539
2540 int addPos = -1;
2541
2542 if (!newTask) {
2543 // If starting in an existing task, find where that is...
2544 HistoryRecord next = null;
2545 boolean startIt = true;
2546 for (int i = NH-1; i >= 0; i--) {
2547 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2548 if (p.finishing) {
2549 continue;
2550 }
2551 if (p.task == r.task) {
2552 // Here it is! Now, if this is not yet visible to the
2553 // user, then just add it without starting; it will
2554 // get started when the user navigates back to it.
2555 addPos = i+1;
2556 if (!startIt) {
2557 mHistory.add(addPos, r);
2558 r.inHistory = true;
2559 r.task.numActivities++;
2560 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2561 r.info.screenOrientation, r.fullscreen);
2562 if (VALIDATE_TOKENS) {
2563 mWindowManager.validateAppTokens(mHistory);
2564 }
2565 return;
2566 }
2567 break;
2568 }
2569 if (p.fullscreen) {
2570 startIt = false;
2571 }
2572 next = p;
2573 }
2574 }
2575
2576 // Place a new activity at top of stack, so it is next to interact
2577 // with the user.
2578 if (addPos < 0) {
2579 addPos = mHistory.size();
2580 }
2581
2582 // If we are not placing the new activity frontmost, we do not want
2583 // to deliver the onUserLeaving callback to the actual frontmost
2584 // activity
2585 if (addPos < NH) {
2586 mUserLeaving = false;
2587 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2588 }
2589
2590 // Slot the activity into the history stack and proceed
2591 mHistory.add(addPos, r);
2592 r.inHistory = true;
2593 r.frontOfTask = newTask;
2594 r.task.numActivities++;
2595 if (NH > 0) {
2596 // We want to show the starting preview window if we are
2597 // switching to a new task, or the next activity's process is
2598 // not currently running.
2599 boolean showStartingIcon = newTask;
2600 ProcessRecord proc = r.app;
2601 if (proc == null) {
2602 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2603 }
2604 if (proc == null || proc.thread == null) {
2605 showStartingIcon = true;
2606 }
2607 if (DEBUG_TRANSITION) Log.v(TAG,
2608 "Prepare open transition: starting " + r);
2609 mWindowManager.prepareAppTransition(newTask
2610 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2611 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2612 mWindowManager.addAppToken(
2613 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2614 boolean doShow = true;
2615 if (newTask) {
2616 // Even though this activity is starting fresh, we still need
2617 // to reset it to make sure we apply affinities to move any
2618 // existing activities from other tasks in to it.
2619 // If the caller has requested that the target task be
2620 // reset, then do so.
2621 if ((r.intent.getFlags()
2622 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2623 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002624 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002625 }
2626 }
2627 if (SHOW_APP_STARTING_ICON && doShow) {
2628 // Figure out if we are transitioning from another activity that is
2629 // "has the same starting icon" as the next one. This allows the
2630 // window manager to keep the previous window it had previously
2631 // created, if it still had one.
2632 HistoryRecord prev = mResumedActivity;
2633 if (prev != null) {
2634 // We don't want to reuse the previous starting preview if:
2635 // (1) The current activity is in a different task.
2636 if (prev.task != r.task) prev = null;
2637 // (2) The current activity is already displayed.
2638 else if (prev.nowVisible) prev = null;
2639 }
2640 mWindowManager.setAppStartingWindow(
2641 r, r.packageName, r.theme, r.nonLocalizedLabel,
2642 r.labelRes, r.icon, prev, showStartingIcon);
2643 }
2644 } else {
2645 // If this is the first activity, don't do any fancy animations,
2646 // because there is nothing for it to animate on top of.
2647 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2648 r.info.screenOrientation, r.fullscreen);
2649 }
2650 if (VALIDATE_TOKENS) {
2651 mWindowManager.validateAppTokens(mHistory);
2652 }
2653
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002654 if (doResume) {
2655 resumeTopActivityLocked(null);
2656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 }
2658
2659 /**
2660 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002661 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2662 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 * an instance of that activity in the stack and, if found, finish all
2664 * activities on top of it and return the instance.
2665 *
2666 * @param newR Description of the new activity being started.
2667 * @return Returns the old activity that should be continue to be used,
2668 * or null if none was found.
2669 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002670 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 HistoryRecord newR, boolean doClear) {
2672 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002673
2674 // First find the requested task.
2675 while (i > 0) {
2676 i--;
2677 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2678 if (r.task.taskId == taskId) {
2679 i++;
2680 break;
2681 }
2682 }
2683
2684 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 while (i > 0) {
2686 i--;
2687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2688 if (r.finishing) {
2689 continue;
2690 }
2691 if (r.task.taskId != taskId) {
2692 return null;
2693 }
2694 if (r.realActivity.equals(newR.realActivity)) {
2695 // Here it is! Now finish everything in front...
2696 HistoryRecord ret = r;
2697 if (doClear) {
2698 while (i < (mHistory.size()-1)) {
2699 i++;
2700 r = (HistoryRecord)mHistory.get(i);
2701 if (r.finishing) {
2702 continue;
2703 }
2704 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2705 null, "clear")) {
2706 i--;
2707 }
2708 }
2709 }
2710
2711 // Finally, if this is a normal launch mode (that is, not
2712 // expecting onNewIntent()), then we will finish the current
2713 // instance of the activity so a new fresh one can be started.
2714 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2715 if (!ret.finishing) {
2716 int index = indexOfTokenLocked(ret, false);
2717 if (index >= 0) {
2718 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2719 null, "clear");
2720 }
2721 return null;
2722 }
2723 }
2724
2725 return ret;
2726 }
2727 }
2728
2729 return null;
2730 }
2731
2732 /**
2733 * Find the activity in the history stack within the given task. Returns
2734 * the index within the history at which it's found, or < 0 if not found.
2735 */
2736 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2737 int i = mHistory.size();
2738 while (i > 0) {
2739 i--;
2740 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2741 if (candidate.task.taskId != task) {
2742 break;
2743 }
2744 if (candidate.realActivity.equals(r.realActivity)) {
2745 return i;
2746 }
2747 }
2748
2749 return -1;
2750 }
2751
2752 /**
2753 * Reorder the history stack so that the activity at the given index is
2754 * brought to the front.
2755 */
2756 private final HistoryRecord moveActivityToFrontLocked(int where) {
2757 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2758 int top = mHistory.size();
2759 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2760 mHistory.add(top, newTop);
2761 oldTop.frontOfTask = false;
2762 newTop.frontOfTask = true;
2763 return newTop;
2764 }
2765
2766 /**
2767 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2768 * method will be called at the proper time.
2769 */
2770 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2771 boolean sent = false;
2772 if (r.state == ActivityState.RESUMED
2773 && r.app != null && r.app.thread != null) {
2774 try {
2775 ArrayList<Intent> ar = new ArrayList<Intent>();
2776 ar.add(new Intent(intent));
2777 r.app.thread.scheduleNewIntent(ar, r);
2778 sent = true;
2779 } catch (Exception e) {
2780 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2781 }
2782 }
2783 if (!sent) {
2784 r.addNewIntentLocked(new Intent(intent));
2785 }
2786 }
2787
2788 private final void logStartActivity(int tag, HistoryRecord r,
2789 TaskRecord task) {
2790 EventLog.writeEvent(tag,
2791 System.identityHashCode(r), task.taskId,
2792 r.shortComponentName, r.intent.getAction(),
2793 r.intent.getType(), r.intent.getDataString(),
2794 r.intent.getFlags());
2795 }
2796
2797 private final int startActivityLocked(IApplicationThread caller,
2798 Intent intent, String resolvedType,
2799 Uri[] grantedUriPermissions,
2800 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2801 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002802 int callingPid, int callingUid, boolean onlyIfNeeded,
2803 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002804 Log.i(TAG, "Starting activity: " + intent);
2805
2806 HistoryRecord sourceRecord = null;
2807 HistoryRecord resultRecord = null;
2808 if (resultTo != null) {
2809 int index = indexOfTokenLocked(resultTo, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002810 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002811 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2812 if (index >= 0) {
2813 sourceRecord = (HistoryRecord)mHistory.get(index);
2814 if (requestCode >= 0 && !sourceRecord.finishing) {
2815 resultRecord = sourceRecord;
2816 }
2817 }
2818 }
2819
2820 int launchFlags = intent.getFlags();
2821
2822 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2823 && sourceRecord != null) {
2824 // Transfer the result target from the source activity to the new
2825 // one being started, including any failures.
2826 if (requestCode >= 0) {
2827 return START_FORWARD_AND_REQUEST_CONFLICT;
2828 }
2829 resultRecord = sourceRecord.resultTo;
2830 resultWho = sourceRecord.resultWho;
2831 requestCode = sourceRecord.requestCode;
2832 sourceRecord.resultTo = null;
2833 if (resultRecord != null) {
2834 resultRecord.removeResultsLocked(
2835 sourceRecord, resultWho, requestCode);
2836 }
2837 }
2838
2839 int err = START_SUCCESS;
2840
2841 if (intent.getComponent() == null) {
2842 // We couldn't find a class that can handle the given Intent.
2843 // That's the end of that!
2844 err = START_INTENT_NOT_RESOLVED;
2845 }
2846
2847 if (err == START_SUCCESS && aInfo == null) {
2848 // We couldn't find the specific class specified in the Intent.
2849 // Also the end of the line.
2850 err = START_CLASS_NOT_FOUND;
2851 }
2852
2853 ProcessRecord callerApp = null;
2854 if (err == START_SUCCESS && caller != null) {
2855 callerApp = getRecordForAppLocked(caller);
2856 if (callerApp != null) {
2857 callingPid = callerApp.pid;
2858 callingUid = callerApp.info.uid;
2859 } else {
2860 Log.w(TAG, "Unable to find app for caller " + caller
2861 + " (pid=" + callingPid + ") when starting: "
2862 + intent.toString());
2863 err = START_PERMISSION_DENIED;
2864 }
2865 }
2866
2867 if (err != START_SUCCESS) {
2868 if (resultRecord != null) {
2869 sendActivityResultLocked(-1,
2870 resultRecord, resultWho, requestCode,
2871 Activity.RESULT_CANCELED, null);
2872 }
2873 return err;
2874 }
2875
2876 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2877 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2878 if (perm != PackageManager.PERMISSION_GRANTED) {
2879 if (resultRecord != null) {
2880 sendActivityResultLocked(-1,
2881 resultRecord, resultWho, requestCode,
2882 Activity.RESULT_CANCELED, null);
2883 }
2884 String msg = "Permission Denial: starting " + intent.toString()
2885 + " from " + callerApp + " (pid=" + callingPid
2886 + ", uid=" + callingUid + ")"
2887 + " requires " + aInfo.permission;
2888 Log.w(TAG, msg);
2889 throw new SecurityException(msg);
2890 }
2891
2892 if (mWatcher != null) {
2893 boolean abort = false;
2894 try {
2895 // The Intent we give to the watcher has the extra data
2896 // stripped off, since it can contain private information.
2897 Intent watchIntent = intent.cloneFilter();
2898 abort = !mWatcher.activityStarting(watchIntent,
2899 aInfo.applicationInfo.packageName);
2900 } catch (RemoteException e) {
2901 mWatcher = null;
2902 }
2903
2904 if (abort) {
2905 if (resultRecord != null) {
2906 sendActivityResultLocked(-1,
2907 resultRecord, resultWho, requestCode,
2908 Activity.RESULT_CANCELED, null);
2909 }
2910 // We pretend to the caller that it was really started, but
2911 // they will just get a cancel result.
2912 return START_SUCCESS;
2913 }
2914 }
2915
2916 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
2917 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002918 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002920 if (mResumedActivity == null
2921 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2922 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2923 PendingActivityLaunch pal = new PendingActivityLaunch();
2924 pal.r = r;
2925 pal.sourceRecord = sourceRecord;
2926 pal.grantedUriPermissions = grantedUriPermissions;
2927 pal.grantedMode = grantedMode;
2928 pal.onlyIfNeeded = onlyIfNeeded;
2929 mPendingActivityLaunches.add(pal);
2930 return START_SWITCHES_CANCELED;
2931 }
2932 }
2933
2934 if (mDidAppSwitch) {
2935 // This is the second allowed switch since we stopped switches,
2936 // so now just generally allow switches. Use case: user presses
2937 // home (switches disabled, switch to home, mDidAppSwitch now true);
2938 // user taps a home icon (coming from home so allowed, we hit here
2939 // and now allow anyone to switch again).
2940 mAppSwitchesAllowedTime = 0;
2941 } else {
2942 mDidAppSwitch = true;
2943 }
2944
2945 doPendingActivityLaunchesLocked(false);
2946
2947 return startActivityUncheckedLocked(r, sourceRecord,
2948 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2949 }
2950
2951 private final void doPendingActivityLaunchesLocked(boolean doResume) {
2952 final int N = mPendingActivityLaunches.size();
2953 if (N <= 0) {
2954 return;
2955 }
2956 for (int i=0; i<N; i++) {
2957 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
2958 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
2959 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
2960 doResume && i == (N-1));
2961 }
2962 mPendingActivityLaunches.clear();
2963 }
2964
2965 private final int startActivityUncheckedLocked(HistoryRecord r,
2966 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
2967 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2968 final Intent intent = r.intent;
2969 final int callingUid = r.launchedFromUid;
2970
2971 int launchFlags = intent.getFlags();
2972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973 // We'll invoke onUserLeaving before onPause only if the launching
2974 // activity did not explicitly state that this is an automated launch.
2975 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2976 if (DEBUG_USER_LEAVING) Log.v(TAG,
2977 "startActivity() => mUserLeaving=" + mUserLeaving);
2978
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002979 // If the caller has asked not to resume at this point, we make note
2980 // of this in the record so that we can skip it when trying to find
2981 // the top running activity.
2982 if (!doResume) {
2983 r.delayedResume = true;
2984 }
2985
2986 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2987 != 0 ? r : null;
2988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002989 // If the onlyIfNeeded flag is set, then we can do this if the activity
2990 // being launched is the same as the one making the call... or, as
2991 // a special case, if we do not know the caller then we count the
2992 // current top activity as the caller.
2993 if (onlyIfNeeded) {
2994 HistoryRecord checkedCaller = sourceRecord;
2995 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002996 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997 }
2998 if (!checkedCaller.realActivity.equals(r.realActivity)) {
2999 // Caller is not the same as launcher, so always needed.
3000 onlyIfNeeded = false;
3001 }
3002 }
3003
3004 if (grantedUriPermissions != null && callingUid > 0) {
3005 for (int i=0; i<grantedUriPermissions.length; i++) {
3006 grantUriPermissionLocked(callingUid, r.packageName,
3007 grantedUriPermissions[i], grantedMode, r);
3008 }
3009 }
3010
3011 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3012 intent, r);
3013
3014 if (sourceRecord == null) {
3015 // This activity is not being started from another... in this
3016 // case we -always- start a new task.
3017 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3018 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3019 + intent);
3020 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3021 }
3022 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3023 // The original activity who is starting us is running as a single
3024 // instance... this new activity it is starting must go on its
3025 // own task.
3026 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3027 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3028 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3029 // The activity being started is a single instance... it always
3030 // gets launched into its own task.
3031 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3032 }
3033
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003034 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035 // For whatever reason this activity is being launched into a new
3036 // task... yet the caller has requested a result back. Well, that
3037 // is pretty messed up, so instead immediately send back a cancel
3038 // and let the new task continue launched as normal without a
3039 // dependency on its originator.
3040 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3041 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003042 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 Activity.RESULT_CANCELED, null);
3044 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003045 }
3046
3047 boolean addingToTask = false;
3048 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3049 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3050 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3051 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3052 // If bring to front is requested, and no result is requested, and
3053 // we can find a task that was started with this same
3054 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003055 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003056 // See if there is a task to bring to the front. If this is
3057 // a SINGLE_INSTANCE activity, there can be one and only one
3058 // instance of it in the history, and it is always in its own
3059 // unique task, so we do a special search.
3060 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3061 ? findTaskLocked(intent, r.info)
3062 : findActivityLocked(intent, r.info);
3063 if (taskTop != null) {
3064 if (taskTop.task.intent == null) {
3065 // This task was started because of movement of
3066 // the activity based on affinity... now that we
3067 // are actually launching it, we can assign the
3068 // base intent.
3069 taskTop.task.setIntent(intent, r.info);
3070 }
3071 // If the target task is not in the front, then we need
3072 // to bring it to the front... except... well, with
3073 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3074 // to have the same behavior as if a new instance was
3075 // being started, which means not bringing it to the front
3076 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003077 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003078 if (curTop.task != taskTop.task) {
3079 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3080 boolean callerAtFront = sourceRecord == null
3081 || curTop.task == sourceRecord.task;
3082 if (callerAtFront) {
3083 // We really do want to push this one into the
3084 // user's face, right now.
3085 moveTaskToFrontLocked(taskTop.task);
3086 }
3087 }
3088 // If the caller has requested that the target task be
3089 // reset, then do so.
3090 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3091 taskTop = resetTaskIfNeededLocked(taskTop, r);
3092 }
3093 if (onlyIfNeeded) {
3094 // We don't need to start a new activity, and
3095 // the client said not to do anything if that
3096 // is the case, so this is it! And for paranoia, make
3097 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003098 if (doResume) {
3099 resumeTopActivityLocked(null);
3100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 return START_RETURN_INTENT_TO_CALLER;
3102 }
3103 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3104 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3105 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3106 // In this situation we want to remove all activities
3107 // from the task up to the one being started. In most
3108 // cases this means we are resetting the task to its
3109 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003110 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003111 taskTop.task.taskId, r, true);
3112 if (top != null) {
3113 if (top.frontOfTask) {
3114 // Activity aliases may mean we use different
3115 // intents for the top activity, so make sure
3116 // the task now has the identity of the new
3117 // intent.
3118 top.task.setIntent(r.intent, r.info);
3119 }
3120 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3121 deliverNewIntentLocked(top, r.intent);
3122 } else {
3123 // A special case: we need to
3124 // start the activity because it is not currently
3125 // running, and the caller has asked to clear the
3126 // current task to have this activity at the top.
3127 addingToTask = true;
3128 // Now pretend like this activity is being started
3129 // by the top of its task, so it is put in the
3130 // right place.
3131 sourceRecord = taskTop;
3132 }
3133 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3134 // In this case the top activity on the task is the
3135 // same as the one being launched, so we take that
3136 // as a request to bring the task to the foreground.
3137 // If the top activity in the task is the root
3138 // activity, deliver this new intent to it if it
3139 // desires.
3140 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3141 && taskTop.realActivity.equals(r.realActivity)) {
3142 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3143 if (taskTop.frontOfTask) {
3144 taskTop.task.setIntent(r.intent, r.info);
3145 }
3146 deliverNewIntentLocked(taskTop, r.intent);
3147 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3148 // In this case we are launching the root activity
3149 // of the task, but with a different intent. We
3150 // should start a new instance on top.
3151 addingToTask = true;
3152 sourceRecord = taskTop;
3153 }
3154 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3155 // In this case an activity is being launched in to an
3156 // existing task, without resetting that task. This
3157 // is typically the situation of launching an activity
3158 // from a notification or shortcut. We want to place
3159 // the new activity on top of the current task.
3160 addingToTask = true;
3161 sourceRecord = taskTop;
3162 } else if (!taskTop.task.rootWasReset) {
3163 // In this case we are launching in to an existing task
3164 // that has not yet been started from its front door.
3165 // The current task has been brought to the front.
3166 // Ideally, we'd probably like to place this new task
3167 // at the bottom of its stack, but that's a little hard
3168 // to do with the current organization of the code so
3169 // for now we'll just drop it.
3170 taskTop.task.setIntent(r.intent, r.info);
3171 }
3172 if (!addingToTask) {
3173 // We didn't do anything... but it was needed (a.k.a., client
3174 // don't use that intent!) And for paranoia, make
3175 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003176 if (doResume) {
3177 resumeTopActivityLocked(null);
3178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 return START_TASK_TO_FRONT;
3180 }
3181 }
3182 }
3183 }
3184
3185 //String uri = r.intent.toURI();
3186 //Intent intent2 = new Intent(uri);
3187 //Log.i(TAG, "Given intent: " + r.intent);
3188 //Log.i(TAG, "URI is: " + uri);
3189 //Log.i(TAG, "To intent: " + intent2);
3190
3191 if (r.packageName != null) {
3192 // If the activity being launched is the same as the one currently
3193 // at the top, then we need to check if it should only be launched
3194 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003195 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3196 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 if (top.realActivity.equals(r.realActivity)) {
3198 if (top.app != null && top.app.thread != null) {
3199 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3200 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3201 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3202 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3203 // For paranoia, make sure we have correctly
3204 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003205 if (doResume) {
3206 resumeTopActivityLocked(null);
3207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 if (onlyIfNeeded) {
3209 // We don't need to start a new activity, and
3210 // the client said not to do anything if that
3211 // is the case, so this is it!
3212 return START_RETURN_INTENT_TO_CALLER;
3213 }
3214 deliverNewIntentLocked(top, r.intent);
3215 return START_DELIVERED_TO_TOP;
3216 }
3217 }
3218 }
3219 }
3220
3221 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003222 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003224 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 Activity.RESULT_CANCELED, null);
3226 }
3227 return START_CLASS_NOT_FOUND;
3228 }
3229
3230 boolean newTask = false;
3231
3232 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003233 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3235 // todo: should do better management of integers.
3236 mCurTask++;
3237 if (mCurTask <= 0) {
3238 mCurTask = 1;
3239 }
3240 r.task = new TaskRecord(mCurTask, r.info, intent,
3241 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3242 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3243 + " in new task " + r.task);
3244 newTask = true;
3245 addRecentTask(r.task);
3246
3247 } else if (sourceRecord != null) {
3248 if (!addingToTask &&
3249 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3250 // In this case, we are adding the activity to an existing
3251 // task, but the caller has asked to clear that task if the
3252 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003253 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 sourceRecord.task.taskId, r, true);
3255 if (top != null) {
3256 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3257 deliverNewIntentLocked(top, r.intent);
3258 // For paranoia, make sure we have correctly
3259 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003260 if (doResume) {
3261 resumeTopActivityLocked(null);
3262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003263 return START_DELIVERED_TO_TOP;
3264 }
3265 } else if (!addingToTask &&
3266 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3267 // In this case, we are launching an activity in our own task
3268 // that may already be running somewhere in the history, and
3269 // we want to shuffle it to the front of the stack if so.
3270 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3271 if (where >= 0) {
3272 HistoryRecord top = moveActivityToFrontLocked(where);
3273 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3274 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003275 if (doResume) {
3276 resumeTopActivityLocked(null);
3277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 return START_DELIVERED_TO_TOP;
3279 }
3280 }
3281 // An existing activity is starting this new activity, so we want
3282 // to keep the new one in the same task as the one that is starting
3283 // it.
3284 r.task = sourceRecord.task;
3285 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3286 + " in existing task " + r.task);
3287
3288 } else {
3289 // This not being started from an existing activity, and not part
3290 // of a new task... just put it in the top task, though these days
3291 // this case should never happen.
3292 final int N = mHistory.size();
3293 HistoryRecord prev =
3294 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3295 r.task = prev != null
3296 ? prev.task
3297 : new TaskRecord(mCurTask, r.info, intent,
3298 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3299 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3300 + " in new guessed " + r.task);
3301 }
3302 if (newTask) {
3303 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3304 }
3305 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 return START_SUCCESS;
3308 }
3309
3310 public final int startActivity(IApplicationThread caller,
3311 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3312 int grantedMode, IBinder resultTo,
3313 String resultWho, int requestCode, boolean onlyIfNeeded,
3314 boolean debug) {
3315 // Refuse possible leaked file descriptors
3316 if (intent != null && intent.hasFileDescriptors()) {
3317 throw new IllegalArgumentException("File descriptors passed in Intent");
3318 }
3319
The Android Open Source Project4df24232009-03-05 14:34:35 -08003320 final boolean componentSpecified = intent.getComponent() != null;
3321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003322 // Don't modify the client's object!
3323 intent = new Intent(intent);
3324
3325 // Collect information about the target of the Intent.
3326 // Must do this before locking, because resolving the intent
3327 // may require launching a process to run its content provider.
3328 ActivityInfo aInfo;
3329 try {
3330 ResolveInfo rInfo =
3331 ActivityThread.getPackageManager().resolveIntent(
3332 intent, resolvedType,
3333 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003334 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 aInfo = rInfo != null ? rInfo.activityInfo : null;
3336 } catch (RemoteException e) {
3337 aInfo = null;
3338 }
3339
3340 if (aInfo != null) {
3341 // Store the found target back into the intent, because now that
3342 // we have it we never want to do this again. For example, if the
3343 // user navigates back to this point in the history, we should
3344 // always restart the exact same activity.
3345 intent.setComponent(new ComponentName(
3346 aInfo.applicationInfo.packageName, aInfo.name));
3347
3348 // Don't debug things in the system process
3349 if (debug) {
3350 if (!aInfo.processName.equals("system")) {
3351 setDebugApp(aInfo.processName, true, false);
3352 }
3353 }
3354 }
3355
3356 synchronized(this) {
3357 final long origId = Binder.clearCallingIdentity();
3358 int res = startActivityLocked(caller, intent, resolvedType,
3359 grantedUriPermissions, grantedMode, aInfo,
3360 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003361 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 Binder.restoreCallingIdentity(origId);
3363 return res;
3364 }
3365 }
3366
3367 public boolean startNextMatchingActivity(IBinder callingActivity,
3368 Intent intent) {
3369 // Refuse possible leaked file descriptors
3370 if (intent != null && intent.hasFileDescriptors() == true) {
3371 throw new IllegalArgumentException("File descriptors passed in Intent");
3372 }
3373
3374 synchronized (this) {
3375 int index = indexOfTokenLocked(callingActivity, false);
3376 if (index < 0) {
3377 return false;
3378 }
3379 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3380 if (r.app == null || r.app.thread == null) {
3381 // The caller is not running... d'oh!
3382 return false;
3383 }
3384 intent = new Intent(intent);
3385 // The caller is not allowed to change the data.
3386 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3387 // And we are resetting to find the next component...
3388 intent.setComponent(null);
3389
3390 ActivityInfo aInfo = null;
3391 try {
3392 List<ResolveInfo> resolves =
3393 ActivityThread.getPackageManager().queryIntentActivities(
3394 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003395 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396
3397 // Look for the original activity in the list...
3398 final int N = resolves != null ? resolves.size() : 0;
3399 for (int i=0; i<N; i++) {
3400 ResolveInfo rInfo = resolves.get(i);
3401 if (rInfo.activityInfo.packageName.equals(r.packageName)
3402 && rInfo.activityInfo.name.equals(r.info.name)) {
3403 // We found the current one... the next matching is
3404 // after it.
3405 i++;
3406 if (i<N) {
3407 aInfo = resolves.get(i).activityInfo;
3408 }
3409 break;
3410 }
3411 }
3412 } catch (RemoteException e) {
3413 }
3414
3415 if (aInfo == null) {
3416 // Nobody who is next!
3417 return false;
3418 }
3419
3420 intent.setComponent(new ComponentName(
3421 aInfo.applicationInfo.packageName, aInfo.name));
3422 intent.setFlags(intent.getFlags()&~(
3423 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3424 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3425 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3426 Intent.FLAG_ACTIVITY_NEW_TASK));
3427
3428 // Okay now we need to start the new activity, replacing the
3429 // currently running activity. This is a little tricky because
3430 // we want to start the new one as if the current one is finished,
3431 // but not finish the current one first so that there is no flicker.
3432 // And thus...
3433 final boolean wasFinishing = r.finishing;
3434 r.finishing = true;
3435
3436 // Propagate reply information over to the new activity.
3437 final HistoryRecord resultTo = r.resultTo;
3438 final String resultWho = r.resultWho;
3439 final int requestCode = r.requestCode;
3440 r.resultTo = null;
3441 if (resultTo != null) {
3442 resultTo.removeResultsLocked(r, resultWho, requestCode);
3443 }
3444
3445 final long origId = Binder.clearCallingIdentity();
3446 // XXX we are not dealing with propagating grantedUriPermissions...
3447 // those are not yet exposed to user code, so there is no need.
3448 int res = startActivityLocked(r.app.thread, intent,
3449 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003450 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003451 Binder.restoreCallingIdentity(origId);
3452
3453 r.finishing = wasFinishing;
3454 if (res != START_SUCCESS) {
3455 return false;
3456 }
3457 return true;
3458 }
3459 }
3460
3461 final int startActivityInPackage(int uid,
3462 Intent intent, String resolvedType, IBinder resultTo,
3463 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003464 final boolean componentSpecified = intent.getComponent() != null;
3465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 // Don't modify the client's object!
3467 intent = new Intent(intent);
3468
3469 // Collect information about the target of the Intent.
3470 // Must do this before locking, because resolving the intent
3471 // may require launching a process to run its content provider.
3472 ActivityInfo aInfo;
3473 try {
3474 ResolveInfo rInfo =
3475 ActivityThread.getPackageManager().resolveIntent(
3476 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003477 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 aInfo = rInfo != null ? rInfo.activityInfo : null;
3479 } catch (RemoteException e) {
3480 aInfo = null;
3481 }
3482
3483 if (aInfo != null) {
3484 // Store the found target back into the intent, because now that
3485 // we have it we never want to do this again. For example, if the
3486 // user navigates back to this point in the history, we should
3487 // always restart the exact same activity.
3488 intent.setComponent(new ComponentName(
3489 aInfo.applicationInfo.packageName, aInfo.name));
3490 }
3491
3492 synchronized(this) {
3493 return startActivityLocked(null, intent, resolvedType,
3494 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003495 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 }
3497 }
3498
3499 private final void addRecentTask(TaskRecord task) {
3500 // Remove any existing entries that are the same kind of task.
3501 int N = mRecentTasks.size();
3502 for (int i=0; i<N; i++) {
3503 TaskRecord tr = mRecentTasks.get(i);
3504 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3505 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3506 mRecentTasks.remove(i);
3507 i--;
3508 N--;
3509 if (task.intent == null) {
3510 // If the new recent task we are adding is not fully
3511 // specified, then replace it with the existing recent task.
3512 task = tr;
3513 }
3514 }
3515 }
3516 if (N >= MAX_RECENT_TASKS) {
3517 mRecentTasks.remove(N-1);
3518 }
3519 mRecentTasks.add(0, task);
3520 }
3521
3522 public void setRequestedOrientation(IBinder token,
3523 int requestedOrientation) {
3524 synchronized (this) {
3525 int index = indexOfTokenLocked(token, false);
3526 if (index < 0) {
3527 return;
3528 }
3529 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3530 final long origId = Binder.clearCallingIdentity();
3531 mWindowManager.setAppOrientation(r, requestedOrientation);
3532 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003533 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 r.mayFreezeScreenLocked(r.app) ? r : null);
3535 if (config != null) {
3536 r.frozenBeforeDestroy = true;
3537 if (!updateConfigurationLocked(config, r)) {
3538 resumeTopActivityLocked(null);
3539 }
3540 }
3541 Binder.restoreCallingIdentity(origId);
3542 }
3543 }
3544
3545 public int getRequestedOrientation(IBinder token) {
3546 synchronized (this) {
3547 int index = indexOfTokenLocked(token, false);
3548 if (index < 0) {
3549 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3550 }
3551 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3552 return mWindowManager.getAppOrientation(r);
3553 }
3554 }
3555
3556 private final void stopActivityLocked(HistoryRecord r) {
3557 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3558 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3559 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3560 if (!r.finishing) {
3561 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3562 "no-history");
3563 }
3564 } else if (r.app != null && r.app.thread != null) {
3565 if (mFocusedActivity == r) {
3566 setFocusedActivityLocked(topRunningActivityLocked(null));
3567 }
3568 r.resumeKeyDispatchingLocked();
3569 try {
3570 r.stopped = false;
3571 r.state = ActivityState.STOPPING;
3572 if (DEBUG_VISBILITY) Log.v(
3573 TAG, "Stopping visible=" + r.visible + " for " + r);
3574 if (!r.visible) {
3575 mWindowManager.setAppVisibility(r, false);
3576 }
3577 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3578 } catch (Exception e) {
3579 // Maybe just ignore exceptions here... if the process
3580 // has crashed, our death notification will clean things
3581 // up.
3582 Log.w(TAG, "Exception thrown during pause", e);
3583 // Just in case, assume it to be stopped.
3584 r.stopped = true;
3585 r.state = ActivityState.STOPPED;
3586 if (r.configDestroy) {
3587 destroyActivityLocked(r, true);
3588 }
3589 }
3590 }
3591 }
3592
3593 /**
3594 * @return Returns true if the activity is being finished, false if for
3595 * some reason it is being left as-is.
3596 */
3597 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3598 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003599 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 TAG, "Finishing activity: token=" + token
3601 + ", result=" + resultCode + ", data=" + resultData);
3602
3603 int index = indexOfTokenLocked(token, false);
3604 if (index < 0) {
3605 return false;
3606 }
3607 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3608
3609 // Is this the last activity left?
3610 boolean lastActivity = true;
3611 for (int i=mHistory.size()-1; i>=0; i--) {
3612 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3613 if (!p.finishing && p != r) {
3614 lastActivity = false;
3615 break;
3616 }
3617 }
3618
3619 // If this is the last activity, but it is the home activity, then
3620 // just don't finish it.
3621 if (lastActivity) {
3622 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3623 return false;
3624 }
3625 }
3626
3627 finishActivityLocked(r, index, resultCode, resultData, reason);
3628 return true;
3629 }
3630
3631 /**
3632 * @return Returns true if this activity has been removed from the history
3633 * list, or false if it is still in the list and will be removed later.
3634 */
3635 private final boolean finishActivityLocked(HistoryRecord r, int index,
3636 int resultCode, Intent resultData, String reason) {
3637 if (r.finishing) {
3638 Log.w(TAG, "Duplicate finish request for " + r);
3639 return false;
3640 }
3641
3642 r.finishing = true;
3643 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3644 System.identityHashCode(r),
3645 r.task.taskId, r.shortComponentName, reason);
3646 r.task.numActivities--;
3647 if (r.frontOfTask && index < (mHistory.size()-1)) {
3648 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3649 if (next.task == r.task) {
3650 next.frontOfTask = true;
3651 }
3652 }
3653
3654 r.pauseKeyDispatchingLocked();
3655 if (mFocusedActivity == r) {
3656 setFocusedActivityLocked(topRunningActivityLocked(null));
3657 }
3658
3659 // send the result
3660 HistoryRecord resultTo = r.resultTo;
3661 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003662 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3663 + " who=" + r.resultWho + " req=" + r.requestCode
3664 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003665 if (r.info.applicationInfo.uid > 0) {
3666 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3667 r.packageName, resultData, r);
3668 }
3669 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3670 resultData);
3671 r.resultTo = null;
3672 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003673 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003674
3675 // Make sure this HistoryRecord is not holding on to other resources,
3676 // because clients have remote IPC references to this object so we
3677 // can't assume that will go away and want to avoid circular IPC refs.
3678 r.results = null;
3679 r.pendingResults = null;
3680 r.newIntents = null;
3681 r.icicle = null;
3682
3683 if (mPendingThumbnails.size() > 0) {
3684 // There are clients waiting to receive thumbnails so, in case
3685 // this is an activity that someone is waiting for, add it
3686 // to the pending list so we can correctly update the clients.
3687 mCancelledThumbnails.add(r);
3688 }
3689
3690 if (mResumedActivity == r) {
3691 boolean endTask = index <= 0
3692 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3693 if (DEBUG_TRANSITION) Log.v(TAG,
3694 "Prepare close transition: finishing " + r);
3695 mWindowManager.prepareAppTransition(endTask
3696 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3697 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3698
3699 // Tell window manager to prepare for this one to be removed.
3700 mWindowManager.setAppVisibility(r, false);
3701
3702 if (mPausingActivity == null) {
3703 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3704 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3705 startPausingLocked(false, false);
3706 }
3707
3708 } else if (r.state != ActivityState.PAUSING) {
3709 // If the activity is PAUSING, we will complete the finish once
3710 // it is done pausing; else we can just directly finish it here.
3711 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3712 return finishCurrentActivityLocked(r, index,
3713 FINISH_AFTER_PAUSE) == null;
3714 } else {
3715 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3716 }
3717
3718 return false;
3719 }
3720
3721 private static final int FINISH_IMMEDIATELY = 0;
3722 private static final int FINISH_AFTER_PAUSE = 1;
3723 private static final int FINISH_AFTER_VISIBLE = 2;
3724
3725 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3726 int mode) {
3727 final int index = indexOfTokenLocked(r, false);
3728 if (index < 0) {
3729 return null;
3730 }
3731
3732 return finishCurrentActivityLocked(r, index, mode);
3733 }
3734
3735 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3736 int index, int mode) {
3737 // First things first: if this activity is currently visible,
3738 // and the resumed activity is not yet visible, then hold off on
3739 // finishing until the resumed one becomes visible.
3740 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3741 if (!mStoppingActivities.contains(r)) {
3742 mStoppingActivities.add(r);
3743 if (mStoppingActivities.size() > 3) {
3744 // If we already have a few activities waiting to stop,
3745 // then give up on things going idle and start clearing
3746 // them out.
3747 Message msg = Message.obtain();
3748 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3749 mHandler.sendMessage(msg);
3750 }
3751 }
3752 r.state = ActivityState.STOPPING;
3753 updateOomAdjLocked();
3754 return r;
3755 }
3756
3757 // make sure the record is cleaned out of other places.
3758 mStoppingActivities.remove(r);
3759 mWaitingVisibleActivities.remove(r);
3760 if (mResumedActivity == r) {
3761 mResumedActivity = null;
3762 }
3763 final ActivityState prevState = r.state;
3764 r.state = ActivityState.FINISHING;
3765
3766 if (mode == FINISH_IMMEDIATELY
3767 || prevState == ActivityState.STOPPED
3768 || prevState == ActivityState.INITIALIZING) {
3769 // If this activity is already stopped, we can just finish
3770 // it right now.
3771 return destroyActivityLocked(r, true) ? null : r;
3772 } else {
3773 // Need to go through the full pause cycle to get this
3774 // activity into the stopped state and then finish it.
3775 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3776 mFinishingActivities.add(r);
3777 resumeTopActivityLocked(null);
3778 }
3779 return r;
3780 }
3781
3782 /**
3783 * This is the internal entry point for handling Activity.finish().
3784 *
3785 * @param token The Binder token referencing the Activity we want to finish.
3786 * @param resultCode Result code, if any, from this Activity.
3787 * @param resultData Result data (Intent), if any, from this Activity.
3788 *
3789 * @result Returns true if the activity successfully finished, or false if it is still running.
3790 */
3791 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3792 // Refuse possible leaked file descriptors
3793 if (resultData != null && resultData.hasFileDescriptors() == true) {
3794 throw new IllegalArgumentException("File descriptors passed in Intent");
3795 }
3796
3797 synchronized(this) {
3798 if (mWatcher != null) {
3799 // Find the first activity that is not finishing.
3800 HistoryRecord next = topRunningActivityLocked(token, 0);
3801 if (next != null) {
3802 // ask watcher if this is allowed
3803 boolean resumeOK = true;
3804 try {
3805 resumeOK = mWatcher.activityResuming(next.packageName);
3806 } catch (RemoteException e) {
3807 mWatcher = null;
3808 }
3809
3810 if (!resumeOK) {
3811 return false;
3812 }
3813 }
3814 }
3815 final long origId = Binder.clearCallingIdentity();
3816 boolean res = requestFinishActivityLocked(token, resultCode,
3817 resultData, "app-request");
3818 Binder.restoreCallingIdentity(origId);
3819 return res;
3820 }
3821 }
3822
3823 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3824 String resultWho, int requestCode, int resultCode, Intent data) {
3825
3826 if (callingUid > 0) {
3827 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3828 data, r);
3829 }
3830
The Android Open Source Project10592532009-03-18 17:39:46 -07003831 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3832 + " : who=" + resultWho + " req=" + requestCode
3833 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3835 try {
3836 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3837 list.add(new ResultInfo(resultWho, requestCode,
3838 resultCode, data));
3839 r.app.thread.scheduleSendResult(r, list);
3840 return;
3841 } catch (Exception e) {
3842 Log.w(TAG, "Exception thrown sending result to " + r, e);
3843 }
3844 }
3845
3846 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3847 }
3848
3849 public final void finishSubActivity(IBinder token, String resultWho,
3850 int requestCode) {
3851 synchronized(this) {
3852 int index = indexOfTokenLocked(token, false);
3853 if (index < 0) {
3854 return;
3855 }
3856 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3857
3858 final long origId = Binder.clearCallingIdentity();
3859
3860 int i;
3861 for (i=mHistory.size()-1; i>=0; i--) {
3862 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3863 if (r.resultTo == self && r.requestCode == requestCode) {
3864 if ((r.resultWho == null && resultWho == null) ||
3865 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3866 finishActivityLocked(r, i,
3867 Activity.RESULT_CANCELED, null, "request-sub");
3868 }
3869 }
3870 }
3871
3872 Binder.restoreCallingIdentity(origId);
3873 }
3874 }
3875
3876 /**
3877 * Perform clean-up of service connections in an activity record.
3878 */
3879 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3880 // Throw away any services that have been bound by this activity.
3881 if (r.connections != null) {
3882 Iterator<ConnectionRecord> it = r.connections.iterator();
3883 while (it.hasNext()) {
3884 ConnectionRecord c = it.next();
3885 removeConnectionLocked(c, null, r);
3886 }
3887 r.connections = null;
3888 }
3889 }
3890
3891 /**
3892 * Perform the common clean-up of an activity record. This is called both
3893 * as part of destroyActivityLocked() (when destroying the client-side
3894 * representation) and cleaning things up as a result of its hosting
3895 * processing going away, in which case there is no remaining client-side
3896 * state to destroy so only the cleanup here is needed.
3897 */
3898 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3899 if (mResumedActivity == r) {
3900 mResumedActivity = null;
3901 }
3902 if (mFocusedActivity == r) {
3903 mFocusedActivity = null;
3904 }
3905
3906 r.configDestroy = false;
3907 r.frozenBeforeDestroy = false;
3908
3909 // Make sure this record is no longer in the pending finishes list.
3910 // This could happen, for example, if we are trimming activities
3911 // down to the max limit while they are still waiting to finish.
3912 mFinishingActivities.remove(r);
3913 mWaitingVisibleActivities.remove(r);
3914
3915 // Remove any pending results.
3916 if (r.finishing && r.pendingResults != null) {
3917 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3918 PendingIntentRecord rec = apr.get();
3919 if (rec != null) {
3920 cancelIntentSenderLocked(rec, false);
3921 }
3922 }
3923 r.pendingResults = null;
3924 }
3925
3926 if (cleanServices) {
3927 cleanUpActivityServicesLocked(r);
3928 }
3929
3930 if (mPendingThumbnails.size() > 0) {
3931 // There are clients waiting to receive thumbnails so, in case
3932 // this is an activity that someone is waiting for, add it
3933 // to the pending list so we can correctly update the clients.
3934 mCancelledThumbnails.add(r);
3935 }
3936
3937 // Get rid of any pending idle timeouts.
3938 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3939 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3940 }
3941
3942 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
3943 if (r.state != ActivityState.DESTROYED) {
3944 mHistory.remove(r);
3945 r.inHistory = false;
3946 r.state = ActivityState.DESTROYED;
3947 mWindowManager.removeAppToken(r);
3948 if (VALIDATE_TOKENS) {
3949 mWindowManager.validateAppTokens(mHistory);
3950 }
3951 cleanUpActivityServicesLocked(r);
3952 removeActivityUriPermissionsLocked(r);
3953 }
3954 }
3955
3956 /**
3957 * Destroy the current CLIENT SIDE instance of an activity. This may be
3958 * called both when actually finishing an activity, or when performing
3959 * a configuration switch where we destroy the current client-side object
3960 * but then create a new client-side object for this same HistoryRecord.
3961 */
3962 private final boolean destroyActivityLocked(HistoryRecord r,
3963 boolean removeFromApp) {
3964 if (DEBUG_SWITCH) Log.v(
3965 TAG, "Removing activity: token=" + r
3966 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3967 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
3968 System.identityHashCode(r),
3969 r.task.taskId, r.shortComponentName);
3970
3971 boolean removedFromHistory = false;
3972
3973 cleanUpActivityLocked(r, false);
3974
3975 if (r.app != null) {
3976 if (removeFromApp) {
3977 int idx = r.app.activities.indexOf(r);
3978 if (idx >= 0) {
3979 r.app.activities.remove(idx);
3980 }
3981 if (r.persistent) {
3982 decPersistentCountLocked(r.app);
3983 }
3984 }
3985
3986 boolean skipDestroy = false;
3987
3988 try {
3989 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
3990 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3991 r.configChangeFlags);
3992 } catch (Exception e) {
3993 // We can just ignore exceptions here... if the process
3994 // has crashed, our death notification will clean things
3995 // up.
3996 //Log.w(TAG, "Exception thrown during finish", e);
3997 if (r.finishing) {
3998 removeActivityFromHistoryLocked(r);
3999 removedFromHistory = true;
4000 skipDestroy = true;
4001 }
4002 }
4003
4004 r.app = null;
4005 r.nowVisible = false;
4006
4007 if (r.finishing && !skipDestroy) {
4008 r.state = ActivityState.DESTROYING;
4009 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4010 msg.obj = r;
4011 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4012 } else {
4013 r.state = ActivityState.DESTROYED;
4014 }
4015 } else {
4016 // remove this record from the history.
4017 if (r.finishing) {
4018 removeActivityFromHistoryLocked(r);
4019 removedFromHistory = true;
4020 } else {
4021 r.state = ActivityState.DESTROYED;
4022 }
4023 }
4024
4025 r.configChangeFlags = 0;
4026
4027 if (!mLRUActivities.remove(r)) {
4028 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4029 }
4030
4031 return removedFromHistory;
4032 }
4033
4034 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4035 ProcessRecord app)
4036 {
4037 int i = list.size();
4038 if (localLOGV) Log.v(
4039 TAG, "Removing app " + app + " from list " + list
4040 + " with " + i + " entries");
4041 while (i > 0) {
4042 i--;
4043 HistoryRecord r = (HistoryRecord)list.get(i);
4044 if (localLOGV) Log.v(
4045 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4046 if (r.app == app) {
4047 if (localLOGV) Log.v(TAG, "Removing this entry!");
4048 list.remove(i);
4049 }
4050 }
4051 }
4052
4053 /**
4054 * Main function for removing an existing process from the activity manager
4055 * as a result of that process going away. Clears out all connections
4056 * to the process.
4057 */
4058 private final void handleAppDiedLocked(ProcessRecord app,
4059 boolean restarting) {
4060 cleanUpApplicationRecordLocked(app, restarting, -1);
4061 if (!restarting) {
4062 mLRUProcesses.remove(app);
4063 }
4064
4065 // Just in case...
4066 if (mPausingActivity != null && mPausingActivity.app == app) {
4067 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4068 mPausingActivity = null;
4069 }
4070 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4071 mLastPausedActivity = null;
4072 }
4073
4074 // Remove this application's activities from active lists.
4075 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4076 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4077 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4078 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4079
4080 boolean atTop = true;
4081 boolean hasVisibleActivities = false;
4082
4083 // Clean out the history list.
4084 int i = mHistory.size();
4085 if (localLOGV) Log.v(
4086 TAG, "Removing app " + app + " from history with " + i + " entries");
4087 while (i > 0) {
4088 i--;
4089 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4090 if (localLOGV) Log.v(
4091 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4092 if (r.app == app) {
4093 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4094 if (localLOGV) Log.v(
4095 TAG, "Removing this entry! frozen=" + r.haveState
4096 + " finishing=" + r.finishing);
4097 mHistory.remove(i);
4098
4099 r.inHistory = false;
4100 mWindowManager.removeAppToken(r);
4101 if (VALIDATE_TOKENS) {
4102 mWindowManager.validateAppTokens(mHistory);
4103 }
4104 removeActivityUriPermissionsLocked(r);
4105
4106 } else {
4107 // We have the current state for this activity, so
4108 // it can be restarted later when needed.
4109 if (localLOGV) Log.v(
4110 TAG, "Keeping entry, setting app to null");
4111 if (r.visible) {
4112 hasVisibleActivities = true;
4113 }
4114 r.app = null;
4115 r.nowVisible = false;
4116 if (!r.haveState) {
4117 r.icicle = null;
4118 }
4119 }
4120
4121 cleanUpActivityLocked(r, true);
4122 r.state = ActivityState.STOPPED;
4123 }
4124 atTop = false;
4125 }
4126
4127 app.activities.clear();
4128
4129 if (app.instrumentationClass != null) {
4130 Log.w(TAG, "Crash of app " + app.processName
4131 + " running instrumentation " + app.instrumentationClass);
4132 Bundle info = new Bundle();
4133 info.putString("shortMsg", "Process crashed.");
4134 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4135 }
4136
4137 if (!restarting) {
4138 if (!resumeTopActivityLocked(null)) {
4139 // If there was nothing to resume, and we are not already
4140 // restarting this process, but there is a visible activity that
4141 // is hosted by the process... then make sure all visible
4142 // activities are running, taking care of restarting this
4143 // process.
4144 if (hasVisibleActivities) {
4145 ensureActivitiesVisibleLocked(null, 0);
4146 }
4147 }
4148 }
4149 }
4150
4151 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4152 IBinder threadBinder = thread.asBinder();
4153
4154 // Find the application record.
4155 int count = mLRUProcesses.size();
4156 int i;
4157 for (i=0; i<count; i++) {
4158 ProcessRecord rec = mLRUProcesses.get(i);
4159 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4160 return i;
4161 }
4162 }
4163 return -1;
4164 }
4165
4166 private final ProcessRecord getRecordForAppLocked(
4167 IApplicationThread thread) {
4168 if (thread == null) {
4169 return null;
4170 }
4171
4172 int appIndex = getLRURecordIndexForAppLocked(thread);
4173 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4174 }
4175
4176 private final void appDiedLocked(ProcessRecord app, int pid,
4177 IApplicationThread thread) {
4178
4179 mProcDeaths[0]++;
4180
4181 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4182 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4183 + ") has died.");
4184 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4185 if (localLOGV) Log.v(
4186 TAG, "Dying app: " + app + ", pid: " + pid
4187 + ", thread: " + thread.asBinder());
4188 boolean doLowMem = app.instrumentationClass == null;
4189 handleAppDiedLocked(app, false);
4190
4191 if (doLowMem) {
4192 // If there are no longer any background processes running,
4193 // and the app that died was not running instrumentation,
4194 // then tell everyone we are now low on memory.
4195 boolean haveBg = false;
4196 int count = mLRUProcesses.size();
4197 int i;
4198 for (i=0; i<count; i++) {
4199 ProcessRecord rec = mLRUProcesses.get(i);
4200 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4201 haveBg = true;
4202 break;
4203 }
4204 }
4205
4206 if (!haveBg) {
4207 Log.i(TAG, "Low Memory: No more background processes.");
4208 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4209 for (i=0; i<count; i++) {
4210 ProcessRecord rec = mLRUProcesses.get(i);
4211 if (rec.thread != null) {
4212 rec.lastRequestedGc = SystemClock.uptimeMillis();
4213 try {
4214 rec.thread.scheduleLowMemory();
4215 } catch (RemoteException e) {
4216 // Don't care if the process is gone.
4217 }
4218 }
4219 }
4220 }
4221 }
4222 } else if (Config.LOGD) {
4223 Log.d(TAG, "Received spurious death notification for thread "
4224 + thread.asBinder());
4225 }
4226 }
4227
4228 final String readFile(String filename) {
4229 try {
4230 FileInputStream fs = new FileInputStream(filename);
4231 byte[] inp = new byte[8192];
4232 int size = fs.read(inp);
4233 fs.close();
4234 return new String(inp, 0, 0, size);
4235 } catch (java.io.IOException e) {
4236 }
4237 return "";
4238 }
4239
4240 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4241 final String annotation) {
4242 if (app.notResponding || app.crashing) {
4243 return;
4244 }
4245
4246 // Log the ANR to the event log.
4247 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4248
4249 // If we are on a secure build and the application is not interesting to the user (it is
4250 // not visible or in the background), just kill it instead of displaying a dialog.
4251 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4252 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4253 Process.killProcess(app.pid);
4254 return;
4255 }
4256
4257 // DeviceMonitor.start();
4258
4259 String processInfo = null;
4260 if (MONITOR_CPU_USAGE) {
4261 updateCpuStatsNow();
4262 synchronized (mProcessStatsThread) {
4263 processInfo = mProcessStats.printCurrentState();
4264 }
4265 }
4266
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004267 StringBuilder info = mStringBuilder;
4268 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004269 info.append("ANR (application not responding) in process: ");
4270 info.append(app.processName);
4271 if (annotation != null) {
4272 info.append("\nAnnotation: ");
4273 info.append(annotation);
4274 }
4275 if (MONITOR_CPU_USAGE) {
4276 info.append("\nCPU usage:\n");
4277 info.append(processInfo);
4278 }
4279 Log.i(TAG, info.toString());
4280
4281 // The application is not responding. Dump as many thread traces as we can.
4282 boolean fileDump = prepareTraceFile(true);
4283 if (!fileDump) {
4284 // Dumping traces to the log, just dump the process that isn't responding so
4285 // we don't overflow the log
4286 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4287 } else {
4288 // Dumping traces to a file so dump all active processes we know about
4289 synchronized (this) {
4290 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4291 ProcessRecord r = mLRUProcesses.get(i);
4292 if (r.thread != null) {
4293 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4294 }
4295 }
4296 }
4297 }
4298
4299 if (mWatcher != null) {
4300 try {
4301 int res = mWatcher.appNotResponding(app.processName,
4302 app.pid, info.toString());
4303 if (res != 0) {
4304 if (res < 0) {
4305 // wait until the SIGQUIT has had a chance to process before killing the
4306 // process.
4307 try {
4308 wait(2000);
4309 } catch (InterruptedException e) {
4310 }
4311
4312 Process.killProcess(app.pid);
4313 return;
4314 }
4315 }
4316 } catch (RemoteException e) {
4317 mWatcher = null;
4318 }
4319 }
4320
4321 makeAppNotRespondingLocked(app,
4322 activity != null ? activity.shortComponentName : null,
4323 annotation != null ? "ANR " + annotation : "ANR",
4324 info.toString(), null);
4325 Message msg = Message.obtain();
4326 HashMap map = new HashMap();
4327 msg.what = SHOW_NOT_RESPONDING_MSG;
4328 msg.obj = map;
4329 map.put("app", app);
4330 if (activity != null) {
4331 map.put("activity", activity);
4332 }
4333
4334 mHandler.sendMessage(msg);
4335 return;
4336 }
4337
4338 /**
4339 * If a stack trace file has been configured, prepare the filesystem
4340 * by creating the directory if it doesn't exist and optionally
4341 * removing the old trace file.
4342 *
4343 * @param removeExisting If set, the existing trace file will be removed.
4344 * @return Returns true if the trace file preparations succeeded
4345 */
4346 public static boolean prepareTraceFile(boolean removeExisting) {
4347 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4348 boolean fileReady = false;
4349 if (!TextUtils.isEmpty(tracesPath)) {
4350 File f = new File(tracesPath);
4351 if (!f.exists()) {
4352 // Ensure the enclosing directory exists
4353 File dir = f.getParentFile();
4354 if (!dir.exists()) {
4355 fileReady = dir.mkdirs();
4356 FileUtils.setPermissions(dir.getAbsolutePath(),
4357 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4358 } else if (dir.isDirectory()) {
4359 fileReady = true;
4360 }
4361 } else if (removeExisting) {
4362 // Remove the previous traces file, so we don't fill the disk.
4363 // The VM will recreate it
4364 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4365 fileReady = f.delete();
4366 }
4367 }
4368
4369 return fileReady;
4370 }
4371
4372
4373 private final void decPersistentCountLocked(ProcessRecord app)
4374 {
4375 app.persistentActivities--;
4376 if (app.persistentActivities > 0) {
4377 // Still more of 'em...
4378 return;
4379 }
4380 if (app.persistent) {
4381 // Ah, but the application itself is persistent. Whatever!
4382 return;
4383 }
4384
4385 // App is no longer persistent... make sure it and the ones
4386 // following it in the LRU list have the correc oom_adj.
4387 updateOomAdjLocked();
4388 }
4389
4390 public void setPersistent(IBinder token, boolean isPersistent) {
4391 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4392 != PackageManager.PERMISSION_GRANTED) {
4393 String msg = "Permission Denial: setPersistent() from pid="
4394 + Binder.getCallingPid()
4395 + ", uid=" + Binder.getCallingUid()
4396 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4397 Log.w(TAG, msg);
4398 throw new SecurityException(msg);
4399 }
4400
4401 synchronized(this) {
4402 int index = indexOfTokenLocked(token, true);
4403 if (index < 0) {
4404 return;
4405 }
4406 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4407 ProcessRecord app = r.app;
4408
4409 if (localLOGV) Log.v(
4410 TAG, "Setting persistence " + isPersistent + ": " + r);
4411
4412 if (isPersistent) {
4413 if (r.persistent) {
4414 // Okay okay, I heard you already!
4415 if (localLOGV) Log.v(TAG, "Already persistent!");
4416 return;
4417 }
4418 r.persistent = true;
4419 app.persistentActivities++;
4420 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4421 if (app.persistentActivities > 1) {
4422 // We aren't the first...
4423 if (localLOGV) Log.v(TAG, "Not the first!");
4424 return;
4425 }
4426 if (app.persistent) {
4427 // This would be redundant.
4428 if (localLOGV) Log.v(TAG, "App is persistent!");
4429 return;
4430 }
4431
4432 // App is now persistent... make sure it and the ones
4433 // following it now have the correct oom_adj.
4434 final long origId = Binder.clearCallingIdentity();
4435 updateOomAdjLocked();
4436 Binder.restoreCallingIdentity(origId);
4437
4438 } else {
4439 if (!r.persistent) {
4440 // Okay okay, I heard you already!
4441 return;
4442 }
4443 r.persistent = false;
4444 final long origId = Binder.clearCallingIdentity();
4445 decPersistentCountLocked(app);
4446 Binder.restoreCallingIdentity(origId);
4447
4448 }
4449 }
4450 }
4451
4452 public boolean clearApplicationUserData(final String packageName,
4453 final IPackageDataObserver observer) {
4454 int uid = Binder.getCallingUid();
4455 int pid = Binder.getCallingPid();
4456 long callingId = Binder.clearCallingIdentity();
4457 try {
4458 IPackageManager pm = ActivityThread.getPackageManager();
4459 int pkgUid = -1;
4460 synchronized(this) {
4461 try {
4462 pkgUid = pm.getPackageUid(packageName);
4463 } catch (RemoteException e) {
4464 }
4465 if (pkgUid == -1) {
4466 Log.w(TAG, "Invalid packageName:" + packageName);
4467 return false;
4468 }
4469 if (uid == pkgUid || checkComponentPermission(
4470 android.Manifest.permission.CLEAR_APP_USER_DATA,
4471 pid, uid, -1)
4472 == PackageManager.PERMISSION_GRANTED) {
4473 restartPackageLocked(packageName, pkgUid);
4474 } else {
4475 throw new SecurityException(pid+" does not have permission:"+
4476 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4477 "for process:"+packageName);
4478 }
4479 }
4480
4481 try {
4482 //clear application user data
4483 pm.clearApplicationUserData(packageName, observer);
4484 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4485 Uri.fromParts("package", packageName, null));
4486 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4487 broadcastIntentLocked(null, null, intent,
4488 null, null, 0, null, null, null,
4489 false, false, MY_PID, Process.SYSTEM_UID);
4490 } catch (RemoteException e) {
4491 }
4492 } finally {
4493 Binder.restoreCallingIdentity(callingId);
4494 }
4495 return true;
4496 }
4497
4498 public void restartPackage(final String packageName) {
4499 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4500 != PackageManager.PERMISSION_GRANTED) {
4501 String msg = "Permission Denial: restartPackage() from pid="
4502 + Binder.getCallingPid()
4503 + ", uid=" + Binder.getCallingUid()
4504 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4505 Log.w(TAG, msg);
4506 throw new SecurityException(msg);
4507 }
4508
4509 long callingId = Binder.clearCallingIdentity();
4510 try {
4511 IPackageManager pm = ActivityThread.getPackageManager();
4512 int pkgUid = -1;
4513 synchronized(this) {
4514 try {
4515 pkgUid = pm.getPackageUid(packageName);
4516 } catch (RemoteException e) {
4517 }
4518 if (pkgUid == -1) {
4519 Log.w(TAG, "Invalid packageName: " + packageName);
4520 return;
4521 }
4522 restartPackageLocked(packageName, pkgUid);
4523 }
4524 } finally {
4525 Binder.restoreCallingIdentity(callingId);
4526 }
4527 }
4528
4529 private void restartPackageLocked(final String packageName, int uid) {
4530 uninstallPackageLocked(packageName, uid, false);
4531 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4532 Uri.fromParts("package", packageName, null));
4533 intent.putExtra(Intent.EXTRA_UID, uid);
4534 broadcastIntentLocked(null, null, intent,
4535 null, null, 0, null, null, null,
4536 false, false, MY_PID, Process.SYSTEM_UID);
4537 }
4538
4539 private final void uninstallPackageLocked(String name, int uid,
4540 boolean callerWillRestart) {
4541 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4542
4543 int i, N;
4544
4545 final String procNamePrefix = name + ":";
4546 if (uid < 0) {
4547 try {
4548 uid = ActivityThread.getPackageManager().getPackageUid(name);
4549 } catch (RemoteException e) {
4550 }
4551 }
4552
4553 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4554 while (badApps.hasNext()) {
4555 SparseArray<Long> ba = badApps.next();
4556 if (ba.get(uid) != null) {
4557 badApps.remove();
4558 }
4559 }
4560
4561 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4562
4563 // Remove all processes this package may have touched: all with the
4564 // same UID (except for the system or root user), and all whose name
4565 // matches the package name.
4566 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4567 final int NA = apps.size();
4568 for (int ia=0; ia<NA; ia++) {
4569 ProcessRecord app = apps.valueAt(ia);
4570 if (app.removed) {
4571 procs.add(app);
4572 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4573 || app.processName.equals(name)
4574 || app.processName.startsWith(procNamePrefix)) {
4575 app.removed = true;
4576 procs.add(app);
4577 }
4578 }
4579 }
4580
4581 N = procs.size();
4582 for (i=0; i<N; i++) {
4583 removeProcessLocked(procs.get(i), callerWillRestart);
4584 }
4585
4586 for (i=mHistory.size()-1; i>=0; i--) {
4587 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4588 if (r.packageName.equals(name)) {
4589 if (Config.LOGD) Log.d(
4590 TAG, " Force finishing activity "
4591 + r.intent.getComponent().flattenToShortString());
4592 if (r.app != null) {
4593 r.app.removed = true;
4594 }
4595 r.app = null;
4596 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4597 }
4598 }
4599
4600 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4601 for (ServiceRecord service : mServices.values()) {
4602 if (service.packageName.equals(name)) {
4603 if (service.app != null) {
4604 service.app.removed = true;
4605 }
4606 service.app = null;
4607 services.add(service);
4608 }
4609 }
4610
4611 N = services.size();
4612 for (i=0; i<N; i++) {
4613 bringDownServiceLocked(services.get(i), true);
4614 }
4615
4616 resumeTopActivityLocked(null);
4617 }
4618
4619 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4620 final String name = app.processName;
4621 final int uid = app.info.uid;
4622 if (Config.LOGD) Log.d(
4623 TAG, "Force removing process " + app + " (" + name
4624 + "/" + uid + ")");
4625
4626 mProcessNames.remove(name, uid);
4627 boolean needRestart = false;
4628 if (app.pid > 0 && app.pid != MY_PID) {
4629 int pid = app.pid;
4630 synchronized (mPidsSelfLocked) {
4631 mPidsSelfLocked.remove(pid);
4632 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4633 }
4634 handleAppDiedLocked(app, true);
4635 mLRUProcesses.remove(app);
4636 Process.killProcess(pid);
4637
4638 if (app.persistent) {
4639 if (!callerWillRestart) {
4640 addAppLocked(app.info);
4641 } else {
4642 needRestart = true;
4643 }
4644 }
4645 } else {
4646 mRemovedProcesses.add(app);
4647 }
4648
4649 return needRestart;
4650 }
4651
4652 private final void processStartTimedOutLocked(ProcessRecord app) {
4653 final int pid = app.pid;
4654 boolean gone = false;
4655 synchronized (mPidsSelfLocked) {
4656 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4657 if (knownApp != null && knownApp.thread == null) {
4658 mPidsSelfLocked.remove(pid);
4659 gone = true;
4660 }
4661 }
4662
4663 if (gone) {
4664 Log.w(TAG, "Process " + app + " failed to attach");
4665 mProcessNames.remove(app.processName, app.info.uid);
4666 Process.killProcess(pid);
4667 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4668 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4669 mPendingBroadcast = null;
4670 scheduleBroadcastsLocked();
4671 }
4672 } else {
4673 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4674 }
4675 }
4676
4677 private final boolean attachApplicationLocked(IApplicationThread thread,
4678 int pid) {
4679
4680 // Find the application record that is being attached... either via
4681 // the pid if we are running in multiple processes, or just pull the
4682 // next app record if we are emulating process with anonymous threads.
4683 ProcessRecord app;
4684 if (pid != MY_PID && pid >= 0) {
4685 synchronized (mPidsSelfLocked) {
4686 app = mPidsSelfLocked.get(pid);
4687 }
4688 } else if (mStartingProcesses.size() > 0) {
4689 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004690 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004691 } else {
4692 app = null;
4693 }
4694
4695 if (app == null) {
4696 Log.w(TAG, "No pending application record for pid " + pid
4697 + " (IApplicationThread " + thread + "); dropping process");
4698 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4699 if (pid > 0 && pid != MY_PID) {
4700 Process.killProcess(pid);
4701 } else {
4702 try {
4703 thread.scheduleExit();
4704 } catch (Exception e) {
4705 // Ignore exceptions.
4706 }
4707 }
4708 return false;
4709 }
4710
4711 // If this application record is still attached to a previous
4712 // process, clean it up now.
4713 if (app.thread != null) {
4714 handleAppDiedLocked(app, true);
4715 }
4716
4717 // Tell the process all about itself.
4718
4719 if (localLOGV) Log.v(
4720 TAG, "Binding process pid " + pid + " to record " + app);
4721
4722 String processName = app.processName;
4723 try {
4724 thread.asBinder().linkToDeath(new AppDeathRecipient(
4725 app, pid, thread), 0);
4726 } catch (RemoteException e) {
4727 app.resetPackageList();
4728 startProcessLocked(app, "link fail", processName);
4729 return false;
4730 }
4731
4732 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4733
4734 app.thread = thread;
4735 app.curAdj = app.setAdj = -100;
4736 app.forcingToForeground = null;
4737 app.foregroundServices = false;
4738 app.debugging = false;
4739
4740 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4741
4742 List providers = generateApplicationProvidersLocked(app);
4743
4744 if (localLOGV) Log.v(
4745 TAG, "New app record " + app
4746 + " thread=" + thread.asBinder() + " pid=" + pid);
4747 try {
4748 int testMode = IApplicationThread.DEBUG_OFF;
4749 if (mDebugApp != null && mDebugApp.equals(processName)) {
4750 testMode = mWaitForDebugger
4751 ? IApplicationThread.DEBUG_WAIT
4752 : IApplicationThread.DEBUG_ON;
4753 app.debugging = true;
4754 if (mDebugTransient) {
4755 mDebugApp = mOrigDebugApp;
4756 mWaitForDebugger = mOrigWaitForDebugger;
4757 }
4758 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004759 thread.bindApplication(processName, app.instrumentationInfo != null
4760 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004761 app.instrumentationClass, app.instrumentationProfileFile,
4762 app.instrumentationArguments, app.instrumentationWatcher, testMode,
4763 mConfiguration, getCommonServicesLocked());
4764 updateLRUListLocked(app, false);
4765 app.lastRequestedGc = SystemClock.uptimeMillis();
4766 } catch (Exception e) {
4767 // todo: Yikes! What should we do? For now we will try to
4768 // start another process, but that could easily get us in
4769 // an infinite loop of restarting processes...
4770 Log.w(TAG, "Exception thrown during bind!", e);
4771
4772 app.resetPackageList();
4773 startProcessLocked(app, "bind fail", processName);
4774 return false;
4775 }
4776
4777 // Remove this record from the list of starting applications.
4778 mPersistentStartingProcesses.remove(app);
4779 mProcessesOnHold.remove(app);
4780
4781 boolean badApp = false;
4782 boolean didSomething = false;
4783
4784 // See if the top visible activity is waiting to run in this process...
4785 HistoryRecord hr = topRunningActivityLocked(null);
4786 if (hr != null) {
4787 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4788 && processName.equals(hr.processName)) {
4789 try {
4790 if (realStartActivityLocked(hr, app, true, true)) {
4791 didSomething = true;
4792 }
4793 } catch (Exception e) {
4794 Log.w(TAG, "Exception in new application when starting activity "
4795 + hr.intent.getComponent().flattenToShortString(), e);
4796 badApp = true;
4797 }
4798 } else {
4799 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4800 }
4801 }
4802
4803 // Find any services that should be running in this process...
4804 if (!badApp && mPendingServices.size() > 0) {
4805 ServiceRecord sr = null;
4806 try {
4807 for (int i=0; i<mPendingServices.size(); i++) {
4808 sr = mPendingServices.get(i);
4809 if (app.info.uid != sr.appInfo.uid
4810 || !processName.equals(sr.processName)) {
4811 continue;
4812 }
4813
4814 mPendingServices.remove(i);
4815 i--;
4816 realStartServiceLocked(sr, app);
4817 didSomething = true;
4818 }
4819 } catch (Exception e) {
4820 Log.w(TAG, "Exception in new application when starting service "
4821 + sr.shortName, e);
4822 badApp = true;
4823 }
4824 }
4825
4826 // Check if the next broadcast receiver is in this process...
4827 BroadcastRecord br = mPendingBroadcast;
4828 if (!badApp && br != null && br.curApp == app) {
4829 try {
4830 mPendingBroadcast = null;
4831 processCurBroadcastLocked(br, app);
4832 didSomething = true;
4833 } catch (Exception e) {
4834 Log.w(TAG, "Exception in new application when starting receiver "
4835 + br.curComponent.flattenToShortString(), e);
4836 badApp = true;
4837 logBroadcastReceiverDiscard(br);
4838 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4839 br.resultExtras, br.resultAbort, true);
4840 scheduleBroadcastsLocked();
4841 }
4842 }
4843
4844 if (badApp) {
4845 // todo: Also need to kill application to deal with all
4846 // kinds of exceptions.
4847 handleAppDiedLocked(app, false);
4848 return false;
4849 }
4850
4851 if (!didSomething) {
4852 updateOomAdjLocked();
4853 }
4854
4855 return true;
4856 }
4857
4858 public final void attachApplication(IApplicationThread thread) {
4859 synchronized (this) {
4860 int callingPid = Binder.getCallingPid();
4861 final long origId = Binder.clearCallingIdentity();
4862 attachApplicationLocked(thread, callingPid);
4863 Binder.restoreCallingIdentity(origId);
4864 }
4865 }
4866
4867 public final void activityIdle(IBinder token) {
4868 final long origId = Binder.clearCallingIdentity();
4869 activityIdleInternal(token, false);
4870 Binder.restoreCallingIdentity(origId);
4871 }
4872
4873 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4874 boolean remove) {
4875 int N = mStoppingActivities.size();
4876 if (N <= 0) return null;
4877
4878 ArrayList<HistoryRecord> stops = null;
4879
4880 final boolean nowVisible = mResumedActivity != null
4881 && mResumedActivity.nowVisible
4882 && !mResumedActivity.waitingVisible;
4883 for (int i=0; i<N; i++) {
4884 HistoryRecord s = mStoppingActivities.get(i);
4885 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4886 + nowVisible + " waitingVisible=" + s.waitingVisible
4887 + " finishing=" + s.finishing);
4888 if (s.waitingVisible && nowVisible) {
4889 mWaitingVisibleActivities.remove(s);
4890 s.waitingVisible = false;
4891 if (s.finishing) {
4892 // If this activity is finishing, it is sitting on top of
4893 // everyone else but we now know it is no longer needed...
4894 // so get rid of it. Otherwise, we need to go through the
4895 // normal flow and hide it once we determine that it is
4896 // hidden by the activities in front of it.
4897 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4898 mWindowManager.setAppVisibility(s, false);
4899 }
4900 }
4901 if (!s.waitingVisible && remove) {
4902 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4903 if (stops == null) {
4904 stops = new ArrayList<HistoryRecord>();
4905 }
4906 stops.add(s);
4907 mStoppingActivities.remove(i);
4908 N--;
4909 i--;
4910 }
4911 }
4912
4913 return stops;
4914 }
4915
4916 void enableScreenAfterBoot() {
4917 mWindowManager.enableScreenAfterBoot();
4918 }
4919
4920 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4921 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4922
4923 ArrayList<HistoryRecord> stops = null;
4924 ArrayList<HistoryRecord> finishes = null;
4925 ArrayList<HistoryRecord> thumbnails = null;
4926 int NS = 0;
4927 int NF = 0;
4928 int NT = 0;
4929 IApplicationThread sendThumbnail = null;
4930 boolean booting = false;
4931 boolean enableScreen = false;
4932
4933 synchronized (this) {
4934 if (token != null) {
4935 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
4936 }
4937
4938 // Get the activity record.
4939 int index = indexOfTokenLocked(token, false);
4940 if (index >= 0) {
4941 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4942
4943 // No longer need to keep the device awake.
4944 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
4945 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
4946 mLaunchingActivity.release();
4947 }
4948
4949 // We are now idle. If someone is waiting for a thumbnail from
4950 // us, we can now deliver.
4951 r.idle = true;
4952 scheduleAppGcsLocked();
4953 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
4954 sendThumbnail = r.app.thread;
4955 r.thumbnailNeeded = false;
4956 }
4957
4958 // If this activity is fullscreen, set up to hide those under it.
4959
4960 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
4961 ensureActivitiesVisibleLocked(null, 0);
4962
4963 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
4964 if (!mBooted && !fromTimeout) {
4965 mBooted = true;
4966 enableScreen = true;
4967 }
4968 }
4969
4970 // Atomically retrieve all of the other things to do.
4971 stops = processStoppingActivitiesLocked(true);
4972 NS = stops != null ? stops.size() : 0;
4973 if ((NF=mFinishingActivities.size()) > 0) {
4974 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
4975 mFinishingActivities.clear();
4976 }
4977 if ((NT=mCancelledThumbnails.size()) > 0) {
4978 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
4979 mCancelledThumbnails.clear();
4980 }
4981
4982 booting = mBooting;
4983 mBooting = false;
4984 }
4985
4986 int i;
4987
4988 // Send thumbnail if requested.
4989 if (sendThumbnail != null) {
4990 try {
4991 sendThumbnail.requestThumbnail(token);
4992 } catch (Exception e) {
4993 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
4994 sendPendingThumbnail(null, token, null, null, true);
4995 }
4996 }
4997
4998 // Stop any activities that are scheduled to do so but have been
4999 // waiting for the next one to start.
5000 for (i=0; i<NS; i++) {
5001 HistoryRecord r = (HistoryRecord)stops.get(i);
5002 synchronized (this) {
5003 if (r.finishing) {
5004 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5005 } else {
5006 stopActivityLocked(r);
5007 }
5008 }
5009 }
5010
5011 // Finish any activities that are scheduled to do so but have been
5012 // waiting for the next one to start.
5013 for (i=0; i<NF; i++) {
5014 HistoryRecord r = (HistoryRecord)finishes.get(i);
5015 synchronized (this) {
5016 destroyActivityLocked(r, true);
5017 }
5018 }
5019
5020 // Report back to any thumbnail receivers.
5021 for (i=0; i<NT; i++) {
5022 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5023 sendPendingThumbnail(r, null, null, null, true);
5024 }
5025
5026 if (booting) {
5027 // Ensure that any processes we had put on hold are now started
5028 // up.
5029 final int NP = mProcessesOnHold.size();
5030 if (NP > 0) {
5031 ArrayList<ProcessRecord> procs =
5032 new ArrayList<ProcessRecord>(mProcessesOnHold);
5033 for (int ip=0; ip<NP; ip++) {
5034 this.startProcessLocked(procs.get(ip), "on-hold", null);
5035 }
5036 }
5037 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5038 // Tell anyone interested that we are done booting!
5039 synchronized (this) {
5040 broadcastIntentLocked(null, null,
5041 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5042 null, null, 0, null, null,
5043 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5044 false, false, MY_PID, Process.SYSTEM_UID);
5045 }
5046 }
5047 }
5048
5049 trimApplications();
5050 //dump();
5051 //mWindowManager.dump();
5052
5053 if (enableScreen) {
5054 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5055 SystemClock.uptimeMillis());
5056 enableScreenAfterBoot();
5057 }
5058 }
5059
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005060 final void ensureScreenEnabled() {
5061 boolean enableScreen;
5062 synchronized (this) {
5063 enableScreen = !mBooted;
5064 mBooted = true;
5065 }
5066
5067 if (enableScreen) {
5068 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5069 SystemClock.uptimeMillis());
5070 enableScreenAfterBoot();
5071 }
5072 }
5073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005074 public final void activityPaused(IBinder token, Bundle icicle) {
5075 // Refuse possible leaked file descriptors
5076 if (icicle != null && icicle.hasFileDescriptors()) {
5077 throw new IllegalArgumentException("File descriptors passed in Bundle");
5078 }
5079
5080 final long origId = Binder.clearCallingIdentity();
5081 activityPaused(token, icicle, false);
5082 Binder.restoreCallingIdentity(origId);
5083 }
5084
5085 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5086 if (DEBUG_PAUSE) Log.v(
5087 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5088 + ", timeout=" + timeout);
5089
5090 HistoryRecord r = null;
5091
5092 synchronized (this) {
5093 int index = indexOfTokenLocked(token, false);
5094 if (index >= 0) {
5095 r = (HistoryRecord)mHistory.get(index);
5096 if (!timeout) {
5097 r.icicle = icicle;
5098 r.haveState = true;
5099 }
5100 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5101 if (mPausingActivity == r) {
5102 r.state = ActivityState.PAUSED;
5103 completePauseLocked();
5104 } else {
5105 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5106 System.identityHashCode(r), r.shortComponentName,
5107 mPausingActivity != null
5108 ? mPausingActivity.shortComponentName : "(none)");
5109 }
5110 }
5111 }
5112 }
5113
5114 public final void activityStopped(IBinder token, Bitmap thumbnail,
5115 CharSequence description) {
5116 if (localLOGV) Log.v(
5117 TAG, "Activity stopped: token=" + token);
5118
5119 HistoryRecord r = null;
5120
5121 final long origId = Binder.clearCallingIdentity();
5122
5123 synchronized (this) {
5124 int index = indexOfTokenLocked(token, false);
5125 if (index >= 0) {
5126 r = (HistoryRecord)mHistory.get(index);
5127 r.thumbnail = thumbnail;
5128 r.description = description;
5129 r.stopped = true;
5130 r.state = ActivityState.STOPPED;
5131 if (!r.finishing) {
5132 if (r.configDestroy) {
5133 destroyActivityLocked(r, true);
5134 resumeTopActivityLocked(null);
5135 }
5136 }
5137 }
5138 }
5139
5140 if (r != null) {
5141 sendPendingThumbnail(r, null, null, null, false);
5142 }
5143
5144 trimApplications();
5145
5146 Binder.restoreCallingIdentity(origId);
5147 }
5148
5149 public final void activityDestroyed(IBinder token) {
5150 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5151 synchronized (this) {
5152 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5153
5154 int index = indexOfTokenLocked(token, false);
5155 if (index >= 0) {
5156 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5157 if (r.state == ActivityState.DESTROYING) {
5158 final long origId = Binder.clearCallingIdentity();
5159 removeActivityFromHistoryLocked(r);
5160 Binder.restoreCallingIdentity(origId);
5161 }
5162 }
5163 }
5164 }
5165
5166 public String getCallingPackage(IBinder token) {
5167 synchronized (this) {
5168 HistoryRecord r = getCallingRecordLocked(token);
5169 return r != null && r.app != null ? r.app.processName : null;
5170 }
5171 }
5172
5173 public ComponentName getCallingActivity(IBinder token) {
5174 synchronized (this) {
5175 HistoryRecord r = getCallingRecordLocked(token);
5176 return r != null ? r.intent.getComponent() : null;
5177 }
5178 }
5179
5180 private HistoryRecord getCallingRecordLocked(IBinder token) {
5181 int index = indexOfTokenLocked(token, true);
5182 if (index >= 0) {
5183 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5184 if (r != null) {
5185 return r.resultTo;
5186 }
5187 }
5188 return null;
5189 }
5190
5191 public ComponentName getActivityClassForToken(IBinder token) {
5192 synchronized(this) {
5193 int index = indexOfTokenLocked(token, false);
5194 if (index >= 0) {
5195 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5196 return r.intent.getComponent();
5197 }
5198 return null;
5199 }
5200 }
5201
5202 public String getPackageForToken(IBinder token) {
5203 synchronized(this) {
5204 int index = indexOfTokenLocked(token, false);
5205 if (index >= 0) {
5206 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5207 return r.packageName;
5208 }
5209 return null;
5210 }
5211 }
5212
5213 public IIntentSender getIntentSender(int type,
5214 String packageName, IBinder token, String resultWho,
5215 int requestCode, Intent intent, String resolvedType, int flags) {
5216 // Refuse possible leaked file descriptors
5217 if (intent != null && intent.hasFileDescriptors() == true) {
5218 throw new IllegalArgumentException("File descriptors passed in Intent");
5219 }
5220
5221 synchronized(this) {
5222 int callingUid = Binder.getCallingUid();
5223 try {
5224 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5225 Process.supportsProcesses()) {
5226 int uid = ActivityThread.getPackageManager()
5227 .getPackageUid(packageName);
5228 if (uid != Binder.getCallingUid()) {
5229 String msg = "Permission Denial: getIntentSender() from pid="
5230 + Binder.getCallingPid()
5231 + ", uid=" + Binder.getCallingUid()
5232 + ", (need uid=" + uid + ")"
5233 + " is not allowed to send as package " + packageName;
5234 Log.w(TAG, msg);
5235 throw new SecurityException(msg);
5236 }
5237 }
5238 } catch (RemoteException e) {
5239 throw new SecurityException(e);
5240 }
5241 HistoryRecord activity = null;
5242 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5243 int index = indexOfTokenLocked(token, false);
5244 if (index < 0) {
5245 return null;
5246 }
5247 activity = (HistoryRecord)mHistory.get(index);
5248 if (activity.finishing) {
5249 return null;
5250 }
5251 }
5252
5253 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5254 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5255 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5256 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5257 |PendingIntent.FLAG_UPDATE_CURRENT);
5258
5259 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5260 type, packageName, activity, resultWho,
5261 requestCode, intent, resolvedType, flags);
5262 WeakReference<PendingIntentRecord> ref;
5263 ref = mIntentSenderRecords.get(key);
5264 PendingIntentRecord rec = ref != null ? ref.get() : null;
5265 if (rec != null) {
5266 if (!cancelCurrent) {
5267 if (updateCurrent) {
5268 rec.key.requestIntent.replaceExtras(intent);
5269 }
5270 return rec;
5271 }
5272 rec.canceled = true;
5273 mIntentSenderRecords.remove(key);
5274 }
5275 if (noCreate) {
5276 return rec;
5277 }
5278 rec = new PendingIntentRecord(this, key, callingUid);
5279 mIntentSenderRecords.put(key, rec.ref);
5280 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5281 if (activity.pendingResults == null) {
5282 activity.pendingResults
5283 = new HashSet<WeakReference<PendingIntentRecord>>();
5284 }
5285 activity.pendingResults.add(rec.ref);
5286 }
5287 return rec;
5288 }
5289 }
5290
5291 public void cancelIntentSender(IIntentSender sender) {
5292 if (!(sender instanceof PendingIntentRecord)) {
5293 return;
5294 }
5295 synchronized(this) {
5296 PendingIntentRecord rec = (PendingIntentRecord)sender;
5297 try {
5298 int uid = ActivityThread.getPackageManager()
5299 .getPackageUid(rec.key.packageName);
5300 if (uid != Binder.getCallingUid()) {
5301 String msg = "Permission Denial: cancelIntentSender() from pid="
5302 + Binder.getCallingPid()
5303 + ", uid=" + Binder.getCallingUid()
5304 + " is not allowed to cancel packges "
5305 + rec.key.packageName;
5306 Log.w(TAG, msg);
5307 throw new SecurityException(msg);
5308 }
5309 } catch (RemoteException e) {
5310 throw new SecurityException(e);
5311 }
5312 cancelIntentSenderLocked(rec, true);
5313 }
5314 }
5315
5316 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5317 rec.canceled = true;
5318 mIntentSenderRecords.remove(rec.key);
5319 if (cleanActivity && rec.key.activity != null) {
5320 rec.key.activity.pendingResults.remove(rec.ref);
5321 }
5322 }
5323
5324 public String getPackageForIntentSender(IIntentSender pendingResult) {
5325 if (!(pendingResult instanceof PendingIntentRecord)) {
5326 return null;
5327 }
5328 synchronized(this) {
5329 try {
5330 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5331 return res.key.packageName;
5332 } catch (ClassCastException e) {
5333 }
5334 }
5335 return null;
5336 }
5337
5338 public void setProcessLimit(int max) {
5339 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5340 "setProcessLimit()");
5341 mProcessLimit = max;
5342 }
5343
5344 public int getProcessLimit() {
5345 return mProcessLimit;
5346 }
5347
5348 void foregroundTokenDied(ForegroundToken token) {
5349 synchronized (ActivityManagerService.this) {
5350 synchronized (mPidsSelfLocked) {
5351 ForegroundToken cur
5352 = mForegroundProcesses.get(token.pid);
5353 if (cur != token) {
5354 return;
5355 }
5356 mForegroundProcesses.remove(token.pid);
5357 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5358 if (pr == null) {
5359 return;
5360 }
5361 pr.forcingToForeground = null;
5362 pr.foregroundServices = false;
5363 }
5364 updateOomAdjLocked();
5365 }
5366 }
5367
5368 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5369 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5370 "setProcessForeground()");
5371 synchronized(this) {
5372 boolean changed = false;
5373
5374 synchronized (mPidsSelfLocked) {
5375 ProcessRecord pr = mPidsSelfLocked.get(pid);
5376 if (pr == null) {
5377 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5378 return;
5379 }
5380 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5381 if (oldToken != null) {
5382 oldToken.token.unlinkToDeath(oldToken, 0);
5383 mForegroundProcesses.remove(pid);
5384 pr.forcingToForeground = null;
5385 changed = true;
5386 }
5387 if (isForeground && token != null) {
5388 ForegroundToken newToken = new ForegroundToken() {
5389 public void binderDied() {
5390 foregroundTokenDied(this);
5391 }
5392 };
5393 newToken.pid = pid;
5394 newToken.token = token;
5395 try {
5396 token.linkToDeath(newToken, 0);
5397 mForegroundProcesses.put(pid, newToken);
5398 pr.forcingToForeground = token;
5399 changed = true;
5400 } catch (RemoteException e) {
5401 // If the process died while doing this, we will later
5402 // do the cleanup with the process death link.
5403 }
5404 }
5405 }
5406
5407 if (changed) {
5408 updateOomAdjLocked();
5409 }
5410 }
5411 }
5412
5413 // =========================================================
5414 // PERMISSIONS
5415 // =========================================================
5416
5417 static class PermissionController extends IPermissionController.Stub {
5418 ActivityManagerService mActivityManagerService;
5419 PermissionController(ActivityManagerService activityManagerService) {
5420 mActivityManagerService = activityManagerService;
5421 }
5422
5423 public boolean checkPermission(String permission, int pid, int uid) {
5424 return mActivityManagerService.checkPermission(permission, pid,
5425 uid) == PackageManager.PERMISSION_GRANTED;
5426 }
5427 }
5428
5429 /**
5430 * This can be called with or without the global lock held.
5431 */
5432 int checkComponentPermission(String permission, int pid, int uid,
5433 int reqUid) {
5434 // We might be performing an operation on behalf of an indirect binder
5435 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5436 // client identity accordingly before proceeding.
5437 Identity tlsIdentity = sCallerIdentity.get();
5438 if (tlsIdentity != null) {
5439 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5440 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5441 uid = tlsIdentity.uid;
5442 pid = tlsIdentity.pid;
5443 }
5444
5445 // Root, system server and our own process get to do everything.
5446 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5447 !Process.supportsProcesses()) {
5448 return PackageManager.PERMISSION_GRANTED;
5449 }
5450 // If the target requires a specific UID, always fail for others.
5451 if (reqUid >= 0 && uid != reqUid) {
5452 return PackageManager.PERMISSION_DENIED;
5453 }
5454 if (permission == null) {
5455 return PackageManager.PERMISSION_GRANTED;
5456 }
5457 try {
5458 return ActivityThread.getPackageManager()
5459 .checkUidPermission(permission, uid);
5460 } catch (RemoteException e) {
5461 // Should never happen, but if it does... deny!
5462 Log.e(TAG, "PackageManager is dead?!?", e);
5463 }
5464 return PackageManager.PERMISSION_DENIED;
5465 }
5466
5467 /**
5468 * As the only public entry point for permissions checking, this method
5469 * can enforce the semantic that requesting a check on a null global
5470 * permission is automatically denied. (Internally a null permission
5471 * string is used when calling {@link #checkComponentPermission} in cases
5472 * when only uid-based security is needed.)
5473 *
5474 * This can be called with or without the global lock held.
5475 */
5476 public int checkPermission(String permission, int pid, int uid) {
5477 if (permission == null) {
5478 return PackageManager.PERMISSION_DENIED;
5479 }
5480 return checkComponentPermission(permission, pid, uid, -1);
5481 }
5482
5483 /**
5484 * Binder IPC calls go through the public entry point.
5485 * This can be called with or without the global lock held.
5486 */
5487 int checkCallingPermission(String permission) {
5488 return checkPermission(permission,
5489 Binder.getCallingPid(),
5490 Binder.getCallingUid());
5491 }
5492
5493 /**
5494 * This can be called with or without the global lock held.
5495 */
5496 void enforceCallingPermission(String permission, String func) {
5497 if (checkCallingPermission(permission)
5498 == PackageManager.PERMISSION_GRANTED) {
5499 return;
5500 }
5501
5502 String msg = "Permission Denial: " + func + " from pid="
5503 + Binder.getCallingPid()
5504 + ", uid=" + Binder.getCallingUid()
5505 + " requires " + permission;
5506 Log.w(TAG, msg);
5507 throw new SecurityException(msg);
5508 }
5509
5510 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5511 ProviderInfo pi, int uid, int modeFlags) {
5512 try {
5513 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5514 if ((pi.readPermission != null) &&
5515 (pm.checkUidPermission(pi.readPermission, uid)
5516 != PackageManager.PERMISSION_GRANTED)) {
5517 return false;
5518 }
5519 }
5520 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5521 if ((pi.writePermission != null) &&
5522 (pm.checkUidPermission(pi.writePermission, uid)
5523 != PackageManager.PERMISSION_GRANTED)) {
5524 return false;
5525 }
5526 }
5527 return true;
5528 } catch (RemoteException e) {
5529 return false;
5530 }
5531 }
5532
5533 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5534 int modeFlags) {
5535 // Root gets to do everything.
5536 if (uid == 0 || !Process.supportsProcesses()) {
5537 return true;
5538 }
5539 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5540 if (perms == null) return false;
5541 UriPermission perm = perms.get(uri);
5542 if (perm == null) return false;
5543 return (modeFlags&perm.modeFlags) == modeFlags;
5544 }
5545
5546 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5547 // Another redirected-binder-call permissions check as in
5548 // {@link checkComponentPermission}.
5549 Identity tlsIdentity = sCallerIdentity.get();
5550 if (tlsIdentity != null) {
5551 uid = tlsIdentity.uid;
5552 pid = tlsIdentity.pid;
5553 }
5554
5555 // Our own process gets to do everything.
5556 if (pid == MY_PID) {
5557 return PackageManager.PERMISSION_GRANTED;
5558 }
5559 synchronized(this) {
5560 return checkUriPermissionLocked(uri, uid, modeFlags)
5561 ? PackageManager.PERMISSION_GRANTED
5562 : PackageManager.PERMISSION_DENIED;
5563 }
5564 }
5565
5566 private void grantUriPermissionLocked(int callingUid,
5567 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5568 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5569 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5570 if (modeFlags == 0) {
5571 return;
5572 }
5573
5574 final IPackageManager pm = ActivityThread.getPackageManager();
5575
5576 // If this is not a content: uri, we can't do anything with it.
5577 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5578 return;
5579 }
5580
5581 String name = uri.getAuthority();
5582 ProviderInfo pi = null;
5583 ContentProviderRecord cpr
5584 = (ContentProviderRecord)mProvidersByName.get(name);
5585 if (cpr != null) {
5586 pi = cpr.info;
5587 } else {
5588 try {
5589 pi = pm.resolveContentProvider(name,
5590 PackageManager.GET_URI_PERMISSION_PATTERNS);
5591 } catch (RemoteException ex) {
5592 }
5593 }
5594 if (pi == null) {
5595 Log.w(TAG, "No content provider found for: " + name);
5596 return;
5597 }
5598
5599 int targetUid;
5600 try {
5601 targetUid = pm.getPackageUid(targetPkg);
5602 if (targetUid < 0) {
5603 return;
5604 }
5605 } catch (RemoteException ex) {
5606 return;
5607 }
5608
5609 // First... does the target actually need this permission?
5610 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5611 // No need to grant the target this permission.
5612 return;
5613 }
5614
5615 // Second... maybe someone else has already granted the
5616 // permission?
5617 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5618 // No need to grant the target this permission.
5619 return;
5620 }
5621
5622 // Third... is the provider allowing granting of URI permissions?
5623 if (!pi.grantUriPermissions) {
5624 throw new SecurityException("Provider " + pi.packageName
5625 + "/" + pi.name
5626 + " does not allow granting of Uri permissions (uri "
5627 + uri + ")");
5628 }
5629 if (pi.uriPermissionPatterns != null) {
5630 final int N = pi.uriPermissionPatterns.length;
5631 boolean allowed = false;
5632 for (int i=0; i<N; i++) {
5633 if (pi.uriPermissionPatterns[i] != null
5634 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5635 allowed = true;
5636 break;
5637 }
5638 }
5639 if (!allowed) {
5640 throw new SecurityException("Provider " + pi.packageName
5641 + "/" + pi.name
5642 + " does not allow granting of permission to path of Uri "
5643 + uri);
5644 }
5645 }
5646
5647 // Fourth... does the caller itself have permission to access
5648 // this uri?
5649 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5650 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5651 throw new SecurityException("Uid " + callingUid
5652 + " does not have permission to uri " + uri);
5653 }
5654 }
5655
5656 // Okay! So here we are: the caller has the assumed permission
5657 // to the uri, and the target doesn't. Let's now give this to
5658 // the target.
5659
5660 HashMap<Uri, UriPermission> targetUris
5661 = mGrantedUriPermissions.get(targetUid);
5662 if (targetUris == null) {
5663 targetUris = new HashMap<Uri, UriPermission>();
5664 mGrantedUriPermissions.put(targetUid, targetUris);
5665 }
5666
5667 UriPermission perm = targetUris.get(uri);
5668 if (perm == null) {
5669 perm = new UriPermission(targetUid, uri);
5670 targetUris.put(uri, perm);
5671
5672 }
5673 perm.modeFlags |= modeFlags;
5674 if (activity == null) {
5675 perm.globalModeFlags |= modeFlags;
5676 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5677 perm.readActivities.add(activity);
5678 if (activity.readUriPermissions == null) {
5679 activity.readUriPermissions = new HashSet<UriPermission>();
5680 }
5681 activity.readUriPermissions.add(perm);
5682 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5683 perm.writeActivities.add(activity);
5684 if (activity.writeUriPermissions == null) {
5685 activity.writeUriPermissions = new HashSet<UriPermission>();
5686 }
5687 activity.writeUriPermissions.add(perm);
5688 }
5689 }
5690
5691 private void grantUriPermissionFromIntentLocked(int callingUid,
5692 String targetPkg, Intent intent, HistoryRecord activity) {
5693 if (intent == null) {
5694 return;
5695 }
5696 Uri data = intent.getData();
5697 if (data == null) {
5698 return;
5699 }
5700 grantUriPermissionLocked(callingUid, targetPkg, data,
5701 intent.getFlags(), activity);
5702 }
5703
5704 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5705 Uri uri, int modeFlags) {
5706 synchronized(this) {
5707 final ProcessRecord r = getRecordForAppLocked(caller);
5708 if (r == null) {
5709 throw new SecurityException("Unable to find app for caller "
5710 + caller
5711 + " when granting permission to uri " + uri);
5712 }
5713 if (targetPkg == null) {
5714 Log.w(TAG, "grantUriPermission: null target");
5715 return;
5716 }
5717 if (uri == null) {
5718 Log.w(TAG, "grantUriPermission: null uri");
5719 return;
5720 }
5721
5722 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5723 null);
5724 }
5725 }
5726
5727 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5728 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5729 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5730 HashMap<Uri, UriPermission> perms
5731 = mGrantedUriPermissions.get(perm.uid);
5732 if (perms != null) {
5733 perms.remove(perm.uri);
5734 if (perms.size() == 0) {
5735 mGrantedUriPermissions.remove(perm.uid);
5736 }
5737 }
5738 }
5739 }
5740
5741 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5742 if (activity.readUriPermissions != null) {
5743 for (UriPermission perm : activity.readUriPermissions) {
5744 perm.readActivities.remove(activity);
5745 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5746 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5747 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5748 removeUriPermissionIfNeededLocked(perm);
5749 }
5750 }
5751 }
5752 if (activity.writeUriPermissions != null) {
5753 for (UriPermission perm : activity.writeUriPermissions) {
5754 perm.writeActivities.remove(activity);
5755 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5756 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5757 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5758 removeUriPermissionIfNeededLocked(perm);
5759 }
5760 }
5761 }
5762 }
5763
5764 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5765 int modeFlags) {
5766 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5767 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5768 if (modeFlags == 0) {
5769 return;
5770 }
5771
5772 final IPackageManager pm = ActivityThread.getPackageManager();
5773
5774 final String authority = uri.getAuthority();
5775 ProviderInfo pi = null;
5776 ContentProviderRecord cpr
5777 = (ContentProviderRecord)mProvidersByName.get(authority);
5778 if (cpr != null) {
5779 pi = cpr.info;
5780 } else {
5781 try {
5782 pi = pm.resolveContentProvider(authority,
5783 PackageManager.GET_URI_PERMISSION_PATTERNS);
5784 } catch (RemoteException ex) {
5785 }
5786 }
5787 if (pi == null) {
5788 Log.w(TAG, "No content provider found for: " + authority);
5789 return;
5790 }
5791
5792 // Does the caller have this permission on the URI?
5793 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5794 // Right now, if you are not the original owner of the permission,
5795 // you are not allowed to revoke it.
5796 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5797 throw new SecurityException("Uid " + callingUid
5798 + " does not have permission to uri " + uri);
5799 //}
5800 }
5801
5802 // Go through all of the permissions and remove any that match.
5803 final List<String> SEGMENTS = uri.getPathSegments();
5804 if (SEGMENTS != null) {
5805 final int NS = SEGMENTS.size();
5806 int N = mGrantedUriPermissions.size();
5807 for (int i=0; i<N; i++) {
5808 HashMap<Uri, UriPermission> perms
5809 = mGrantedUriPermissions.valueAt(i);
5810 Iterator<UriPermission> it = perms.values().iterator();
5811 toploop:
5812 while (it.hasNext()) {
5813 UriPermission perm = it.next();
5814 Uri targetUri = perm.uri;
5815 if (!authority.equals(targetUri.getAuthority())) {
5816 continue;
5817 }
5818 List<String> targetSegments = targetUri.getPathSegments();
5819 if (targetSegments == null) {
5820 continue;
5821 }
5822 if (targetSegments.size() < NS) {
5823 continue;
5824 }
5825 for (int j=0; j<NS; j++) {
5826 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5827 continue toploop;
5828 }
5829 }
5830 perm.clearModes(modeFlags);
5831 if (perm.modeFlags == 0) {
5832 it.remove();
5833 }
5834 }
5835 if (perms.size() == 0) {
5836 mGrantedUriPermissions.remove(
5837 mGrantedUriPermissions.keyAt(i));
5838 N--;
5839 i--;
5840 }
5841 }
5842 }
5843 }
5844
5845 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5846 int modeFlags) {
5847 synchronized(this) {
5848 final ProcessRecord r = getRecordForAppLocked(caller);
5849 if (r == null) {
5850 throw new SecurityException("Unable to find app for caller "
5851 + caller
5852 + " when revoking permission to uri " + uri);
5853 }
5854 if (uri == null) {
5855 Log.w(TAG, "revokeUriPermission: null uri");
5856 return;
5857 }
5858
5859 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5860 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5861 if (modeFlags == 0) {
5862 return;
5863 }
5864
5865 final IPackageManager pm = ActivityThread.getPackageManager();
5866
5867 final String authority = uri.getAuthority();
5868 ProviderInfo pi = null;
5869 ContentProviderRecord cpr
5870 = (ContentProviderRecord)mProvidersByName.get(authority);
5871 if (cpr != null) {
5872 pi = cpr.info;
5873 } else {
5874 try {
5875 pi = pm.resolveContentProvider(authority,
5876 PackageManager.GET_URI_PERMISSION_PATTERNS);
5877 } catch (RemoteException ex) {
5878 }
5879 }
5880 if (pi == null) {
5881 Log.w(TAG, "No content provider found for: " + authority);
5882 return;
5883 }
5884
5885 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5886 }
5887 }
5888
5889 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5890 synchronized (this) {
5891 ProcessRecord app =
5892 who != null ? getRecordForAppLocked(who) : null;
5893 if (app == null) return;
5894
5895 Message msg = Message.obtain();
5896 msg.what = WAIT_FOR_DEBUGGER_MSG;
5897 msg.obj = app;
5898 msg.arg1 = waiting ? 1 : 0;
5899 mHandler.sendMessage(msg);
5900 }
5901 }
5902
5903 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5904 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005905 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005906 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005907 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005908 }
5909
5910 // =========================================================
5911 // TASK MANAGEMENT
5912 // =========================================================
5913
5914 public List getTasks(int maxNum, int flags,
5915 IThumbnailReceiver receiver) {
5916 ArrayList list = new ArrayList();
5917
5918 PendingThumbnailsRecord pending = null;
5919 IApplicationThread topThumbnail = null;
5920 HistoryRecord topRecord = null;
5921
5922 synchronized(this) {
5923 if (localLOGV) Log.v(
5924 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
5925 + ", receiver=" + receiver);
5926
5927 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
5928 != PackageManager.PERMISSION_GRANTED) {
5929 if (receiver != null) {
5930 // If the caller wants to wait for pending thumbnails,
5931 // it ain't gonna get them.
5932 try {
5933 receiver.finished();
5934 } catch (RemoteException ex) {
5935 }
5936 }
5937 String msg = "Permission Denial: getTasks() from pid="
5938 + Binder.getCallingPid()
5939 + ", uid=" + Binder.getCallingUid()
5940 + " requires " + android.Manifest.permission.GET_TASKS;
5941 Log.w(TAG, msg);
5942 throw new SecurityException(msg);
5943 }
5944
5945 int pos = mHistory.size()-1;
5946 HistoryRecord next =
5947 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5948 HistoryRecord top = null;
5949 CharSequence topDescription = null;
5950 TaskRecord curTask = null;
5951 int numActivities = 0;
5952 int numRunning = 0;
5953 while (pos >= 0 && maxNum > 0) {
5954 final HistoryRecord r = next;
5955 pos--;
5956 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5957
5958 // Initialize state for next task if needed.
5959 if (top == null ||
5960 (top.state == ActivityState.INITIALIZING
5961 && top.task == r.task)) {
5962 top = r;
5963 topDescription = r.description;
5964 curTask = r.task;
5965 numActivities = numRunning = 0;
5966 }
5967
5968 // Add 'r' into the current task.
5969 numActivities++;
5970 if (r.app != null && r.app.thread != null) {
5971 numRunning++;
5972 }
5973 if (topDescription == null) {
5974 topDescription = r.description;
5975 }
5976
5977 if (localLOGV) Log.v(
5978 TAG, r.intent.getComponent().flattenToShortString()
5979 + ": task=" + r.task);
5980
5981 // If the next one is a different task, generate a new
5982 // TaskInfo entry for what we have.
5983 if (next == null || next.task != curTask) {
5984 ActivityManager.RunningTaskInfo ci
5985 = new ActivityManager.RunningTaskInfo();
5986 ci.id = curTask.taskId;
5987 ci.baseActivity = r.intent.getComponent();
5988 ci.topActivity = top.intent.getComponent();
5989 ci.thumbnail = top.thumbnail;
5990 ci.description = topDescription;
5991 ci.numActivities = numActivities;
5992 ci.numRunning = numRunning;
5993 //System.out.println(
5994 // "#" + maxNum + ": " + " descr=" + ci.description);
5995 if (ci.thumbnail == null && receiver != null) {
5996 if (localLOGV) Log.v(
5997 TAG, "State=" + top.state + "Idle=" + top.idle
5998 + " app=" + top.app
5999 + " thr=" + (top.app != null ? top.app.thread : null));
6000 if (top.state == ActivityState.RESUMED
6001 || top.state == ActivityState.PAUSING) {
6002 if (top.idle && top.app != null
6003 && top.app.thread != null) {
6004 topRecord = top;
6005 topThumbnail = top.app.thread;
6006 } else {
6007 top.thumbnailNeeded = true;
6008 }
6009 }
6010 if (pending == null) {
6011 pending = new PendingThumbnailsRecord(receiver);
6012 }
6013 pending.pendingRecords.add(top);
6014 }
6015 list.add(ci);
6016 maxNum--;
6017 top = null;
6018 }
6019 }
6020
6021 if (pending != null) {
6022 mPendingThumbnails.add(pending);
6023 }
6024 }
6025
6026 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6027
6028 if (topThumbnail != null) {
6029 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6030 try {
6031 topThumbnail.requestThumbnail(topRecord);
6032 } catch (Exception e) {
6033 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6034 sendPendingThumbnail(null, topRecord, null, null, true);
6035 }
6036 }
6037
6038 if (pending == null && receiver != null) {
6039 // In this case all thumbnails were available and the client
6040 // is being asked to be told when the remaining ones come in...
6041 // which is unusually, since the top-most currently running
6042 // activity should never have a canned thumbnail! Oh well.
6043 try {
6044 receiver.finished();
6045 } catch (RemoteException ex) {
6046 }
6047 }
6048
6049 return list;
6050 }
6051
6052 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6053 int flags) {
6054 synchronized (this) {
6055 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6056 "getRecentTasks()");
6057
6058 final int N = mRecentTasks.size();
6059 ArrayList<ActivityManager.RecentTaskInfo> res
6060 = new ArrayList<ActivityManager.RecentTaskInfo>(
6061 maxNum < N ? maxNum : N);
6062 for (int i=0; i<N && maxNum > 0; i++) {
6063 TaskRecord tr = mRecentTasks.get(i);
6064 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6065 || (tr.intent == null)
6066 || ((tr.intent.getFlags()
6067 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6068 ActivityManager.RecentTaskInfo rti
6069 = new ActivityManager.RecentTaskInfo();
6070 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6071 rti.baseIntent = new Intent(
6072 tr.intent != null ? tr.intent : tr.affinityIntent);
6073 rti.origActivity = tr.origActivity;
6074 res.add(rti);
6075 maxNum--;
6076 }
6077 }
6078 return res;
6079 }
6080 }
6081
6082 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6083 int j;
6084 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6085 TaskRecord jt = startTask;
6086
6087 // First look backwards
6088 for (j=startIndex-1; j>=0; j--) {
6089 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6090 if (r.task != jt) {
6091 jt = r.task;
6092 if (affinity.equals(jt.affinity)) {
6093 return j;
6094 }
6095 }
6096 }
6097
6098 // Now look forwards
6099 final int N = mHistory.size();
6100 jt = startTask;
6101 for (j=startIndex+1; j<N; j++) {
6102 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6103 if (r.task != jt) {
6104 if (affinity.equals(jt.affinity)) {
6105 return j;
6106 }
6107 jt = r.task;
6108 }
6109 }
6110
6111 // Might it be at the top?
6112 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6113 return N-1;
6114 }
6115
6116 return -1;
6117 }
6118
6119 /**
6120 * Perform a reset of the given task, if needed as part of launching it.
6121 * Returns the new HistoryRecord at the top of the task.
6122 */
6123 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6124 HistoryRecord newActivity) {
6125 boolean forceReset = (newActivity.info.flags
6126 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6127 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6128 if ((newActivity.info.flags
6129 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6130 forceReset = true;
6131 }
6132 }
6133
6134 final TaskRecord task = taskTop.task;
6135
6136 // We are going to move through the history list so that we can look
6137 // at each activity 'target' with 'below' either the interesting
6138 // activity immediately below it in the stack or null.
6139 HistoryRecord target = null;
6140 int targetI = 0;
6141 int taskTopI = -1;
6142 int replyChainEnd = -1;
6143 int lastReparentPos = -1;
6144 for (int i=mHistory.size()-1; i>=-1; i--) {
6145 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6146
6147 if (below != null && below.finishing) {
6148 continue;
6149 }
6150 if (target == null) {
6151 target = below;
6152 targetI = i;
6153 // If we were in the middle of a reply chain before this
6154 // task, it doesn't appear like the root of the chain wants
6155 // anything interesting, so drop it.
6156 replyChainEnd = -1;
6157 continue;
6158 }
6159
6160 final int flags = target.info.flags;
6161
6162 final boolean finishOnTaskLaunch =
6163 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6164 final boolean allowTaskReparenting =
6165 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6166
6167 if (target.task == task) {
6168 // We are inside of the task being reset... we'll either
6169 // finish this activity, push it out for another task,
6170 // or leave it as-is. We only do this
6171 // for activities that are not the root of the task (since
6172 // if we finish the root, we may no longer have the task!).
6173 if (taskTopI < 0) {
6174 taskTopI = targetI;
6175 }
6176 if (below != null && below.task == task) {
6177 final boolean clearWhenTaskReset =
6178 (target.intent.getFlags()
6179 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006180 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006181 // If this activity is sending a reply to a previous
6182 // activity, we can't do anything with it now until
6183 // we reach the start of the reply chain.
6184 // XXX note that we are assuming the result is always
6185 // to the previous activity, which is almost always
6186 // the case but we really shouldn't count on.
6187 if (replyChainEnd < 0) {
6188 replyChainEnd = targetI;
6189 }
Ed Heyl73798232009-03-24 21:32:21 -07006190 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006191 && target.taskAffinity != null
6192 && !target.taskAffinity.equals(task.affinity)) {
6193 // If this activity has an affinity for another
6194 // task, then we need to move it out of here. We will
6195 // move it as far out of the way as possible, to the
6196 // bottom of the activity stack. This also keeps it
6197 // correctly ordered with any activities we previously
6198 // moved.
6199 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6200 if (target.taskAffinity != null
6201 && target.taskAffinity.equals(p.task.affinity)) {
6202 // If the activity currently at the bottom has the
6203 // same task affinity as the one we are moving,
6204 // then merge it into the same task.
6205 target.task = p.task;
6206 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6207 + " out to bottom task " + p.task);
6208 } else {
6209 mCurTask++;
6210 if (mCurTask <= 0) {
6211 mCurTask = 1;
6212 }
6213 target.task = new TaskRecord(mCurTask, target.info, null,
6214 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6215 target.task.affinityIntent = target.intent;
6216 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6217 + " out to new task " + target.task);
6218 }
6219 mWindowManager.setAppGroupId(target, task.taskId);
6220 if (replyChainEnd < 0) {
6221 replyChainEnd = targetI;
6222 }
6223 int dstPos = 0;
6224 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6225 p = (HistoryRecord)mHistory.get(srcPos);
6226 if (p.finishing) {
6227 continue;
6228 }
6229 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6230 + " out to target's task " + target.task);
6231 task.numActivities--;
6232 p.task = target.task;
6233 target.task.numActivities++;
6234 mHistory.remove(srcPos);
6235 mHistory.add(dstPos, p);
6236 mWindowManager.moveAppToken(dstPos, p);
6237 mWindowManager.setAppGroupId(p, p.task.taskId);
6238 dstPos++;
6239 if (VALIDATE_TOKENS) {
6240 mWindowManager.validateAppTokens(mHistory);
6241 }
6242 i++;
6243 }
6244 if (taskTop == p) {
6245 taskTop = below;
6246 }
6247 if (taskTopI == replyChainEnd) {
6248 taskTopI = -1;
6249 }
6250 replyChainEnd = -1;
6251 addRecentTask(target.task);
6252 } else if (forceReset || finishOnTaskLaunch
6253 || clearWhenTaskReset) {
6254 // If the activity should just be removed -- either
6255 // because it asks for it, or the task should be
6256 // cleared -- then finish it and anything that is
6257 // part of its reply chain.
6258 if (clearWhenTaskReset) {
6259 // In this case, we want to finish this activity
6260 // and everything above it, so be sneaky and pretend
6261 // like these are all in the reply chain.
6262 replyChainEnd = targetI+1;
6263 while (replyChainEnd < mHistory.size() &&
6264 ((HistoryRecord)mHistory.get(
6265 replyChainEnd)).task == task) {
6266 replyChainEnd++;
6267 }
6268 replyChainEnd--;
6269 } else if (replyChainEnd < 0) {
6270 replyChainEnd = targetI;
6271 }
6272 HistoryRecord p = null;
6273 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6274 p = (HistoryRecord)mHistory.get(srcPos);
6275 if (p.finishing) {
6276 continue;
6277 }
6278 if (finishActivityLocked(p, srcPos,
6279 Activity.RESULT_CANCELED, null, "reset")) {
6280 replyChainEnd--;
6281 srcPos--;
6282 }
6283 }
6284 if (taskTop == p) {
6285 taskTop = below;
6286 }
6287 if (taskTopI == replyChainEnd) {
6288 taskTopI = -1;
6289 }
6290 replyChainEnd = -1;
6291 } else {
6292 // If we were in the middle of a chain, well the
6293 // activity that started it all doesn't want anything
6294 // special, so leave it all as-is.
6295 replyChainEnd = -1;
6296 }
6297 } else {
6298 // Reached the bottom of the task -- any reply chain
6299 // should be left as-is.
6300 replyChainEnd = -1;
6301 }
6302
6303 } else if (target.resultTo != null) {
6304 // If this activity is sending a reply to a previous
6305 // activity, we can't do anything with it now until
6306 // we reach the start of the reply chain.
6307 // XXX note that we are assuming the result is always
6308 // to the previous activity, which is almost always
6309 // the case but we really shouldn't count on.
6310 if (replyChainEnd < 0) {
6311 replyChainEnd = targetI;
6312 }
6313
6314 } else if (taskTopI >= 0 && allowTaskReparenting
6315 && task.affinity != null
6316 && task.affinity.equals(target.taskAffinity)) {
6317 // We are inside of another task... if this activity has
6318 // an affinity for our task, then either remove it if we are
6319 // clearing or move it over to our task. Note that
6320 // we currently punt on the case where we are resetting a
6321 // task that is not at the top but who has activities above
6322 // with an affinity to it... this is really not a normal
6323 // case, and we will need to later pull that task to the front
6324 // and usually at that point we will do the reset and pick
6325 // up those remaining activities. (This only happens if
6326 // someone starts an activity in a new task from an activity
6327 // in a task that is not currently on top.)
6328 if (forceReset || finishOnTaskLaunch) {
6329 if (replyChainEnd < 0) {
6330 replyChainEnd = targetI;
6331 }
6332 HistoryRecord p = null;
6333 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6334 p = (HistoryRecord)mHistory.get(srcPos);
6335 if (p.finishing) {
6336 continue;
6337 }
6338 if (finishActivityLocked(p, srcPos,
6339 Activity.RESULT_CANCELED, null, "reset")) {
6340 taskTopI--;
6341 lastReparentPos--;
6342 replyChainEnd--;
6343 srcPos--;
6344 }
6345 }
6346 replyChainEnd = -1;
6347 } else {
6348 if (replyChainEnd < 0) {
6349 replyChainEnd = targetI;
6350 }
6351 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6352 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6353 if (p.finishing) {
6354 continue;
6355 }
6356 if (lastReparentPos < 0) {
6357 lastReparentPos = taskTopI;
6358 taskTop = p;
6359 } else {
6360 lastReparentPos--;
6361 }
6362 mHistory.remove(srcPos);
6363 p.task.numActivities--;
6364 p.task = task;
6365 mHistory.add(lastReparentPos, p);
6366 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6367 + " in to resetting task " + task);
6368 task.numActivities++;
6369 mWindowManager.moveAppToken(lastReparentPos, p);
6370 mWindowManager.setAppGroupId(p, p.task.taskId);
6371 if (VALIDATE_TOKENS) {
6372 mWindowManager.validateAppTokens(mHistory);
6373 }
6374 }
6375 replyChainEnd = -1;
6376
6377 // Now we've moved it in to place... but what if this is
6378 // a singleTop activity and we have put it on top of another
6379 // instance of the same activity? Then we drop the instance
6380 // below so it remains singleTop.
6381 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6382 for (int j=lastReparentPos-1; j>=0; j--) {
6383 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6384 if (p.finishing) {
6385 continue;
6386 }
6387 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6388 if (finishActivityLocked(p, j,
6389 Activity.RESULT_CANCELED, null, "replace")) {
6390 taskTopI--;
6391 lastReparentPos--;
6392 }
6393 }
6394 }
6395 }
6396 }
6397 }
6398
6399 target = below;
6400 targetI = i;
6401 }
6402
6403 return taskTop;
6404 }
6405
6406 /**
6407 * TODO: Add mWatcher hook
6408 */
6409 public void moveTaskToFront(int task) {
6410 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6411 "moveTaskToFront()");
6412
6413 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006414 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6415 Binder.getCallingUid(), "Task to front")) {
6416 return;
6417 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006418 final long origId = Binder.clearCallingIdentity();
6419 try {
6420 int N = mRecentTasks.size();
6421 for (int i=0; i<N; i++) {
6422 TaskRecord tr = mRecentTasks.get(i);
6423 if (tr.taskId == task) {
6424 moveTaskToFrontLocked(tr);
6425 return;
6426 }
6427 }
6428 for (int i=mHistory.size()-1; i>=0; i--) {
6429 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6430 if (hr.task.taskId == task) {
6431 moveTaskToFrontLocked(hr.task);
6432 return;
6433 }
6434 }
6435 } finally {
6436 Binder.restoreCallingIdentity(origId);
6437 }
6438 }
6439 }
6440
6441 private final void moveTaskToFrontLocked(TaskRecord tr) {
6442 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6443
6444 final int task = tr.taskId;
6445 int top = mHistory.size()-1;
6446
6447 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6448 // nothing to do!
6449 return;
6450 }
6451
6452 if (DEBUG_TRANSITION) Log.v(TAG,
6453 "Prepare to front transition: task=" + tr);
6454 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6455
6456 ArrayList moved = new ArrayList();
6457
6458 // Applying the affinities may have removed entries from the history,
6459 // so get the size again.
6460 top = mHistory.size()-1;
6461 int pos = top;
6462
6463 // Shift all activities with this task up to the top
6464 // of the stack, keeping them in the same internal order.
6465 while (pos >= 0) {
6466 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6467 if (localLOGV) Log.v(
6468 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6469 boolean first = true;
6470 if (r.task.taskId == task) {
6471 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6472 mHistory.remove(pos);
6473 mHistory.add(top, r);
6474 moved.add(0, r);
6475 top--;
6476 if (first) {
6477 addRecentTask(r.task);
6478 first = false;
6479 }
6480 }
6481 pos--;
6482 }
6483
6484 mWindowManager.moveAppTokensToTop(moved);
6485 if (VALIDATE_TOKENS) {
6486 mWindowManager.validateAppTokens(mHistory);
6487 }
6488
6489 finishTaskMove(task);
6490 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6491 }
6492
6493 private final void finishTaskMove(int task) {
6494 resumeTopActivityLocked(null);
6495 }
6496
6497 public void moveTaskToBack(int task) {
6498 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6499 "moveTaskToBack()");
6500
6501 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006502 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6503 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6504 Binder.getCallingUid(), "Task to back")) {
6505 return;
6506 }
6507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006508 final long origId = Binder.clearCallingIdentity();
6509 moveTaskToBackLocked(task);
6510 Binder.restoreCallingIdentity(origId);
6511 }
6512 }
6513
6514 /**
6515 * Moves an activity, and all of the other activities within the same task, to the bottom
6516 * of the history stack. The activity's order within the task is unchanged.
6517 *
6518 * @param token A reference to the activity we wish to move
6519 * @param nonRoot If false then this only works if the activity is the root
6520 * of a task; if true it will work for any activity in a task.
6521 * @return Returns true if the move completed, false if not.
6522 */
6523 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6524 synchronized(this) {
6525 final long origId = Binder.clearCallingIdentity();
6526 int taskId = getTaskForActivityLocked(token, !nonRoot);
6527 if (taskId >= 0) {
6528 return moveTaskToBackLocked(taskId);
6529 }
6530 Binder.restoreCallingIdentity(origId);
6531 }
6532 return false;
6533 }
6534
6535 /**
6536 * Worker method for rearranging history stack. Implements the function of moving all
6537 * activities for a specific task (gathering them if disjoint) into a single group at the
6538 * bottom of the stack.
6539 *
6540 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6541 * to premeptively cancel the move.
6542 *
6543 * @param task The taskId to collect and move to the bottom.
6544 * @return Returns true if the move completed, false if not.
6545 */
6546 private final boolean moveTaskToBackLocked(int task) {
6547 Log.i(TAG, "moveTaskToBack: " + task);
6548
6549 // If we have a watcher, preflight the move before committing to it. First check
6550 // for *other* available tasks, but if none are available, then try again allowing the
6551 // current task to be selected.
6552 if (mWatcher != null) {
6553 HistoryRecord next = topRunningActivityLocked(null, task);
6554 if (next == null) {
6555 next = topRunningActivityLocked(null, 0);
6556 }
6557 if (next != null) {
6558 // ask watcher if this is allowed
6559 boolean moveOK = true;
6560 try {
6561 moveOK = mWatcher.activityResuming(next.packageName);
6562 } catch (RemoteException e) {
6563 mWatcher = null;
6564 }
6565 if (!moveOK) {
6566 return false;
6567 }
6568 }
6569 }
6570
6571 ArrayList moved = new ArrayList();
6572
6573 if (DEBUG_TRANSITION) Log.v(TAG,
6574 "Prepare to back transition: task=" + task);
6575 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6576
6577 final int N = mHistory.size();
6578 int bottom = 0;
6579 int pos = 0;
6580
6581 // Shift all activities with this task down to the bottom
6582 // of the stack, keeping them in the same internal order.
6583 while (pos < N) {
6584 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6585 if (localLOGV) Log.v(
6586 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6587 if (r.task.taskId == task) {
6588 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6589 mHistory.remove(pos);
6590 mHistory.add(bottom, r);
6591 moved.add(r);
6592 bottom++;
6593 }
6594 pos++;
6595 }
6596
6597 mWindowManager.moveAppTokensToBottom(moved);
6598 if (VALIDATE_TOKENS) {
6599 mWindowManager.validateAppTokens(mHistory);
6600 }
6601
6602 finishTaskMove(task);
6603 return true;
6604 }
6605
6606 public void moveTaskBackwards(int task) {
6607 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6608 "moveTaskBackwards()");
6609
6610 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006611 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6612 Binder.getCallingUid(), "Task backwards")) {
6613 return;
6614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006615 final long origId = Binder.clearCallingIdentity();
6616 moveTaskBackwardsLocked(task);
6617 Binder.restoreCallingIdentity(origId);
6618 }
6619 }
6620
6621 private final void moveTaskBackwardsLocked(int task) {
6622 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6623 }
6624
6625 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6626 synchronized(this) {
6627 return getTaskForActivityLocked(token, onlyRoot);
6628 }
6629 }
6630
6631 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6632 final int N = mHistory.size();
6633 TaskRecord lastTask = null;
6634 for (int i=0; i<N; i++) {
6635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6636 if (r == token) {
6637 if (!onlyRoot || lastTask != r.task) {
6638 return r.task.taskId;
6639 }
6640 return -1;
6641 }
6642 lastTask = r.task;
6643 }
6644
6645 return -1;
6646 }
6647
6648 /**
6649 * Returns the top activity in any existing task matching the given
6650 * Intent. Returns null if no such task is found.
6651 */
6652 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6653 ComponentName cls = intent.getComponent();
6654 if (info.targetActivity != null) {
6655 cls = new ComponentName(info.packageName, info.targetActivity);
6656 }
6657
6658 TaskRecord cp = null;
6659
6660 final int N = mHistory.size();
6661 for (int i=(N-1); i>=0; i--) {
6662 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6663 if (!r.finishing && r.task != cp
6664 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6665 cp = r.task;
6666 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6667 // + "/aff=" + r.task.affinity + " to new cls="
6668 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6669 if (r.task.affinity != null) {
6670 if (r.task.affinity.equals(info.taskAffinity)) {
6671 //Log.i(TAG, "Found matching affinity!");
6672 return r;
6673 }
6674 } else if (r.task.intent != null
6675 && r.task.intent.getComponent().equals(cls)) {
6676 //Log.i(TAG, "Found matching class!");
6677 //dump();
6678 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6679 return r;
6680 } else if (r.task.affinityIntent != null
6681 && r.task.affinityIntent.getComponent().equals(cls)) {
6682 //Log.i(TAG, "Found matching class!");
6683 //dump();
6684 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6685 return r;
6686 }
6687 }
6688 }
6689
6690 return null;
6691 }
6692
6693 /**
6694 * Returns the first activity (starting from the top of the stack) that
6695 * is the same as the given activity. Returns null if no such activity
6696 * is found.
6697 */
6698 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6699 ComponentName cls = intent.getComponent();
6700 if (info.targetActivity != null) {
6701 cls = new ComponentName(info.packageName, info.targetActivity);
6702 }
6703
6704 final int N = mHistory.size();
6705 for (int i=(N-1); i>=0; i--) {
6706 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6707 if (!r.finishing) {
6708 if (r.intent.getComponent().equals(cls)) {
6709 //Log.i(TAG, "Found matching class!");
6710 //dump();
6711 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6712 return r;
6713 }
6714 }
6715 }
6716
6717 return null;
6718 }
6719
6720 public void finishOtherInstances(IBinder token, ComponentName className) {
6721 synchronized(this) {
6722 final long origId = Binder.clearCallingIdentity();
6723
6724 int N = mHistory.size();
6725 TaskRecord lastTask = null;
6726 for (int i=0; i<N; i++) {
6727 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6728 if (r.realActivity.equals(className)
6729 && r != token && lastTask != r.task) {
6730 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6731 null, "others")) {
6732 i--;
6733 N--;
6734 }
6735 }
6736 lastTask = r.task;
6737 }
6738
6739 Binder.restoreCallingIdentity(origId);
6740 }
6741 }
6742
6743 // =========================================================
6744 // THUMBNAILS
6745 // =========================================================
6746
6747 public void reportThumbnail(IBinder token,
6748 Bitmap thumbnail, CharSequence description) {
6749 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6750 final long origId = Binder.clearCallingIdentity();
6751 sendPendingThumbnail(null, token, thumbnail, description, true);
6752 Binder.restoreCallingIdentity(origId);
6753 }
6754
6755 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6756 Bitmap thumbnail, CharSequence description, boolean always) {
6757 TaskRecord task = null;
6758 ArrayList receivers = null;
6759
6760 //System.out.println("Send pending thumbnail: " + r);
6761
6762 synchronized(this) {
6763 if (r == null) {
6764 int index = indexOfTokenLocked(token, false);
6765 if (index < 0) {
6766 return;
6767 }
6768 r = (HistoryRecord)mHistory.get(index);
6769 }
6770 if (thumbnail == null) {
6771 thumbnail = r.thumbnail;
6772 description = r.description;
6773 }
6774 if (thumbnail == null && !always) {
6775 // If there is no thumbnail, and this entry is not actually
6776 // going away, then abort for now and pick up the next
6777 // thumbnail we get.
6778 return;
6779 }
6780 task = r.task;
6781
6782 int N = mPendingThumbnails.size();
6783 int i=0;
6784 while (i<N) {
6785 PendingThumbnailsRecord pr =
6786 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6787 //System.out.println("Looking in " + pr.pendingRecords);
6788 if (pr.pendingRecords.remove(r)) {
6789 if (receivers == null) {
6790 receivers = new ArrayList();
6791 }
6792 receivers.add(pr);
6793 if (pr.pendingRecords.size() == 0) {
6794 pr.finished = true;
6795 mPendingThumbnails.remove(i);
6796 N--;
6797 continue;
6798 }
6799 }
6800 i++;
6801 }
6802 }
6803
6804 if (receivers != null) {
6805 final int N = receivers.size();
6806 for (int i=0; i<N; i++) {
6807 try {
6808 PendingThumbnailsRecord pr =
6809 (PendingThumbnailsRecord)receivers.get(i);
6810 pr.receiver.newThumbnail(
6811 task != null ? task.taskId : -1, thumbnail, description);
6812 if (pr.finished) {
6813 pr.receiver.finished();
6814 }
6815 } catch (Exception e) {
6816 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6817 }
6818 }
6819 }
6820 }
6821
6822 // =========================================================
6823 // CONTENT PROVIDERS
6824 // =========================================================
6825
6826 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6827 List providers = null;
6828 try {
6829 providers = ActivityThread.getPackageManager().
6830 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006831 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006832 } catch (RemoteException ex) {
6833 }
6834 if (providers != null) {
6835 final int N = providers.size();
6836 for (int i=0; i<N; i++) {
6837 ProviderInfo cpi =
6838 (ProviderInfo)providers.get(i);
6839 ContentProviderRecord cpr =
6840 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6841 if (cpr == null) {
6842 cpr = new ContentProviderRecord(cpi, app.info);
6843 mProvidersByClass.put(cpi.name, cpr);
6844 }
6845 app.pubProviders.put(cpi.name, cpr);
6846 app.addPackage(cpi.applicationInfo.packageName);
6847 }
6848 }
6849 return providers;
6850 }
6851
6852 private final String checkContentProviderPermissionLocked(
6853 ProviderInfo cpi, ProcessRecord r, int mode) {
6854 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6855 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6856 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6857 cpi.exported ? -1 : cpi.applicationInfo.uid)
6858 == PackageManager.PERMISSION_GRANTED
6859 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6860 return null;
6861 }
6862 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6863 cpi.exported ? -1 : cpi.applicationInfo.uid)
6864 == PackageManager.PERMISSION_GRANTED) {
6865 return null;
6866 }
6867 String msg = "Permission Denial: opening provider " + cpi.name
6868 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6869 + ", uid=" + callingUid + ") requires "
6870 + cpi.readPermission + " or " + cpi.writePermission;
6871 Log.w(TAG, msg);
6872 return msg;
6873 }
6874
6875 private final ContentProviderHolder getContentProviderImpl(
6876 IApplicationThread caller, String name) {
6877 ContentProviderRecord cpr;
6878 ProviderInfo cpi = null;
6879
6880 synchronized(this) {
6881 ProcessRecord r = null;
6882 if (caller != null) {
6883 r = getRecordForAppLocked(caller);
6884 if (r == null) {
6885 throw new SecurityException(
6886 "Unable to find app for caller " + caller
6887 + " (pid=" + Binder.getCallingPid()
6888 + ") when getting content provider " + name);
6889 }
6890 }
6891
6892 // First check if this content provider has been published...
6893 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6894 if (cpr != null) {
6895 cpi = cpr.info;
6896 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6897 return new ContentProviderHolder(cpi,
6898 cpi.readPermission != null
6899 ? cpi.readPermission : cpi.writePermission);
6900 }
6901
6902 if (r != null && cpr.canRunHere(r)) {
6903 // This provider has been published or is in the process
6904 // of being published... but it is also allowed to run
6905 // in the caller's process, so don't make a connection
6906 // and just let the caller instantiate its own instance.
6907 if (cpr.provider != null) {
6908 // don't give caller the provider object, it needs
6909 // to make its own.
6910 cpr = new ContentProviderRecord(cpr);
6911 }
6912 return cpr;
6913 }
6914
6915 final long origId = Binder.clearCallingIdentity();
6916
6917 // In this case the provider is a single instance, so we can
6918 // return it right away.
6919 if (r != null) {
6920 r.conProviders.add(cpr);
6921 cpr.clients.add(r);
6922 } else {
6923 cpr.externals++;
6924 }
6925
6926 if (cpr.app != null) {
6927 updateOomAdjLocked(cpr.app);
6928 }
6929
6930 Binder.restoreCallingIdentity(origId);
6931
6932 } else {
6933 try {
6934 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07006935 resolveContentProvider(name,
6936 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006937 } catch (RemoteException ex) {
6938 }
6939 if (cpi == null) {
6940 return null;
6941 }
6942
6943 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6944 return new ContentProviderHolder(cpi,
6945 cpi.readPermission != null
6946 ? cpi.readPermission : cpi.writePermission);
6947 }
6948
6949 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6950 final boolean firstClass = cpr == null;
6951 if (firstClass) {
6952 try {
6953 ApplicationInfo ai =
6954 ActivityThread.getPackageManager().
6955 getApplicationInfo(
6956 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006957 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006958 if (ai == null) {
6959 Log.w(TAG, "No package info for content provider "
6960 + cpi.name);
6961 return null;
6962 }
6963 cpr = new ContentProviderRecord(cpi, ai);
6964 } catch (RemoteException ex) {
6965 // pm is in same process, this will never happen.
6966 }
6967 }
6968
6969 if (r != null && cpr.canRunHere(r)) {
6970 // If this is a multiprocess provider, then just return its
6971 // info and allow the caller to instantiate it. Only do
6972 // this if the provider is the same user as the caller's
6973 // process, or can run as root (so can be in any process).
6974 return cpr;
6975 }
6976
6977 if (false) {
6978 RuntimeException e = new RuntimeException("foo");
6979 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
6980 // + " pruid " + ai.uid + "): " + cpi.className, e);
6981 }
6982
6983 // This is single process, and our app is now connecting to it.
6984 // See if we are already in the process of launching this
6985 // provider.
6986 final int N = mLaunchingProviders.size();
6987 int i;
6988 for (i=0; i<N; i++) {
6989 if (mLaunchingProviders.get(i) == cpr) {
6990 break;
6991 }
6992 if (false) {
6993 final ContentProviderRecord rec =
6994 (ContentProviderRecord)mLaunchingProviders.get(i);
6995 if (rec.info.name.equals(cpr.info.name)) {
6996 cpr = rec;
6997 break;
6998 }
6999 }
7000 }
7001
7002 // If the provider is not already being launched, then get it
7003 // started.
7004 if (i >= N) {
7005 final long origId = Binder.clearCallingIdentity();
7006 ProcessRecord proc = startProcessLocked(cpi.processName,
7007 cpr.appInfo, false, 0, "content provider",
7008 new ComponentName(cpi.applicationInfo.packageName,
7009 cpi.name));
7010 if (proc == null) {
7011 Log.w(TAG, "Unable to launch app "
7012 + cpi.applicationInfo.packageName + "/"
7013 + cpi.applicationInfo.uid + " for provider "
7014 + name + ": process is bad");
7015 return null;
7016 }
7017 cpr.launchingApp = proc;
7018 mLaunchingProviders.add(cpr);
7019 Binder.restoreCallingIdentity(origId);
7020 }
7021
7022 // Make sure the provider is published (the same provider class
7023 // may be published under multiple names).
7024 if (firstClass) {
7025 mProvidersByClass.put(cpi.name, cpr);
7026 }
7027 mProvidersByName.put(name, cpr);
7028
7029 if (r != null) {
7030 r.conProviders.add(cpr);
7031 cpr.clients.add(r);
7032 } else {
7033 cpr.externals++;
7034 }
7035 }
7036 }
7037
7038 // Wait for the provider to be published...
7039 synchronized (cpr) {
7040 while (cpr.provider == null) {
7041 if (cpr.launchingApp == null) {
7042 Log.w(TAG, "Unable to launch app "
7043 + cpi.applicationInfo.packageName + "/"
7044 + cpi.applicationInfo.uid + " for provider "
7045 + name + ": launching app became null");
7046 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7047 cpi.applicationInfo.packageName,
7048 cpi.applicationInfo.uid, name);
7049 return null;
7050 }
7051 try {
7052 cpr.wait();
7053 } catch (InterruptedException ex) {
7054 }
7055 }
7056 }
7057 return cpr;
7058 }
7059
7060 public final ContentProviderHolder getContentProvider(
7061 IApplicationThread caller, String name) {
7062 if (caller == null) {
7063 String msg = "null IApplicationThread when getting content provider "
7064 + name;
7065 Log.w(TAG, msg);
7066 throw new SecurityException(msg);
7067 }
7068
7069 return getContentProviderImpl(caller, name);
7070 }
7071
7072 private ContentProviderHolder getContentProviderExternal(String name) {
7073 return getContentProviderImpl(null, name);
7074 }
7075
7076 /**
7077 * Drop a content provider from a ProcessRecord's bookkeeping
7078 * @param cpr
7079 */
7080 public void removeContentProvider(IApplicationThread caller, String name) {
7081 synchronized (this) {
7082 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7083 if(cpr == null) {
7084 //remove from mProvidersByClass
7085 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7086 return;
7087 }
7088 final ProcessRecord r = getRecordForAppLocked(caller);
7089 if (r == null) {
7090 throw new SecurityException(
7091 "Unable to find app for caller " + caller +
7092 " when removing content provider " + name);
7093 }
7094 //update content provider record entry info
7095 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7096 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7097 r.info.processName+" from process "+localCpr.appInfo.processName);
7098 if(localCpr.appInfo.processName == r.info.processName) {
7099 //should not happen. taken care of as a local provider
7100 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7101 return;
7102 } else {
7103 localCpr.clients.remove(r);
7104 r.conProviders.remove(localCpr);
7105 }
7106 updateOomAdjLocked();
7107 }
7108 }
7109
7110 private void removeContentProviderExternal(String name) {
7111 synchronized (this) {
7112 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7113 if(cpr == null) {
7114 //remove from mProvidersByClass
7115 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7116 return;
7117 }
7118
7119 //update content provider record entry info
7120 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7121 localCpr.externals--;
7122 if (localCpr.externals < 0) {
7123 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7124 }
7125 updateOomAdjLocked();
7126 }
7127 }
7128
7129 public final void publishContentProviders(IApplicationThread caller,
7130 List<ContentProviderHolder> providers) {
7131 if (providers == null) {
7132 return;
7133 }
7134
7135 synchronized(this) {
7136 final ProcessRecord r = getRecordForAppLocked(caller);
7137 if (r == null) {
7138 throw new SecurityException(
7139 "Unable to find app for caller " + caller
7140 + " (pid=" + Binder.getCallingPid()
7141 + ") when publishing content providers");
7142 }
7143
7144 final long origId = Binder.clearCallingIdentity();
7145
7146 final int N = providers.size();
7147 for (int i=0; i<N; i++) {
7148 ContentProviderHolder src = providers.get(i);
7149 if (src == null || src.info == null || src.provider == null) {
7150 continue;
7151 }
7152 ContentProviderRecord dst =
7153 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7154 if (dst != null) {
7155 mProvidersByClass.put(dst.info.name, dst);
7156 String names[] = dst.info.authority.split(";");
7157 for (int j = 0; j < names.length; j++) {
7158 mProvidersByName.put(names[j], dst);
7159 }
7160
7161 int NL = mLaunchingProviders.size();
7162 int j;
7163 for (j=0; j<NL; j++) {
7164 if (mLaunchingProviders.get(j) == dst) {
7165 mLaunchingProviders.remove(j);
7166 j--;
7167 NL--;
7168 }
7169 }
7170 synchronized (dst) {
7171 dst.provider = src.provider;
7172 dst.app = r;
7173 dst.notifyAll();
7174 }
7175 updateOomAdjLocked(r);
7176 }
7177 }
7178
7179 Binder.restoreCallingIdentity(origId);
7180 }
7181 }
7182
7183 public static final void installSystemProviders() {
7184 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7185 List providers = mSelf.generateApplicationProvidersLocked(app);
7186 mSystemThread.installSystemProviders(providers);
7187 }
7188
7189 // =========================================================
7190 // GLOBAL MANAGEMENT
7191 // =========================================================
7192
7193 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7194 ApplicationInfo info, String customProcess) {
7195 String proc = customProcess != null ? customProcess : info.processName;
7196 BatteryStatsImpl.Uid.Proc ps = null;
7197 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7198 synchronized (stats) {
7199 ps = stats.getProcessStatsLocked(info.uid, proc);
7200 }
7201 return new ProcessRecord(ps, thread, info, proc);
7202 }
7203
7204 final ProcessRecord addAppLocked(ApplicationInfo info) {
7205 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7206
7207 if (app == null) {
7208 app = newProcessRecordLocked(null, info, null);
7209 mProcessNames.put(info.processName, info.uid, app);
7210 updateLRUListLocked(app, true);
7211 }
7212
7213 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7214 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7215 app.persistent = true;
7216 app.maxAdj = CORE_SERVER_ADJ;
7217 }
7218 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7219 mPersistentStartingProcesses.add(app);
7220 startProcessLocked(app, "added application", app.processName);
7221 }
7222
7223 return app;
7224 }
7225
7226 public void unhandledBack() {
7227 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7228 "unhandledBack()");
7229
7230 synchronized(this) {
7231 int count = mHistory.size();
7232 if (Config.LOGD) Log.d(
7233 TAG, "Performing unhandledBack(): stack size = " + count);
7234 if (count > 1) {
7235 final long origId = Binder.clearCallingIdentity();
7236 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7237 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7238 Binder.restoreCallingIdentity(origId);
7239 }
7240 }
7241 }
7242
7243 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7244 String name = uri.getAuthority();
7245 ContentProviderHolder cph = getContentProviderExternal(name);
7246 ParcelFileDescriptor pfd = null;
7247 if (cph != null) {
7248 // We record the binder invoker's uid in thread-local storage before
7249 // going to the content provider to open the file. Later, in the code
7250 // that handles all permissions checks, we look for this uid and use
7251 // that rather than the Activity Manager's own uid. The effect is that
7252 // we do the check against the caller's permissions even though it looks
7253 // to the content provider like the Activity Manager itself is making
7254 // the request.
7255 sCallerIdentity.set(new Identity(
7256 Binder.getCallingPid(), Binder.getCallingUid()));
7257 try {
7258 pfd = cph.provider.openFile(uri, "r");
7259 } catch (FileNotFoundException e) {
7260 // do nothing; pfd will be returned null
7261 } finally {
7262 // Ensure that whatever happens, we clean up the identity state
7263 sCallerIdentity.remove();
7264 }
7265
7266 // We've got the fd now, so we're done with the provider.
7267 removeContentProviderExternal(name);
7268 } else {
7269 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7270 }
7271 return pfd;
7272 }
7273
7274 public void goingToSleep() {
7275 synchronized(this) {
7276 mSleeping = true;
7277 mWindowManager.setEventDispatching(false);
7278
7279 if (mResumedActivity != null) {
7280 pauseIfSleepingLocked();
7281 } else {
7282 Log.w(TAG, "goingToSleep with no resumed activity!");
7283 }
7284 }
7285 }
7286
Dianne Hackborn55280a92009-05-07 15:53:46 -07007287 public boolean shutdown(int timeout) {
7288 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7289 != PackageManager.PERMISSION_GRANTED) {
7290 throw new SecurityException("Requires permission "
7291 + android.Manifest.permission.SHUTDOWN);
7292 }
7293
7294 boolean timedout = false;
7295
7296 synchronized(this) {
7297 mShuttingDown = true;
7298 mWindowManager.setEventDispatching(false);
7299
7300 if (mResumedActivity != null) {
7301 pauseIfSleepingLocked();
7302 final long endTime = System.currentTimeMillis() + timeout;
7303 while (mResumedActivity != null || mPausingActivity != null) {
7304 long delay = endTime - System.currentTimeMillis();
7305 if (delay <= 0) {
7306 Log.w(TAG, "Activity manager shutdown timed out");
7307 timedout = true;
7308 break;
7309 }
7310 try {
7311 this.wait();
7312 } catch (InterruptedException e) {
7313 }
7314 }
7315 }
7316 }
7317
7318 mUsageStatsService.shutdown();
7319 mBatteryStatsService.shutdown();
7320
7321 return timedout;
7322 }
7323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007324 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007325 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007326 if (!mGoingToSleep.isHeld()) {
7327 mGoingToSleep.acquire();
7328 if (mLaunchingActivity.isHeld()) {
7329 mLaunchingActivity.release();
7330 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7331 }
7332 }
7333
7334 // If we are not currently pausing an activity, get the current
7335 // one to pause. If we are pausing one, we will just let that stuff
7336 // run and release the wake lock when all done.
7337 if (mPausingActivity == null) {
7338 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7339 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7340 startPausingLocked(false, true);
7341 }
7342 }
7343 }
7344
7345 public void wakingUp() {
7346 synchronized(this) {
7347 if (mGoingToSleep.isHeld()) {
7348 mGoingToSleep.release();
7349 }
7350 mWindowManager.setEventDispatching(true);
7351 mSleeping = false;
7352 resumeTopActivityLocked(null);
7353 }
7354 }
7355
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007356 public void stopAppSwitches() {
7357 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7358 != PackageManager.PERMISSION_GRANTED) {
7359 throw new SecurityException("Requires permission "
7360 + android.Manifest.permission.STOP_APP_SWITCHES);
7361 }
7362
7363 synchronized(this) {
7364 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7365 + APP_SWITCH_DELAY_TIME;
7366 mDidAppSwitch = false;
7367 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7368 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7369 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7370 }
7371 }
7372
7373 public void resumeAppSwitches() {
7374 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7375 != PackageManager.PERMISSION_GRANTED) {
7376 throw new SecurityException("Requires permission "
7377 + android.Manifest.permission.STOP_APP_SWITCHES);
7378 }
7379
7380 synchronized(this) {
7381 // Note that we don't execute any pending app switches... we will
7382 // let those wait until either the timeout, or the next start
7383 // activity request.
7384 mAppSwitchesAllowedTime = 0;
7385 }
7386 }
7387
7388 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7389 String name) {
7390 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7391 return true;
7392 }
7393
7394 final int perm = checkComponentPermission(
7395 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7396 callingUid, -1);
7397 if (perm == PackageManager.PERMISSION_GRANTED) {
7398 return true;
7399 }
7400
7401 Log.w(TAG, name + " request from " + callingUid + " stopped");
7402 return false;
7403 }
7404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007405 public void setDebugApp(String packageName, boolean waitForDebugger,
7406 boolean persistent) {
7407 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7408 "setDebugApp()");
7409
7410 // Note that this is not really thread safe if there are multiple
7411 // callers into it at the same time, but that's not a situation we
7412 // care about.
7413 if (persistent) {
7414 final ContentResolver resolver = mContext.getContentResolver();
7415 Settings.System.putString(
7416 resolver, Settings.System.DEBUG_APP,
7417 packageName);
7418 Settings.System.putInt(
7419 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7420 waitForDebugger ? 1 : 0);
7421 }
7422
7423 synchronized (this) {
7424 if (!persistent) {
7425 mOrigDebugApp = mDebugApp;
7426 mOrigWaitForDebugger = mWaitForDebugger;
7427 }
7428 mDebugApp = packageName;
7429 mWaitForDebugger = waitForDebugger;
7430 mDebugTransient = !persistent;
7431 if (packageName != null) {
7432 final long origId = Binder.clearCallingIdentity();
7433 uninstallPackageLocked(packageName, -1, false);
7434 Binder.restoreCallingIdentity(origId);
7435 }
7436 }
7437 }
7438
7439 public void setAlwaysFinish(boolean enabled) {
7440 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7441 "setAlwaysFinish()");
7442
7443 Settings.System.putInt(
7444 mContext.getContentResolver(),
7445 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7446
7447 synchronized (this) {
7448 mAlwaysFinishActivities = enabled;
7449 }
7450 }
7451
7452 public void setActivityWatcher(IActivityWatcher watcher) {
7453 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7454 "setActivityWatcher()");
7455 synchronized (this) {
7456 mWatcher = watcher;
7457 }
7458 }
7459
7460 public final void enterSafeMode() {
7461 synchronized(this) {
7462 // It only makes sense to do this before the system is ready
7463 // and started launching other packages.
7464 if (!mSystemReady) {
7465 try {
7466 ActivityThread.getPackageManager().enterSafeMode();
7467 } catch (RemoteException e) {
7468 }
7469
7470 View v = LayoutInflater.from(mContext).inflate(
7471 com.android.internal.R.layout.safe_mode, null);
7472 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7473 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7474 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7475 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7476 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7477 lp.format = v.getBackground().getOpacity();
7478 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7479 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7480 ((WindowManager)mContext.getSystemService(
7481 Context.WINDOW_SERVICE)).addView(v, lp);
7482 }
7483 }
7484 }
7485
7486 public void noteWakeupAlarm(IIntentSender sender) {
7487 if (!(sender instanceof PendingIntentRecord)) {
7488 return;
7489 }
7490 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7491 synchronized (stats) {
7492 if (mBatteryStatsService.isOnBattery()) {
7493 mBatteryStatsService.enforceCallingPermission();
7494 PendingIntentRecord rec = (PendingIntentRecord)sender;
7495 int MY_UID = Binder.getCallingUid();
7496 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7497 BatteryStatsImpl.Uid.Pkg pkg =
7498 stats.getPackageStatsLocked(uid, rec.key.packageName);
7499 pkg.incWakeupsLocked();
7500 }
7501 }
7502 }
7503
7504 public boolean killPidsForMemory(int[] pids) {
7505 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7506 throw new SecurityException("killPidsForMemory only available to the system");
7507 }
7508
7509 // XXX Note: don't acquire main activity lock here, because the window
7510 // manager calls in with its locks held.
7511
7512 boolean killed = false;
7513 synchronized (mPidsSelfLocked) {
7514 int[] types = new int[pids.length];
7515 int worstType = 0;
7516 for (int i=0; i<pids.length; i++) {
7517 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7518 if (proc != null) {
7519 int type = proc.setAdj;
7520 types[i] = type;
7521 if (type > worstType) {
7522 worstType = type;
7523 }
7524 }
7525 }
7526
7527 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7528 // then constrain it so we will kill all hidden procs.
7529 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7530 worstType = HIDDEN_APP_MIN_ADJ;
7531 }
7532 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7533 for (int i=0; i<pids.length; i++) {
7534 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7535 if (proc == null) {
7536 continue;
7537 }
7538 int adj = proc.setAdj;
7539 if (adj >= worstType) {
7540 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7541 + adj + ")");
7542 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7543 proc.processName, adj);
7544 killed = true;
7545 Process.killProcess(pids[i]);
7546 }
7547 }
7548 }
7549 return killed;
7550 }
7551
7552 public void reportPss(IApplicationThread caller, int pss) {
7553 Watchdog.PssRequestor req;
7554 String name;
7555 ProcessRecord callerApp;
7556 synchronized (this) {
7557 if (caller == null) {
7558 return;
7559 }
7560 callerApp = getRecordForAppLocked(caller);
7561 if (callerApp == null) {
7562 return;
7563 }
7564 callerApp.lastPss = pss;
7565 req = callerApp;
7566 name = callerApp.processName;
7567 }
7568 Watchdog.getInstance().reportPss(req, name, pss);
7569 if (!callerApp.persistent) {
7570 removeRequestedPss(callerApp);
7571 }
7572 }
7573
7574 public void requestPss(Runnable completeCallback) {
7575 ArrayList<ProcessRecord> procs;
7576 synchronized (this) {
7577 mRequestPssCallback = completeCallback;
7578 mRequestPssList.clear();
7579 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7580 ProcessRecord proc = mLRUProcesses.get(i);
7581 if (!proc.persistent) {
7582 mRequestPssList.add(proc);
7583 }
7584 }
7585 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7586 }
7587
7588 int oldPri = Process.getThreadPriority(Process.myTid());
7589 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7590 for (int i=procs.size()-1; i>=0; i--) {
7591 ProcessRecord proc = procs.get(i);
7592 proc.lastPss = 0;
7593 proc.requestPss();
7594 }
7595 Process.setThreadPriority(oldPri);
7596 }
7597
7598 void removeRequestedPss(ProcessRecord proc) {
7599 Runnable callback = null;
7600 synchronized (this) {
7601 if (mRequestPssList.remove(proc)) {
7602 if (mRequestPssList.size() == 0) {
7603 callback = mRequestPssCallback;
7604 mRequestPssCallback = null;
7605 }
7606 }
7607 }
7608
7609 if (callback != null) {
7610 callback.run();
7611 }
7612 }
7613
7614 public void collectPss(Watchdog.PssStats stats) {
7615 stats.mEmptyPss = 0;
7616 stats.mEmptyCount = 0;
7617 stats.mBackgroundPss = 0;
7618 stats.mBackgroundCount = 0;
7619 stats.mServicePss = 0;
7620 stats.mServiceCount = 0;
7621 stats.mVisiblePss = 0;
7622 stats.mVisibleCount = 0;
7623 stats.mForegroundPss = 0;
7624 stats.mForegroundCount = 0;
7625 stats.mNoPssCount = 0;
7626 synchronized (this) {
7627 int i;
7628 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7629 ? mProcDeaths.length : stats.mProcDeaths.length;
7630 int aggr = 0;
7631 for (i=0; i<NPD; i++) {
7632 aggr += mProcDeaths[i];
7633 stats.mProcDeaths[i] = aggr;
7634 }
7635 while (i<stats.mProcDeaths.length) {
7636 stats.mProcDeaths[i] = 0;
7637 i++;
7638 }
7639
7640 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7641 ProcessRecord proc = mLRUProcesses.get(i);
7642 if (proc.persistent) {
7643 continue;
7644 }
7645 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7646 if (proc.lastPss == 0) {
7647 stats.mNoPssCount++;
7648 continue;
7649 }
7650 if (proc.setAdj == EMPTY_APP_ADJ) {
7651 stats.mEmptyPss += proc.lastPss;
7652 stats.mEmptyCount++;
7653 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7654 stats.mEmptyPss += proc.lastPss;
7655 stats.mEmptyCount++;
7656 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7657 stats.mBackgroundPss += proc.lastPss;
7658 stats.mBackgroundCount++;
7659 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7660 stats.mVisiblePss += proc.lastPss;
7661 stats.mVisibleCount++;
7662 } else {
7663 stats.mForegroundPss += proc.lastPss;
7664 stats.mForegroundCount++;
7665 }
7666 }
7667 }
7668 }
7669
7670 public final void startRunning(String pkg, String cls, String action,
7671 String data) {
7672 synchronized(this) {
7673 if (mStartRunning) {
7674 return;
7675 }
7676 mStartRunning = true;
7677 mTopComponent = pkg != null && cls != null
7678 ? new ComponentName(pkg, cls) : null;
7679 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7680 mTopData = data;
7681 if (!mSystemReady) {
7682 return;
7683 }
7684 }
7685
7686 systemReady();
7687 }
7688
7689 private void retrieveSettings() {
7690 final ContentResolver resolver = mContext.getContentResolver();
7691 String debugApp = Settings.System.getString(
7692 resolver, Settings.System.DEBUG_APP);
7693 boolean waitForDebugger = Settings.System.getInt(
7694 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7695 boolean alwaysFinishActivities = Settings.System.getInt(
7696 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7697
7698 Configuration configuration = new Configuration();
7699 Settings.System.getConfiguration(resolver, configuration);
7700
7701 synchronized (this) {
7702 mDebugApp = mOrigDebugApp = debugApp;
7703 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7704 mAlwaysFinishActivities = alwaysFinishActivities;
7705 // This happens before any activities are started, so we can
7706 // change mConfiguration in-place.
7707 mConfiguration.updateFrom(configuration);
7708 }
7709 }
7710
7711 public boolean testIsSystemReady() {
7712 // no need to synchronize(this) just to read & return the value
7713 return mSystemReady;
7714 }
7715
7716 public void systemReady() {
7717 // In the simulator, startRunning will never have been called, which
7718 // normally sets a few crucial variables. Do it here instead.
7719 if (!Process.supportsProcesses()) {
7720 mStartRunning = true;
7721 mTopAction = Intent.ACTION_MAIN;
7722 }
7723
7724 synchronized(this) {
7725 if (mSystemReady) {
7726 return;
7727 }
7728 mSystemReady = true;
7729 if (!mStartRunning) {
7730 return;
7731 }
7732 }
7733
7734 if (Config.LOGD) Log.d(TAG, "Start running!");
7735 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7736 SystemClock.uptimeMillis());
7737
7738 synchronized(this) {
7739 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7740 ResolveInfo ri = mContext.getPackageManager()
7741 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007742 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007743 CharSequence errorMsg = null;
7744 if (ri != null) {
7745 ActivityInfo ai = ri.activityInfo;
7746 ApplicationInfo app = ai.applicationInfo;
7747 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7748 mTopAction = Intent.ACTION_FACTORY_TEST;
7749 mTopData = null;
7750 mTopComponent = new ComponentName(app.packageName,
7751 ai.name);
7752 } else {
7753 errorMsg = mContext.getResources().getText(
7754 com.android.internal.R.string.factorytest_not_system);
7755 }
7756 } else {
7757 errorMsg = mContext.getResources().getText(
7758 com.android.internal.R.string.factorytest_no_action);
7759 }
7760 if (errorMsg != null) {
7761 mTopAction = null;
7762 mTopData = null;
7763 mTopComponent = null;
7764 Message msg = Message.obtain();
7765 msg.what = SHOW_FACTORY_ERROR_MSG;
7766 msg.getData().putCharSequence("msg", errorMsg);
7767 mHandler.sendMessage(msg);
7768 }
7769 }
7770 }
7771
7772 retrieveSettings();
7773
7774 synchronized (this) {
7775 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7776 try {
7777 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007778 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007779 if (apps != null) {
7780 int N = apps.size();
7781 int i;
7782 for (i=0; i<N; i++) {
7783 ApplicationInfo info
7784 = (ApplicationInfo)apps.get(i);
7785 if (info != null &&
7786 !info.packageName.equals("android")) {
7787 addAppLocked(info);
7788 }
7789 }
7790 }
7791 } catch (RemoteException ex) {
7792 // pm is in same process, this will never happen.
7793 }
7794 }
7795
7796 try {
7797 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7798 Message msg = Message.obtain();
7799 msg.what = SHOW_UID_ERROR_MSG;
7800 mHandler.sendMessage(msg);
7801 }
7802 } catch (RemoteException e) {
7803 }
7804
7805 // Start up initial activity.
7806 mBooting = true;
7807 resumeTopActivityLocked(null);
7808 }
7809 }
7810
7811 boolean makeAppCrashingLocked(ProcessRecord app,
7812 String tag, String shortMsg, String longMsg, byte[] crashData) {
7813 app.crashing = true;
7814 app.crashingReport = generateProcessError(app,
7815 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7816 startAppProblemLocked(app);
7817 app.stopFreezingAllLocked();
7818 return handleAppCrashLocked(app);
7819 }
7820
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007821 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7822 IPackageManager pm = ActivityThread.getPackageManager();
7823 try {
7824 // was an installer package name specified when this app was
7825 // installed?
7826 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7827 if (installerPackageName == null) {
7828 return null;
7829 }
7830
7831 // is there an Activity in this package that handles ACTION_APP_ERROR?
7832 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
7833 ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
7834 if (info == null || info.activityInfo == null) {
7835 return null;
7836 }
7837
7838 return new ComponentName(installerPackageName, info.activityInfo.name);
7839 } catch (RemoteException e) {
7840 // will return null and no error report will be delivered
7841 }
7842 return null;
7843 }
7844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007845 void makeAppNotRespondingLocked(ProcessRecord app,
7846 String tag, String shortMsg, String longMsg, byte[] crashData) {
7847 app.notResponding = true;
7848 app.notRespondingReport = generateProcessError(app,
7849 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7850 crashData);
7851 startAppProblemLocked(app);
7852 app.stopFreezingAllLocked();
7853 }
7854
7855 /**
7856 * Generate a process error record, suitable for attachment to a ProcessRecord.
7857 *
7858 * @param app The ProcessRecord in which the error occurred.
7859 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7860 * ActivityManager.AppErrorStateInfo
7861 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7862 * @param shortMsg Short message describing the crash.
7863 * @param longMsg Long message describing the crash.
7864 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7865 *
7866 * @return Returns a fully-formed AppErrorStateInfo record.
7867 */
7868 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7869 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7870 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7871
7872 report.condition = condition;
7873 report.processName = app.processName;
7874 report.pid = app.pid;
7875 report.uid = app.info.uid;
7876 report.tag = tag;
7877 report.shortMsg = shortMsg;
7878 report.longMsg = longMsg;
7879 report.crashData = crashData;
7880
7881 return report;
7882 }
7883
7884 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7885 boolean crashed) {
7886 synchronized (this) {
7887 app.crashing = false;
7888 app.crashingReport = null;
7889 app.notResponding = false;
7890 app.notRespondingReport = null;
7891 if (app.anrDialog == fromDialog) {
7892 app.anrDialog = null;
7893 }
7894 if (app.waitDialog == fromDialog) {
7895 app.waitDialog = null;
7896 }
7897 if (app.pid > 0 && app.pid != MY_PID) {
7898 if (crashed) {
7899 handleAppCrashLocked(app);
7900 }
7901 Log.i(ActivityManagerService.TAG, "Killing process "
7902 + app.processName
7903 + " (pid=" + app.pid + ") at user's request");
7904 Process.killProcess(app.pid);
7905 }
7906
7907 }
7908 }
7909
7910 boolean handleAppCrashLocked(ProcessRecord app) {
7911 long now = SystemClock.uptimeMillis();
7912
7913 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7914 app.info.uid);
7915 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7916 // This process loses!
7917 Log.w(TAG, "Process " + app.info.processName
7918 + " has crashed too many times: killing!");
7919 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7920 app.info.processName, app.info.uid);
7921 killServicesLocked(app, false);
7922 for (int i=mHistory.size()-1; i>=0; i--) {
7923 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7924 if (r.app == app) {
7925 if (Config.LOGD) Log.d(
7926 TAG, " Force finishing activity "
7927 + r.intent.getComponent().flattenToShortString());
7928 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
7929 }
7930 }
7931 if (!app.persistent) {
7932 // We don't want to start this process again until the user
7933 // explicitly does so... but for persistent process, we really
7934 // need to keep it running. If a persistent process is actually
7935 // repeatedly crashing, then badness for everyone.
7936 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
7937 app.info.processName);
7938 mBadProcesses.put(app.info.processName, app.info.uid, now);
7939 app.bad = true;
7940 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
7941 app.removed = true;
7942 removeProcessLocked(app, false);
7943 return false;
7944 }
7945 }
7946
7947 // Bump up the crash count of any services currently running in the proc.
7948 if (app.services.size() != 0) {
7949 // Any services running in the application need to be placed
7950 // back in the pending list.
7951 Iterator it = app.services.iterator();
7952 while (it.hasNext()) {
7953 ServiceRecord sr = (ServiceRecord)it.next();
7954 sr.crashCount++;
7955 }
7956 }
7957
7958 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
7959 return true;
7960 }
7961
7962 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007963 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007964 skipCurrentReceiverLocked(app);
7965 }
7966
7967 void skipCurrentReceiverLocked(ProcessRecord app) {
7968 boolean reschedule = false;
7969 BroadcastRecord r = app.curReceiver;
7970 if (r != null) {
7971 // The current broadcast is waiting for this app's receiver
7972 // to be finished. Looks like that's not going to happen, so
7973 // let the broadcast continue.
7974 logBroadcastReceiverDiscard(r);
7975 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
7976 r.resultExtras, r.resultAbort, true);
7977 reschedule = true;
7978 }
7979 r = mPendingBroadcast;
7980 if (r != null && r.curApp == app) {
7981 if (DEBUG_BROADCAST) Log.v(TAG,
7982 "skip & discard pending app " + r);
7983 logBroadcastReceiverDiscard(r);
7984 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
7985 r.resultExtras, r.resultAbort, true);
7986 reschedule = true;
7987 }
7988 if (reschedule) {
7989 scheduleBroadcastsLocked();
7990 }
7991 }
7992
7993 public int handleApplicationError(IBinder app, int flags,
7994 String tag, String shortMsg, String longMsg, byte[] crashData) {
7995 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007996 ProcessRecord r = null;
7997 synchronized (this) {
7998 if (app != null) {
7999 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8000 final int NA = apps.size();
8001 for (int ia=0; ia<NA; ia++) {
8002 ProcessRecord p = apps.valueAt(ia);
8003 if (p.thread != null && p.thread.asBinder() == app) {
8004 r = p;
8005 break;
8006 }
8007 }
8008 }
8009 }
8010
8011 if (r != null) {
8012 // The application has crashed. Send the SIGQUIT to the process so
8013 // that it can dump its state.
8014 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8015 //Log.i(TAG, "Current system threads:");
8016 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8017 }
8018
8019 if (mWatcher != null) {
8020 try {
8021 String name = r != null ? r.processName : null;
8022 int pid = r != null ? r.pid : Binder.getCallingPid();
8023 if (!mWatcher.appCrashed(name, pid,
8024 shortMsg, longMsg, crashData)) {
8025 Log.w(TAG, "Force-killing crashed app " + name
8026 + " at watcher's request");
8027 Process.killProcess(pid);
8028 return 0;
8029 }
8030 } catch (RemoteException e) {
8031 mWatcher = null;
8032 }
8033 }
8034
8035 final long origId = Binder.clearCallingIdentity();
8036
8037 // If this process is running instrumentation, finish it.
8038 if (r != null && r.instrumentationClass != null) {
8039 Log.w(TAG, "Error in app " + r.processName
8040 + " running instrumentation " + r.instrumentationClass + ":");
8041 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8042 if (longMsg != null) Log.w(TAG, " " + longMsg);
8043 Bundle info = new Bundle();
8044 info.putString("shortMsg", shortMsg);
8045 info.putString("longMsg", longMsg);
8046 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8047 Binder.restoreCallingIdentity(origId);
8048 return 0;
8049 }
8050
8051 if (r != null) {
8052 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8053 return 0;
8054 }
8055 } else {
8056 Log.w(TAG, "Some application object " + app + " tag " + tag
8057 + " has crashed, but I don't know who it is.");
8058 Log.w(TAG, "ShortMsg:" + shortMsg);
8059 Log.w(TAG, "LongMsg:" + longMsg);
8060 Binder.restoreCallingIdentity(origId);
8061 return 0;
8062 }
8063
8064 Message msg = Message.obtain();
8065 msg.what = SHOW_ERROR_MSG;
8066 HashMap data = new HashMap();
8067 data.put("result", result);
8068 data.put("app", r);
8069 data.put("flags", flags);
8070 data.put("shortMsg", shortMsg);
8071 data.put("longMsg", longMsg);
8072 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8073 // For system processes, submit crash data to the server.
8074 data.put("crashData", crashData);
8075 }
8076 msg.obj = data;
8077 mHandler.sendMessage(msg);
8078
8079 Binder.restoreCallingIdentity(origId);
8080 }
8081
8082 int res = result.get();
8083
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008084 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008085 synchronized (this) {
8086 if (r != null) {
8087 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8088 SystemClock.uptimeMillis());
8089 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008090 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8091 appErrorIntent = createAppErrorIntentLocked(r);
8092 res = AppErrorDialog.FORCE_QUIT;
8093 }
8094 }
8095
8096 if (appErrorIntent != null) {
8097 try {
8098 mContext.startActivity(appErrorIntent);
8099 } catch (ActivityNotFoundException e) {
8100 Log.w(TAG, "bug report receiver dissappeared", e);
8101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008102 }
8103
8104 return res;
8105 }
8106
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008107 Intent createAppErrorIntentLocked(ProcessRecord r) {
8108 ApplicationErrorReport report = createAppErrorReportLocked(r);
8109 if (report == null) {
8110 return null;
8111 }
8112 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8113 result.setComponent(r.errorReportReceiver);
8114 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8115 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8116 return result;
8117 }
8118
8119 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8120 if (r.errorReportReceiver == null) {
8121 return null;
8122 }
8123
8124 if (!r.crashing && !r.notResponding) {
8125 return null;
8126 }
8127
8128 try {
8129 ApplicationErrorReport report = new ApplicationErrorReport();
8130 report.packageName = r.info.packageName;
8131 report.installerPackageName = r.errorReportReceiver.getPackageName();
8132 report.processName = r.processName;
8133
8134 if (r.crashing) {
8135 report.type = ApplicationErrorReport.TYPE_CRASH;
8136 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8137
8138 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8139 r.crashingReport.crashData);
8140 DataInputStream dataStream = new DataInputStream(byteStream);
8141 CrashData crashData = new CrashData(dataStream);
8142 ThrowableData throwData = crashData.getThrowableData();
8143
8144 report.time = crashData.getTime();
8145 report.crashInfo.stackTrace = throwData.toString();
8146
8147 // extract the source of the exception, useful for report
8148 // clustering
8149 while (throwData.getCause() != null) {
8150 throwData = throwData.getCause();
8151 }
8152 StackTraceElementData trace = throwData.getStackTrace()[0];
8153 report.crashInfo.exceptionClassName = throwData.getType();
8154 report.crashInfo.throwFileName = trace.getFileName();
8155 report.crashInfo.throwClassName = trace.getClassName();
8156 report.crashInfo.throwMethodName = trace.getMethodName();
8157 } else if (r.notResponding) {
8158 report.type = ApplicationErrorReport.TYPE_ANR;
8159 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8160
8161 report.anrInfo.activity = r.notRespondingReport.tag;
8162 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8163 report.anrInfo.info = r.notRespondingReport.longMsg;
8164 }
8165
8166 return report;
8167 } catch (IOException e) {
8168 // we don't send it
8169 }
8170
8171 return null;
8172 }
8173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008174 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8175 // assume our apps are happy - lazy create the list
8176 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8177
8178 synchronized (this) {
8179
8180 // iterate across all processes
8181 final int N = mLRUProcesses.size();
8182 for (int i = 0; i < N; i++) {
8183 ProcessRecord app = mLRUProcesses.get(i);
8184 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8185 // This one's in trouble, so we'll generate a report for it
8186 // crashes are higher priority (in case there's a crash *and* an anr)
8187 ActivityManager.ProcessErrorStateInfo report = null;
8188 if (app.crashing) {
8189 report = app.crashingReport;
8190 } else if (app.notResponding) {
8191 report = app.notRespondingReport;
8192 }
8193
8194 if (report != null) {
8195 if (errList == null) {
8196 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8197 }
8198 errList.add(report);
8199 } else {
8200 Log.w(TAG, "Missing app error report, app = " + app.processName +
8201 " crashing = " + app.crashing +
8202 " notResponding = " + app.notResponding);
8203 }
8204 }
8205 }
8206 }
8207
8208 return errList;
8209 }
8210
8211 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8212 // Lazy instantiation of list
8213 List<ActivityManager.RunningAppProcessInfo> runList = null;
8214 synchronized (this) {
8215 // Iterate across all processes
8216 final int N = mLRUProcesses.size();
8217 for (int i = 0; i < N; i++) {
8218 ProcessRecord app = mLRUProcesses.get(i);
8219 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8220 // Generate process state info for running application
8221 ActivityManager.RunningAppProcessInfo currApp =
8222 new ActivityManager.RunningAppProcessInfo(app.processName,
8223 app.pid, app.getPackageList());
8224 int adj = app.curAdj;
8225 if (adj >= CONTENT_PROVIDER_ADJ) {
8226 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8227 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8228 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008229 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8230 } else if (adj >= HOME_APP_ADJ) {
8231 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8232 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008233 } else if (adj >= SECONDARY_SERVER_ADJ) {
8234 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8235 } else if (adj >= VISIBLE_APP_ADJ) {
8236 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8237 } else {
8238 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8239 }
8240 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8241 // + " lru=" + currApp.lru);
8242 if (runList == null) {
8243 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8244 }
8245 runList.add(currApp);
8246 }
8247 }
8248 }
8249 return runList;
8250 }
8251
8252 @Override
8253 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8254 synchronized (this) {
8255 if (checkCallingPermission(android.Manifest.permission.DUMP)
8256 != PackageManager.PERMISSION_GRANTED) {
8257 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8258 + Binder.getCallingPid()
8259 + ", uid=" + Binder.getCallingUid()
8260 + " without permission "
8261 + android.Manifest.permission.DUMP);
8262 return;
8263 }
8264 if (args.length != 0 && "service".equals(args[0])) {
8265 dumpService(fd, pw, args);
8266 return;
8267 }
8268 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008269 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008270 pw.println(" ");
8271 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008272 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008273 if (mWaitingVisibleActivities.size() > 0) {
8274 pw.println(" ");
8275 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008276 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008277 }
8278 if (mStoppingActivities.size() > 0) {
8279 pw.println(" ");
8280 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008281 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008282 }
8283 if (mFinishingActivities.size() > 0) {
8284 pw.println(" ");
8285 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008286 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008287 }
8288
8289 pw.println(" ");
8290 pw.println(" mPausingActivity: " + mPausingActivity);
8291 pw.println(" mResumedActivity: " + mResumedActivity);
8292 pw.println(" mFocusedActivity: " + mFocusedActivity);
8293 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8294
8295 if (mRecentTasks.size() > 0) {
8296 pw.println(" ");
8297 pw.println("Recent tasks in Current Activity Manager State:");
8298
8299 final int N = mRecentTasks.size();
8300 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008301 TaskRecord tr = mRecentTasks.get(i);
8302 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8303 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008304 mRecentTasks.get(i).dump(pw, " ");
8305 }
8306 }
8307
8308 pw.println(" ");
8309 pw.println(" mCurTask: " + mCurTask);
8310
8311 pw.println(" ");
8312 pw.println("Processes in Current Activity Manager State:");
8313
8314 boolean needSep = false;
8315 int numPers = 0;
8316
8317 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8318 final int NA = procs.size();
8319 for (int ia=0; ia<NA; ia++) {
8320 if (!needSep) {
8321 pw.println(" All known processes:");
8322 needSep = true;
8323 }
8324 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008325 pw.print(r.persistent ? " *PERS*" : " *APP*");
8326 pw.print(" UID "); pw.print(procs.keyAt(ia));
8327 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008328 r.dump(pw, " ");
8329 if (r.persistent) {
8330 numPers++;
8331 }
8332 }
8333 }
8334
8335 if (mLRUProcesses.size() > 0) {
8336 if (needSep) pw.println(" ");
8337 needSep = true;
8338 pw.println(" Running processes (most recent first):");
8339 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008340 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008341 needSep = true;
8342 }
8343
8344 synchronized (mPidsSelfLocked) {
8345 if (mPidsSelfLocked.size() > 0) {
8346 if (needSep) pw.println(" ");
8347 needSep = true;
8348 pw.println(" PID mappings:");
8349 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008350 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8351 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008352 }
8353 }
8354 }
8355
8356 if (mForegroundProcesses.size() > 0) {
8357 if (needSep) pw.println(" ");
8358 needSep = true;
8359 pw.println(" Foreground Processes:");
8360 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008361 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8362 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008363 }
8364 }
8365
8366 if (mPersistentStartingProcesses.size() > 0) {
8367 if (needSep) pw.println(" ");
8368 needSep = true;
8369 pw.println(" Persisent processes that are starting:");
8370 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008371 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008372 }
8373
8374 if (mStartingProcesses.size() > 0) {
8375 if (needSep) pw.println(" ");
8376 needSep = true;
8377 pw.println(" Processes that are starting:");
8378 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008379 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008380 }
8381
8382 if (mRemovedProcesses.size() > 0) {
8383 if (needSep) pw.println(" ");
8384 needSep = true;
8385 pw.println(" Processes that are being removed:");
8386 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008387 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008388 }
8389
8390 if (mProcessesOnHold.size() > 0) {
8391 if (needSep) pw.println(" ");
8392 needSep = true;
8393 pw.println(" Processes that are on old until the system is ready:");
8394 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008395 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008396 }
8397
8398 if (mProcessCrashTimes.getMap().size() > 0) {
8399 if (needSep) pw.println(" ");
8400 needSep = true;
8401 pw.println(" Time since processes crashed:");
8402 long now = SystemClock.uptimeMillis();
8403 for (Map.Entry<String, SparseArray<Long>> procs
8404 : mProcessCrashTimes.getMap().entrySet()) {
8405 SparseArray<Long> uids = procs.getValue();
8406 final int N = uids.size();
8407 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008408 pw.print(" Process "); pw.print(procs.getKey());
8409 pw.print(" uid "); pw.print(uids.keyAt(i));
8410 pw.print(": last crashed ");
8411 pw.print((now-uids.valueAt(i)));
8412 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 }
8414 }
8415 }
8416
8417 if (mBadProcesses.getMap().size() > 0) {
8418 if (needSep) pw.println(" ");
8419 needSep = true;
8420 pw.println(" Bad processes:");
8421 for (Map.Entry<String, SparseArray<Long>> procs
8422 : mBadProcesses.getMap().entrySet()) {
8423 SparseArray<Long> uids = procs.getValue();
8424 final int N = uids.size();
8425 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008426 pw.print(" Bad process "); pw.print(procs.getKey());
8427 pw.print(" uid "); pw.print(uids.keyAt(i));
8428 pw.print(": crashed at time ");
8429 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008430 }
8431 }
8432 }
8433
8434 pw.println(" ");
8435 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008436 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008437 pw.println(" mConfiguration: " + mConfiguration);
8438 pw.println(" mStartRunning=" + mStartRunning
8439 + " mSystemReady=" + mSystemReady
8440 + " mBooting=" + mBooting
8441 + " mBooted=" + mBooted
8442 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008443 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008444 pw.println(" mGoingToSleep=" + mGoingToSleep);
8445 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8446 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8447 + " mDebugTransient=" + mDebugTransient
8448 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8449 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8450 + " mWatcher=" + mWatcher);
8451 }
8452 }
8453
8454 /**
8455 * There are three ways to call this:
8456 * - no service specified: dump all the services
8457 * - a flattened component name that matched an existing service was specified as the
8458 * first arg: dump that one service
8459 * - the first arg isn't the flattened component name of an existing service:
8460 * dump all services whose component contains the first arg as a substring
8461 */
8462 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8463 String[] newArgs;
8464 String componentNameString;
8465 ServiceRecord r;
8466 if (args.length == 1) {
8467 componentNameString = null;
8468 newArgs = EMPTY_STRING_ARRAY;
8469 r = null;
8470 } else {
8471 componentNameString = args[1];
8472 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8473 r = componentName != null ? mServices.get(componentName) : null;
8474 newArgs = new String[args.length - 2];
8475 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8476 }
8477
8478 if (r != null) {
8479 dumpService(fd, pw, r, newArgs);
8480 } else {
8481 for (ServiceRecord r1 : mServices.values()) {
8482 if (componentNameString == null
8483 || r1.name.flattenToString().contains(componentNameString)) {
8484 dumpService(fd, pw, r1, newArgs);
8485 }
8486 }
8487 }
8488 }
8489
8490 /**
8491 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8492 * there is a thread associated with the service.
8493 */
8494 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8495 pw.println(" Service " + r.name.flattenToString());
8496 if (r.app != null && r.app.thread != null) {
8497 try {
8498 // flush anything that is already in the PrintWriter since the thread is going
8499 // to write to the file descriptor directly
8500 pw.flush();
8501 r.app.thread.dumpService(fd, r, args);
8502 pw.print("\n");
8503 } catch (RemoteException e) {
8504 pw.println("got a RemoteException while dumping the service");
8505 }
8506 }
8507 }
8508
8509 void dumpBroadcasts(PrintWriter pw) {
8510 synchronized (this) {
8511 if (checkCallingPermission(android.Manifest.permission.DUMP)
8512 != PackageManager.PERMISSION_GRANTED) {
8513 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8514 + Binder.getCallingPid()
8515 + ", uid=" + Binder.getCallingUid()
8516 + " without permission "
8517 + android.Manifest.permission.DUMP);
8518 return;
8519 }
8520 pw.println("Broadcasts in Current Activity Manager State:");
8521
8522 if (mRegisteredReceivers.size() > 0) {
8523 pw.println(" ");
8524 pw.println(" Registered Receivers:");
8525 Iterator it = mRegisteredReceivers.values().iterator();
8526 while (it.hasNext()) {
8527 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008528 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008529 r.dump(pw, " ");
8530 }
8531 }
8532
8533 pw.println(" ");
8534 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008535 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008536
8537 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8538 || mPendingBroadcast != null) {
8539 if (mParallelBroadcasts.size() > 0) {
8540 pw.println(" ");
8541 pw.println(" Active broadcasts:");
8542 }
8543 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8544 pw.println(" Broadcast #" + i + ":");
8545 mParallelBroadcasts.get(i).dump(pw, " ");
8546 }
8547 if (mOrderedBroadcasts.size() > 0) {
8548 pw.println(" ");
8549 pw.println(" Active serialized broadcasts:");
8550 }
8551 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8552 pw.println(" Serialized Broadcast #" + i + ":");
8553 mOrderedBroadcasts.get(i).dump(pw, " ");
8554 }
8555 pw.println(" ");
8556 pw.println(" Pending broadcast:");
8557 if (mPendingBroadcast != null) {
8558 mPendingBroadcast.dump(pw, " ");
8559 } else {
8560 pw.println(" (null)");
8561 }
8562 }
8563
8564 pw.println(" ");
8565 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8566 if (mStickyBroadcasts != null) {
8567 pw.println(" ");
8568 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008569 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008570 for (Map.Entry<String, ArrayList<Intent>> ent
8571 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008572 pw.print(" * Sticky action "); pw.print(ent.getKey());
8573 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008574 ArrayList<Intent> intents = ent.getValue();
8575 final int N = intents.size();
8576 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008577 sb.setLength(0);
8578 sb.append(" Intent: ");
8579 intents.get(i).toShortString(sb, true, false);
8580 pw.println(sb.toString());
8581 Bundle bundle = intents.get(i).getExtras();
8582 if (bundle != null) {
8583 pw.print(" ");
8584 pw.println(bundle.toString());
8585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008586 }
8587 }
8588 }
8589
8590 pw.println(" ");
8591 pw.println(" mHandler:");
8592 mHandler.dump(new PrintWriterPrinter(pw), " ");
8593 }
8594 }
8595
8596 void dumpServices(PrintWriter pw) {
8597 synchronized (this) {
8598 if (checkCallingPermission(android.Manifest.permission.DUMP)
8599 != PackageManager.PERMISSION_GRANTED) {
8600 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8601 + Binder.getCallingPid()
8602 + ", uid=" + Binder.getCallingUid()
8603 + " without permission "
8604 + android.Manifest.permission.DUMP);
8605 return;
8606 }
8607 pw.println("Services in Current Activity Manager State:");
8608
8609 boolean needSep = false;
8610
8611 if (mServices.size() > 0) {
8612 pw.println(" Active services:");
8613 Iterator<ServiceRecord> it = mServices.values().iterator();
8614 while (it.hasNext()) {
8615 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008616 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 r.dump(pw, " ");
8618 }
8619 needSep = true;
8620 }
8621
8622 if (mPendingServices.size() > 0) {
8623 if (needSep) pw.println(" ");
8624 pw.println(" Pending services:");
8625 for (int i=0; i<mPendingServices.size(); i++) {
8626 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008627 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008628 r.dump(pw, " ");
8629 }
8630 needSep = true;
8631 }
8632
8633 if (mRestartingServices.size() > 0) {
8634 if (needSep) pw.println(" ");
8635 pw.println(" Restarting services:");
8636 for (int i=0; i<mRestartingServices.size(); i++) {
8637 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008638 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008639 r.dump(pw, " ");
8640 }
8641 needSep = true;
8642 }
8643
8644 if (mStoppingServices.size() > 0) {
8645 if (needSep) pw.println(" ");
8646 pw.println(" Stopping services:");
8647 for (int i=0; i<mStoppingServices.size(); i++) {
8648 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008649 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008650 r.dump(pw, " ");
8651 }
8652 needSep = true;
8653 }
8654
8655 if (mServiceConnections.size() > 0) {
8656 if (needSep) pw.println(" ");
8657 pw.println(" Connection bindings to services:");
8658 Iterator<ConnectionRecord> it
8659 = mServiceConnections.values().iterator();
8660 while (it.hasNext()) {
8661 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008662 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008663 r.dump(pw, " ");
8664 }
8665 }
8666 }
8667 }
8668
8669 void dumpProviders(PrintWriter pw) {
8670 synchronized (this) {
8671 if (checkCallingPermission(android.Manifest.permission.DUMP)
8672 != PackageManager.PERMISSION_GRANTED) {
8673 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8674 + Binder.getCallingPid()
8675 + ", uid=" + Binder.getCallingUid()
8676 + " without permission "
8677 + android.Manifest.permission.DUMP);
8678 return;
8679 }
8680
8681 pw.println("Content Providers in Current Activity Manager State:");
8682
8683 boolean needSep = false;
8684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008685 if (mProvidersByClass.size() > 0) {
8686 if (needSep) pw.println(" ");
8687 pw.println(" Published content providers (by class):");
8688 Iterator it = mProvidersByClass.entrySet().iterator();
8689 while (it.hasNext()) {
8690 Map.Entry e = (Map.Entry)it.next();
8691 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008692 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008693 r.dump(pw, " ");
8694 }
8695 needSep = true;
8696 }
8697
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008698 if (mProvidersByName.size() > 0) {
8699 pw.println(" ");
8700 pw.println(" Authority to provider mappings:");
8701 Iterator it = mProvidersByName.entrySet().iterator();
8702 while (it.hasNext()) {
8703 Map.Entry e = (Map.Entry)it.next();
8704 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8705 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8706 pw.println(r);
8707 }
8708 needSep = true;
8709 }
8710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008711 if (mLaunchingProviders.size() > 0) {
8712 if (needSep) pw.println(" ");
8713 pw.println(" Launching content providers:");
8714 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008715 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8716 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008717 }
8718 needSep = true;
8719 }
8720
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008721 if (mGrantedUriPermissions.size() > 0) {
8722 pw.println();
8723 pw.println("Granted Uri Permissions:");
8724 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8725 int uid = mGrantedUriPermissions.keyAt(i);
8726 HashMap<Uri, UriPermission> perms
8727 = mGrantedUriPermissions.valueAt(i);
8728 pw.print(" * UID "); pw.print(uid);
8729 pw.println(" holds:");
8730 for (UriPermission perm : perms.values()) {
8731 pw.print(" "); pw.println(perm);
8732 perm.dump(pw, " ");
8733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008734 }
8735 }
8736 }
8737 }
8738
8739 void dumpSenders(PrintWriter pw) {
8740 synchronized (this) {
8741 if (checkCallingPermission(android.Manifest.permission.DUMP)
8742 != PackageManager.PERMISSION_GRANTED) {
8743 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8744 + Binder.getCallingPid()
8745 + ", uid=" + Binder.getCallingUid()
8746 + " without permission "
8747 + android.Manifest.permission.DUMP);
8748 return;
8749 }
8750
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008751 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008752
8753 if (this.mIntentSenderRecords.size() > 0) {
8754 Iterator<WeakReference<PendingIntentRecord>> it
8755 = mIntentSenderRecords.values().iterator();
8756 while (it.hasNext()) {
8757 WeakReference<PendingIntentRecord> ref = it.next();
8758 PendingIntentRecord rec = ref != null ? ref.get(): null;
8759 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008760 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008761 rec.dump(pw, " ");
8762 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008763 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008764 }
8765 }
8766 }
8767 }
8768 }
8769
8770 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008771 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 TaskRecord lastTask = null;
8773 for (int i=list.size()-1; i>=0; i--) {
8774 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008775 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008776 if (lastTask != r.task) {
8777 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008778 pw.print(prefix);
8779 pw.print(full ? "* " : " ");
8780 pw.println(lastTask);
8781 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008782 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008784 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008785 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8786 pw.print(" #"); pw.print(i); pw.print(": ");
8787 pw.println(r);
8788 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008789 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008791 }
8792 }
8793
8794 private static final int dumpProcessList(PrintWriter pw, List list,
8795 String prefix, String normalLabel, String persistentLabel,
8796 boolean inclOomAdj) {
8797 int numPers = 0;
8798 for (int i=list.size()-1; i>=0; i--) {
8799 ProcessRecord r = (ProcessRecord)list.get(i);
8800 if (false) {
8801 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8802 + " #" + i + ":");
8803 r.dump(pw, prefix + " ");
8804 } else if (inclOomAdj) {
8805 pw.println(String.format("%s%s #%2d: oom_adj=%3d %s",
8806 prefix, (r.persistent ? persistentLabel : normalLabel),
8807 i, r.setAdj, r.toString()));
8808 } else {
8809 pw.println(String.format("%s%s #%2d: %s",
8810 prefix, (r.persistent ? persistentLabel : normalLabel),
8811 i, r.toString()));
8812 }
8813 if (r.persistent) {
8814 numPers++;
8815 }
8816 }
8817 return numPers;
8818 }
8819
8820 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8821 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008822 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008823 long uptime = SystemClock.uptimeMillis();
8824 long realtime = SystemClock.elapsedRealtime();
8825
8826 if (isCheckinRequest) {
8827 // short checkin version
8828 pw.println(uptime + "," + realtime);
8829 pw.flush();
8830 } else {
8831 pw.println("Applications Memory Usage (kB):");
8832 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8833 }
8834 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8835 ProcessRecord r = (ProcessRecord)list.get(i);
8836 if (r.thread != null) {
8837 if (!isCheckinRequest) {
8838 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8839 pw.flush();
8840 }
8841 try {
8842 r.thread.asBinder().dump(fd, args);
8843 } catch (RemoteException e) {
8844 if (!isCheckinRequest) {
8845 pw.println("Got RemoteException!");
8846 pw.flush();
8847 }
8848 }
8849 }
8850 }
8851 }
8852
8853 /**
8854 * Searches array of arguments for the specified string
8855 * @param args array of argument strings
8856 * @param value value to search for
8857 * @return true if the value is contained in the array
8858 */
8859 private static boolean scanArgs(String[] args, String value) {
8860 if (args != null) {
8861 for (String arg : args) {
8862 if (value.equals(arg)) {
8863 return true;
8864 }
8865 }
8866 }
8867 return false;
8868 }
8869
8870 private final int indexOfTokenLocked(IBinder token, boolean required) {
8871 int count = mHistory.size();
8872
8873 // convert the token to an entry in the history.
8874 HistoryRecord r = null;
8875 int index = -1;
8876 for (int i=count-1; i>=0; i--) {
8877 Object o = mHistory.get(i);
8878 if (o == token) {
8879 r = (HistoryRecord)o;
8880 index = i;
8881 break;
8882 }
8883 }
8884 if (index < 0 && required) {
8885 RuntimeInit.crash(TAG, new InvalidTokenException(token));
8886 }
8887
8888 return index;
8889 }
8890
8891 static class InvalidTokenException extends Exception {
8892 InvalidTokenException(IBinder token) {
8893 super("Bad activity token: " + token);
8894 }
8895 }
8896
8897 private final void killServicesLocked(ProcessRecord app,
8898 boolean allowRestart) {
8899 // Report disconnected services.
8900 if (false) {
8901 // XXX we are letting the client link to the service for
8902 // death notifications.
8903 if (app.services.size() > 0) {
8904 Iterator it = app.services.iterator();
8905 while (it.hasNext()) {
8906 ServiceRecord r = (ServiceRecord)it.next();
8907 if (r.connections.size() > 0) {
8908 Iterator<ConnectionRecord> jt
8909 = r.connections.values().iterator();
8910 while (jt.hasNext()) {
8911 ConnectionRecord c = jt.next();
8912 if (c.binding.client != app) {
8913 try {
8914 //c.conn.connected(r.className, null);
8915 } catch (Exception e) {
8916 // todo: this should be asynchronous!
8917 Log.w(TAG, "Exception thrown disconnected servce "
8918 + r.shortName
8919 + " from app " + app.processName, e);
8920 }
8921 }
8922 }
8923 }
8924 }
8925 }
8926 }
8927
8928 // Clean up any connections this application has to other services.
8929 if (app.connections.size() > 0) {
8930 Iterator<ConnectionRecord> it = app.connections.iterator();
8931 while (it.hasNext()) {
8932 ConnectionRecord r = it.next();
8933 removeConnectionLocked(r, app, null);
8934 }
8935 }
8936 app.connections.clear();
8937
8938 if (app.services.size() != 0) {
8939 // Any services running in the application need to be placed
8940 // back in the pending list.
8941 Iterator it = app.services.iterator();
8942 while (it.hasNext()) {
8943 ServiceRecord sr = (ServiceRecord)it.next();
8944 synchronized (sr.stats.getBatteryStats()) {
8945 sr.stats.stopLaunchedLocked();
8946 }
8947 sr.app = null;
8948 sr.executeNesting = 0;
8949 mStoppingServices.remove(sr);
8950 if (sr.bindings.size() > 0) {
8951 Iterator<IntentBindRecord> bindings
8952 = sr.bindings.values().iterator();
8953 while (bindings.hasNext()) {
8954 IntentBindRecord b = bindings.next();
8955 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
8956 + ": shouldUnbind=" + b.hasBound);
8957 b.binder = null;
8958 b.requested = b.received = b.hasBound = false;
8959 }
8960 }
8961
8962 if (sr.crashCount >= 2) {
8963 Log.w(TAG, "Service crashed " + sr.crashCount
8964 + " times, stopping: " + sr);
8965 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
8966 sr.crashCount, sr.shortName, app.pid);
8967 bringDownServiceLocked(sr, true);
8968 } else if (!allowRestart) {
8969 bringDownServiceLocked(sr, true);
8970 } else {
8971 scheduleServiceRestartLocked(sr);
8972 }
8973 }
8974
8975 if (!allowRestart) {
8976 app.services.clear();
8977 }
8978 }
8979
8980 app.executingServices.clear();
8981 }
8982
8983 private final void removeDyingProviderLocked(ProcessRecord proc,
8984 ContentProviderRecord cpr) {
8985 synchronized (cpr) {
8986 cpr.launchingApp = null;
8987 cpr.notifyAll();
8988 }
8989
8990 mProvidersByClass.remove(cpr.info.name);
8991 String names[] = cpr.info.authority.split(";");
8992 for (int j = 0; j < names.length; j++) {
8993 mProvidersByName.remove(names[j]);
8994 }
8995
8996 Iterator<ProcessRecord> cit = cpr.clients.iterator();
8997 while (cit.hasNext()) {
8998 ProcessRecord capp = cit.next();
8999 if (!capp.persistent && capp.thread != null
9000 && capp.pid != 0
9001 && capp.pid != MY_PID) {
9002 Log.i(TAG, "Killing app " + capp.processName
9003 + " (pid " + capp.pid
9004 + ") because provider " + cpr.info.name
9005 + " is in dying process " + proc.processName);
9006 Process.killProcess(capp.pid);
9007 }
9008 }
9009
9010 mLaunchingProviders.remove(cpr);
9011 }
9012
9013 /**
9014 * Main code for cleaning up a process when it has gone away. This is
9015 * called both as a result of the process dying, or directly when stopping
9016 * a process when running in single process mode.
9017 */
9018 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9019 boolean restarting, int index) {
9020 if (index >= 0) {
9021 mLRUProcesses.remove(index);
9022 }
9023
9024 // Dismiss any open dialogs.
9025 if (app.crashDialog != null) {
9026 app.crashDialog.dismiss();
9027 app.crashDialog = null;
9028 }
9029 if (app.anrDialog != null) {
9030 app.anrDialog.dismiss();
9031 app.anrDialog = null;
9032 }
9033 if (app.waitDialog != null) {
9034 app.waitDialog.dismiss();
9035 app.waitDialog = null;
9036 }
9037
9038 app.crashing = false;
9039 app.notResponding = false;
9040
9041 app.resetPackageList();
9042 app.thread = null;
9043 app.forcingToForeground = null;
9044 app.foregroundServices = false;
9045
9046 killServicesLocked(app, true);
9047
9048 boolean restart = false;
9049
9050 int NL = mLaunchingProviders.size();
9051
9052 // Remove published content providers.
9053 if (!app.pubProviders.isEmpty()) {
9054 Iterator it = app.pubProviders.values().iterator();
9055 while (it.hasNext()) {
9056 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9057 cpr.provider = null;
9058 cpr.app = null;
9059
9060 // See if someone is waiting for this provider... in which
9061 // case we don't remove it, but just let it restart.
9062 int i = 0;
9063 if (!app.bad) {
9064 for (; i<NL; i++) {
9065 if (mLaunchingProviders.get(i) == cpr) {
9066 restart = true;
9067 break;
9068 }
9069 }
9070 } else {
9071 i = NL;
9072 }
9073
9074 if (i >= NL) {
9075 removeDyingProviderLocked(app, cpr);
9076 NL = mLaunchingProviders.size();
9077 }
9078 }
9079 app.pubProviders.clear();
9080 }
9081
9082 // Look through the content providers we are waiting to have launched,
9083 // and if any run in this process then either schedule a restart of
9084 // the process or kill the client waiting for it if this process has
9085 // gone bad.
9086 for (int i=0; i<NL; i++) {
9087 ContentProviderRecord cpr = (ContentProviderRecord)
9088 mLaunchingProviders.get(i);
9089 if (cpr.launchingApp == app) {
9090 if (!app.bad) {
9091 restart = true;
9092 } else {
9093 removeDyingProviderLocked(app, cpr);
9094 NL = mLaunchingProviders.size();
9095 }
9096 }
9097 }
9098
9099 // Unregister from connected content providers.
9100 if (!app.conProviders.isEmpty()) {
9101 Iterator it = app.conProviders.iterator();
9102 while (it.hasNext()) {
9103 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9104 cpr.clients.remove(app);
9105 }
9106 app.conProviders.clear();
9107 }
9108
9109 skipCurrentReceiverLocked(app);
9110
9111 // Unregister any receivers.
9112 if (app.receivers.size() > 0) {
9113 Iterator<ReceiverList> it = app.receivers.iterator();
9114 while (it.hasNext()) {
9115 removeReceiverLocked(it.next());
9116 }
9117 app.receivers.clear();
9118 }
9119
9120 // If the caller is restarting this app, then leave it in its
9121 // current lists and let the caller take care of it.
9122 if (restarting) {
9123 return;
9124 }
9125
9126 if (!app.persistent) {
9127 if (DEBUG_PROCESSES) Log.v(TAG,
9128 "Removing non-persistent process during cleanup: " + app);
9129 mProcessNames.remove(app.processName, app.info.uid);
9130 } else if (!app.removed) {
9131 // This app is persistent, so we need to keep its record around.
9132 // If it is not already on the pending app list, add it there
9133 // and start a new process for it.
9134 app.thread = null;
9135 app.forcingToForeground = null;
9136 app.foregroundServices = false;
9137 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9138 mPersistentStartingProcesses.add(app);
9139 restart = true;
9140 }
9141 }
9142 mProcessesOnHold.remove(app);
9143
The Android Open Source Project4df24232009-03-05 14:34:35 -08009144 if (app == mHomeProcess) {
9145 mHomeProcess = null;
9146 }
9147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009148 if (restart) {
9149 // We have components that still need to be running in the
9150 // process, so re-launch it.
9151 mProcessNames.put(app.processName, app.info.uid, app);
9152 startProcessLocked(app, "restart", app.processName);
9153 } else if (app.pid > 0 && app.pid != MY_PID) {
9154 // Goodbye!
9155 synchronized (mPidsSelfLocked) {
9156 mPidsSelfLocked.remove(app.pid);
9157 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9158 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009159 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009160 }
9161 }
9162
9163 // =========================================================
9164 // SERVICES
9165 // =========================================================
9166
9167 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9168 ActivityManager.RunningServiceInfo info =
9169 new ActivityManager.RunningServiceInfo();
9170 info.service = r.name;
9171 if (r.app != null) {
9172 info.pid = r.app.pid;
9173 }
9174 info.process = r.processName;
9175 info.foreground = r.isForeground;
9176 info.activeSince = r.createTime;
9177 info.started = r.startRequested;
9178 info.clientCount = r.connections.size();
9179 info.crashCount = r.crashCount;
9180 info.lastActivityTime = r.lastActivity;
9181 return info;
9182 }
9183
9184 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9185 int flags) {
9186 synchronized (this) {
9187 ArrayList<ActivityManager.RunningServiceInfo> res
9188 = new ArrayList<ActivityManager.RunningServiceInfo>();
9189
9190 if (mServices.size() > 0) {
9191 Iterator<ServiceRecord> it = mServices.values().iterator();
9192 while (it.hasNext() && res.size() < maxNum) {
9193 res.add(makeRunningServiceInfoLocked(it.next()));
9194 }
9195 }
9196
9197 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9198 ServiceRecord r = mRestartingServices.get(i);
9199 ActivityManager.RunningServiceInfo info =
9200 makeRunningServiceInfoLocked(r);
9201 info.restarting = r.nextRestartTime;
9202 res.add(info);
9203 }
9204
9205 return res;
9206 }
9207 }
9208
9209 private final ServiceRecord findServiceLocked(ComponentName name,
9210 IBinder token) {
9211 ServiceRecord r = mServices.get(name);
9212 return r == token ? r : null;
9213 }
9214
9215 private final class ServiceLookupResult {
9216 final ServiceRecord record;
9217 final String permission;
9218
9219 ServiceLookupResult(ServiceRecord _record, String _permission) {
9220 record = _record;
9221 permission = _permission;
9222 }
9223 };
9224
9225 private ServiceLookupResult findServiceLocked(Intent service,
9226 String resolvedType) {
9227 ServiceRecord r = null;
9228 if (service.getComponent() != null) {
9229 r = mServices.get(service.getComponent());
9230 }
9231 if (r == null) {
9232 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9233 r = mServicesByIntent.get(filter);
9234 }
9235
9236 if (r == null) {
9237 try {
9238 ResolveInfo rInfo =
9239 ActivityThread.getPackageManager().resolveService(
9240 service, resolvedType, 0);
9241 ServiceInfo sInfo =
9242 rInfo != null ? rInfo.serviceInfo : null;
9243 if (sInfo == null) {
9244 return null;
9245 }
9246
9247 ComponentName name = new ComponentName(
9248 sInfo.applicationInfo.packageName, sInfo.name);
9249 r = mServices.get(name);
9250 } catch (RemoteException ex) {
9251 // pm is in same process, this will never happen.
9252 }
9253 }
9254 if (r != null) {
9255 int callingPid = Binder.getCallingPid();
9256 int callingUid = Binder.getCallingUid();
9257 if (checkComponentPermission(r.permission,
9258 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9259 != PackageManager.PERMISSION_GRANTED) {
9260 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9261 + " from pid=" + callingPid
9262 + ", uid=" + callingUid
9263 + " requires " + r.permission);
9264 return new ServiceLookupResult(null, r.permission);
9265 }
9266 return new ServiceLookupResult(r, null);
9267 }
9268 return null;
9269 }
9270
9271 private class ServiceRestarter implements Runnable {
9272 private ServiceRecord mService;
9273
9274 void setService(ServiceRecord service) {
9275 mService = service;
9276 }
9277
9278 public void run() {
9279 synchronized(ActivityManagerService.this) {
9280 performServiceRestartLocked(mService);
9281 }
9282 }
9283 }
9284
9285 private ServiceLookupResult retrieveServiceLocked(Intent service,
9286 String resolvedType, int callingPid, int callingUid) {
9287 ServiceRecord r = null;
9288 if (service.getComponent() != null) {
9289 r = mServices.get(service.getComponent());
9290 }
9291 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9292 r = mServicesByIntent.get(filter);
9293 if (r == null) {
9294 try {
9295 ResolveInfo rInfo =
9296 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009297 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009298 ServiceInfo sInfo =
9299 rInfo != null ? rInfo.serviceInfo : null;
9300 if (sInfo == null) {
9301 Log.w(TAG, "Unable to start service " + service +
9302 ": not found");
9303 return null;
9304 }
9305
9306 ComponentName name = new ComponentName(
9307 sInfo.applicationInfo.packageName, sInfo.name);
9308 r = mServices.get(name);
9309 if (r == null) {
9310 filter = new Intent.FilterComparison(service.cloneFilter());
9311 ServiceRestarter res = new ServiceRestarter();
9312 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9313 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9314 synchronized (stats) {
9315 ss = stats.getServiceStatsLocked(
9316 sInfo.applicationInfo.uid, sInfo.packageName,
9317 sInfo.name);
9318 }
9319 r = new ServiceRecord(ss, name, filter, sInfo, res);
9320 res.setService(r);
9321 mServices.put(name, r);
9322 mServicesByIntent.put(filter, r);
9323
9324 // Make sure this component isn't in the pending list.
9325 int N = mPendingServices.size();
9326 for (int i=0; i<N; i++) {
9327 ServiceRecord pr = mPendingServices.get(i);
9328 if (pr.name.equals(name)) {
9329 mPendingServices.remove(i);
9330 i--;
9331 N--;
9332 }
9333 }
9334 }
9335 } catch (RemoteException ex) {
9336 // pm is in same process, this will never happen.
9337 }
9338 }
9339 if (r != null) {
9340 if (checkComponentPermission(r.permission,
9341 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9342 != PackageManager.PERMISSION_GRANTED) {
9343 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9344 + " from pid=" + Binder.getCallingPid()
9345 + ", uid=" + Binder.getCallingUid()
9346 + " requires " + r.permission);
9347 return new ServiceLookupResult(null, r.permission);
9348 }
9349 return new ServiceLookupResult(r, null);
9350 }
9351 return null;
9352 }
9353
9354 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9355 long now = SystemClock.uptimeMillis();
9356 if (r.executeNesting == 0 && r.app != null) {
9357 if (r.app.executingServices.size() == 0) {
9358 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9359 msg.obj = r.app;
9360 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9361 }
9362 r.app.executingServices.add(r);
9363 }
9364 r.executeNesting++;
9365 r.executingStart = now;
9366 }
9367
9368 private final void sendServiceArgsLocked(ServiceRecord r,
9369 boolean oomAdjusted) {
9370 final int N = r.startArgs.size();
9371 if (N == 0) {
9372 return;
9373 }
9374
9375 final int BASEID = r.lastStartId - N + 1;
9376 int i = 0;
9377 while (i < N) {
9378 try {
9379 Intent args = r.startArgs.get(i);
9380 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9381 + r.name + " " + r.intent + " args=" + args);
9382 bumpServiceExecutingLocked(r);
9383 if (!oomAdjusted) {
9384 oomAdjusted = true;
9385 updateOomAdjLocked(r.app);
9386 }
9387 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9388 i++;
9389 } catch (Exception e) {
9390 break;
9391 }
9392 }
9393 if (i == N) {
9394 r.startArgs.clear();
9395 } else {
9396 while (i > 0) {
9397 r.startArgs.remove(0);
9398 i--;
9399 }
9400 }
9401 }
9402
9403 private final boolean requestServiceBindingLocked(ServiceRecord r,
9404 IntentBindRecord i, boolean rebind) {
9405 if (r.app == null || r.app.thread == null) {
9406 // If service is not currently running, can't yet bind.
9407 return false;
9408 }
9409 if ((!i.requested || rebind) && i.apps.size() > 0) {
9410 try {
9411 bumpServiceExecutingLocked(r);
9412 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9413 + ": shouldUnbind=" + i.hasBound);
9414 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9415 if (!rebind) {
9416 i.requested = true;
9417 }
9418 i.hasBound = true;
9419 i.doRebind = false;
9420 } catch (RemoteException e) {
9421 return false;
9422 }
9423 }
9424 return true;
9425 }
9426
9427 private final void requestServiceBindingsLocked(ServiceRecord r) {
9428 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9429 while (bindings.hasNext()) {
9430 IntentBindRecord i = bindings.next();
9431 if (!requestServiceBindingLocked(r, i, false)) {
9432 break;
9433 }
9434 }
9435 }
9436
9437 private final void realStartServiceLocked(ServiceRecord r,
9438 ProcessRecord app) throws RemoteException {
9439 if (app.thread == null) {
9440 throw new RemoteException();
9441 }
9442
9443 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009444 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009445
9446 app.services.add(r);
9447 bumpServiceExecutingLocked(r);
9448 updateLRUListLocked(app, true);
9449
9450 boolean created = false;
9451 try {
9452 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9453 + r.name + " " + r.intent);
9454 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9455 System.identityHashCode(r), r.shortName,
9456 r.intent.getIntent().toString(), r.app.pid);
9457 synchronized (r.stats.getBatteryStats()) {
9458 r.stats.startLaunchedLocked();
9459 }
9460 app.thread.scheduleCreateService(r, r.serviceInfo);
9461 created = true;
9462 } finally {
9463 if (!created) {
9464 app.services.remove(r);
9465 scheduleServiceRestartLocked(r);
9466 }
9467 }
9468
9469 requestServiceBindingsLocked(r);
9470 sendServiceArgsLocked(r, true);
9471 }
9472
9473 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9474 r.totalRestartCount++;
9475 if (r.restartDelay == 0) {
9476 r.restartCount++;
9477 r.restartDelay = SERVICE_RESTART_DURATION;
9478 } else {
9479 // If it has been a "reasonably long time" since the service
9480 // was started, then reset our restart duration back to
9481 // the beginning, so we don't infinitely increase the duration
9482 // on a service that just occasionally gets killed (which is
9483 // a normal case, due to process being killed to reclaim memory).
9484 long now = SystemClock.uptimeMillis();
9485 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9486 r.restartCount = 1;
9487 r.restartDelay = SERVICE_RESTART_DURATION;
9488 } else {
9489 r.restartDelay *= 2;
9490 }
9491 }
9492 if (!mRestartingServices.contains(r)) {
9493 mRestartingServices.add(r);
9494 }
9495 mHandler.removeCallbacks(r.restarter);
9496 mHandler.postDelayed(r.restarter, r.restartDelay);
9497 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9498 Log.w(TAG, "Scheduling restart of crashed service "
9499 + r.shortName + " in " + r.restartDelay + "ms");
9500 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9501 r.shortName, r.restartDelay);
9502
9503 Message msg = Message.obtain();
9504 msg.what = SERVICE_ERROR_MSG;
9505 msg.obj = r;
9506 mHandler.sendMessage(msg);
9507 }
9508
9509 final void performServiceRestartLocked(ServiceRecord r) {
9510 if (!mRestartingServices.contains(r)) {
9511 return;
9512 }
9513 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9514 }
9515
9516 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9517 if (r.restartDelay == 0) {
9518 return false;
9519 }
9520 r.resetRestartCounter();
9521 mRestartingServices.remove(r);
9522 mHandler.removeCallbacks(r.restarter);
9523 return true;
9524 }
9525
9526 private final boolean bringUpServiceLocked(ServiceRecord r,
9527 int intentFlags, boolean whileRestarting) {
9528 //Log.i(TAG, "Bring up service:");
9529 //r.dump(" ");
9530
9531 if (r.app != null) {
9532 sendServiceArgsLocked(r, false);
9533 return true;
9534 }
9535
9536 if (!whileRestarting && r.restartDelay > 0) {
9537 // If waiting for a restart, then do nothing.
9538 return true;
9539 }
9540
9541 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9542 + " " + r.intent);
9543
9544 final String appName = r.processName;
9545 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9546 if (app != null && app.thread != null) {
9547 try {
9548 realStartServiceLocked(r, app);
9549 return true;
9550 } catch (RemoteException e) {
9551 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9552 }
9553
9554 // If a dead object exception was thrown -- fall through to
9555 // restart the application.
9556 }
9557
9558 if (!mPendingServices.contains(r)) {
9559 // Not running -- get it started, and enqueue this service record
9560 // to be executed when the app comes up.
9561 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9562 "service", r.name) == null) {
9563 Log.w(TAG, "Unable to launch app "
9564 + r.appInfo.packageName + "/"
9565 + r.appInfo.uid + " for service "
9566 + r.intent.getIntent() + ": process is bad");
9567 bringDownServiceLocked(r, true);
9568 return false;
9569 }
9570 mPendingServices.add(r);
9571 }
9572 return true;
9573 }
9574
9575 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9576 //Log.i(TAG, "Bring down service:");
9577 //r.dump(" ");
9578
9579 // Does it still need to run?
9580 if (!force && r.startRequested) {
9581 return;
9582 }
9583 if (r.connections.size() > 0) {
9584 if (!force) {
9585 // XXX should probably keep a count of the number of auto-create
9586 // connections directly in the service.
9587 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9588 while (it.hasNext()) {
9589 ConnectionRecord cr = it.next();
9590 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9591 return;
9592 }
9593 }
9594 }
9595
9596 // Report to all of the connections that the service is no longer
9597 // available.
9598 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9599 while (it.hasNext()) {
9600 ConnectionRecord c = it.next();
9601 try {
9602 // todo: shouldn't be a synchronous call!
9603 c.conn.connected(r.name, null);
9604 } catch (Exception e) {
9605 Log.w(TAG, "Failure disconnecting service " + r.name +
9606 " to connection " + c.conn.asBinder() +
9607 " (in " + c.binding.client.processName + ")", e);
9608 }
9609 }
9610 }
9611
9612 // Tell the service that it has been unbound.
9613 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9614 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9615 while (it.hasNext()) {
9616 IntentBindRecord ibr = it.next();
9617 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9618 + ": hasBound=" + ibr.hasBound);
9619 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9620 try {
9621 bumpServiceExecutingLocked(r);
9622 updateOomAdjLocked(r.app);
9623 ibr.hasBound = false;
9624 r.app.thread.scheduleUnbindService(r,
9625 ibr.intent.getIntent());
9626 } catch (Exception e) {
9627 Log.w(TAG, "Exception when unbinding service "
9628 + r.shortName, e);
9629 serviceDoneExecutingLocked(r, true);
9630 }
9631 }
9632 }
9633 }
9634
9635 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9636 + " " + r.intent);
9637 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9638 System.identityHashCode(r), r.shortName,
9639 (r.app != null) ? r.app.pid : -1);
9640
9641 mServices.remove(r.name);
9642 mServicesByIntent.remove(r.intent);
9643 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9644 r.totalRestartCount = 0;
9645 unscheduleServiceRestartLocked(r);
9646
9647 // Also make sure it is not on the pending list.
9648 int N = mPendingServices.size();
9649 for (int i=0; i<N; i++) {
9650 if (mPendingServices.get(i) == r) {
9651 mPendingServices.remove(i);
9652 if (DEBUG_SERVICE) Log.v(
9653 TAG, "Removed pending service: " + r.shortName);
9654 i--;
9655 N--;
9656 }
9657 }
9658
9659 if (r.app != null) {
9660 synchronized (r.stats.getBatteryStats()) {
9661 r.stats.stopLaunchedLocked();
9662 }
9663 r.app.services.remove(r);
9664 if (r.app.thread != null) {
9665 updateServiceForegroundLocked(r.app, false);
9666 try {
9667 Log.i(TAG, "Stopping service: " + r.shortName);
9668 bumpServiceExecutingLocked(r);
9669 mStoppingServices.add(r);
9670 updateOomAdjLocked(r.app);
9671 r.app.thread.scheduleStopService(r);
9672 } catch (Exception e) {
9673 Log.w(TAG, "Exception when stopping service "
9674 + r.shortName, e);
9675 serviceDoneExecutingLocked(r, true);
9676 }
9677 } else {
9678 if (DEBUG_SERVICE) Log.v(
9679 TAG, "Removed service that has no process: " + r.shortName);
9680 }
9681 } else {
9682 if (DEBUG_SERVICE) Log.v(
9683 TAG, "Removed service that is not running: " + r.shortName);
9684 }
9685 }
9686
9687 ComponentName startServiceLocked(IApplicationThread caller,
9688 Intent service, String resolvedType,
9689 int callingPid, int callingUid) {
9690 synchronized(this) {
9691 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9692 + " type=" + resolvedType + " args=" + service.getExtras());
9693
9694 if (caller != null) {
9695 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9696 if (callerApp == null) {
9697 throw new SecurityException(
9698 "Unable to find app for caller " + caller
9699 + " (pid=" + Binder.getCallingPid()
9700 + ") when starting service " + service);
9701 }
9702 }
9703
9704 ServiceLookupResult res =
9705 retrieveServiceLocked(service, resolvedType,
9706 callingPid, callingUid);
9707 if (res == null) {
9708 return null;
9709 }
9710 if (res.record == null) {
9711 return new ComponentName("!", res.permission != null
9712 ? res.permission : "private to package");
9713 }
9714 ServiceRecord r = res.record;
9715 if (unscheduleServiceRestartLocked(r)) {
9716 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9717 + r.shortName);
9718 }
9719 r.startRequested = true;
9720 r.startArgs.add(service);
9721 r.lastStartId++;
9722 if (r.lastStartId < 1) {
9723 r.lastStartId = 1;
9724 }
9725 r.lastActivity = SystemClock.uptimeMillis();
9726 synchronized (r.stats.getBatteryStats()) {
9727 r.stats.startRunningLocked();
9728 }
9729 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9730 return new ComponentName("!", "Service process is bad");
9731 }
9732 return r.name;
9733 }
9734 }
9735
9736 public ComponentName startService(IApplicationThread caller, Intent service,
9737 String resolvedType) {
9738 // Refuse possible leaked file descriptors
9739 if (service != null && service.hasFileDescriptors() == true) {
9740 throw new IllegalArgumentException("File descriptors passed in Intent");
9741 }
9742
9743 synchronized(this) {
9744 final int callingPid = Binder.getCallingPid();
9745 final int callingUid = Binder.getCallingUid();
9746 final long origId = Binder.clearCallingIdentity();
9747 ComponentName res = startServiceLocked(caller, service,
9748 resolvedType, callingPid, callingUid);
9749 Binder.restoreCallingIdentity(origId);
9750 return res;
9751 }
9752 }
9753
9754 ComponentName startServiceInPackage(int uid,
9755 Intent service, String resolvedType) {
9756 synchronized(this) {
9757 final long origId = Binder.clearCallingIdentity();
9758 ComponentName res = startServiceLocked(null, service,
9759 resolvedType, -1, uid);
9760 Binder.restoreCallingIdentity(origId);
9761 return res;
9762 }
9763 }
9764
9765 public int stopService(IApplicationThread caller, Intent service,
9766 String resolvedType) {
9767 // Refuse possible leaked file descriptors
9768 if (service != null && service.hasFileDescriptors() == true) {
9769 throw new IllegalArgumentException("File descriptors passed in Intent");
9770 }
9771
9772 synchronized(this) {
9773 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9774 + " type=" + resolvedType);
9775
9776 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9777 if (caller != null && callerApp == null) {
9778 throw new SecurityException(
9779 "Unable to find app for caller " + caller
9780 + " (pid=" + Binder.getCallingPid()
9781 + ") when stopping service " + service);
9782 }
9783
9784 // If this service is active, make sure it is stopped.
9785 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9786 if (r != null) {
9787 if (r.record != null) {
9788 synchronized (r.record.stats.getBatteryStats()) {
9789 r.record.stats.stopRunningLocked();
9790 }
9791 r.record.startRequested = false;
9792 final long origId = Binder.clearCallingIdentity();
9793 bringDownServiceLocked(r.record, false);
9794 Binder.restoreCallingIdentity(origId);
9795 return 1;
9796 }
9797 return -1;
9798 }
9799 }
9800
9801 return 0;
9802 }
9803
9804 public IBinder peekService(Intent service, String resolvedType) {
9805 // Refuse possible leaked file descriptors
9806 if (service != null && service.hasFileDescriptors() == true) {
9807 throw new IllegalArgumentException("File descriptors passed in Intent");
9808 }
9809
9810 IBinder ret = null;
9811
9812 synchronized(this) {
9813 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9814
9815 if (r != null) {
9816 // r.record is null if findServiceLocked() failed the caller permission check
9817 if (r.record == null) {
9818 throw new SecurityException(
9819 "Permission Denial: Accessing service " + r.record.name
9820 + " from pid=" + Binder.getCallingPid()
9821 + ", uid=" + Binder.getCallingUid()
9822 + " requires " + r.permission);
9823 }
9824 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9825 if (ib != null) {
9826 ret = ib.binder;
9827 }
9828 }
9829 }
9830
9831 return ret;
9832 }
9833
9834 public boolean stopServiceToken(ComponentName className, IBinder token,
9835 int startId) {
9836 synchronized(this) {
9837 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9838 + " " + token + " startId=" + startId);
9839 ServiceRecord r = findServiceLocked(className, token);
9840 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9841 synchronized (r.stats.getBatteryStats()) {
9842 r.stats.stopRunningLocked();
9843 r.startRequested = false;
9844 }
9845 final long origId = Binder.clearCallingIdentity();
9846 bringDownServiceLocked(r, false);
9847 Binder.restoreCallingIdentity(origId);
9848 return true;
9849 }
9850 }
9851 return false;
9852 }
9853
9854 public void setServiceForeground(ComponentName className, IBinder token,
9855 boolean isForeground) {
9856 synchronized(this) {
9857 ServiceRecord r = findServiceLocked(className, token);
9858 if (r != null) {
9859 if (r.isForeground != isForeground) {
9860 final long origId = Binder.clearCallingIdentity();
9861 r.isForeground = isForeground;
9862 if (r.app != null) {
9863 updateServiceForegroundLocked(r.app, true);
9864 }
9865 Binder.restoreCallingIdentity(origId);
9866 }
9867 }
9868 }
9869 }
9870
9871 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9872 boolean anyForeground = false;
9873 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9874 if (sr.isForeground) {
9875 anyForeground = true;
9876 break;
9877 }
9878 }
9879 if (anyForeground != proc.foregroundServices) {
9880 proc.foregroundServices = anyForeground;
9881 if (oomAdj) {
9882 updateOomAdjLocked();
9883 }
9884 }
9885 }
9886
9887 public int bindService(IApplicationThread caller, IBinder token,
9888 Intent service, String resolvedType,
9889 IServiceConnection connection, int flags) {
9890 // Refuse possible leaked file descriptors
9891 if (service != null && service.hasFileDescriptors() == true) {
9892 throw new IllegalArgumentException("File descriptors passed in Intent");
9893 }
9894
9895 synchronized(this) {
9896 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9897 + " type=" + resolvedType + " conn=" + connection.asBinder()
9898 + " flags=0x" + Integer.toHexString(flags));
9899 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9900 if (callerApp == null) {
9901 throw new SecurityException(
9902 "Unable to find app for caller " + caller
9903 + " (pid=" + Binder.getCallingPid()
9904 + ") when binding service " + service);
9905 }
9906
9907 HistoryRecord activity = null;
9908 if (token != null) {
9909 int aindex = indexOfTokenLocked(token, false);
9910 if (aindex < 0) {
9911 Log.w(TAG, "Binding with unknown activity: " + token);
9912 return 0;
9913 }
9914 activity = (HistoryRecord)mHistory.get(aindex);
9915 }
9916
9917 ServiceLookupResult res =
9918 retrieveServiceLocked(service, resolvedType,
9919 Binder.getCallingPid(), Binder.getCallingUid());
9920 if (res == null) {
9921 return 0;
9922 }
9923 if (res.record == null) {
9924 return -1;
9925 }
9926 ServiceRecord s = res.record;
9927
9928 final long origId = Binder.clearCallingIdentity();
9929
9930 if (unscheduleServiceRestartLocked(s)) {
9931 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
9932 + s.shortName);
9933 }
9934
9935 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
9936 ConnectionRecord c = new ConnectionRecord(b, activity,
9937 connection, flags);
9938
9939 IBinder binder = connection.asBinder();
9940 s.connections.put(binder, c);
9941 b.connections.add(c);
9942 if (activity != null) {
9943 if (activity.connections == null) {
9944 activity.connections = new HashSet<ConnectionRecord>();
9945 }
9946 activity.connections.add(c);
9947 }
9948 b.client.connections.add(c);
9949 mServiceConnections.put(binder, c);
9950
9951 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
9952 s.lastActivity = SystemClock.uptimeMillis();
9953 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
9954 return 0;
9955 }
9956 }
9957
9958 if (s.app != null) {
9959 // This could have made the service more important.
9960 updateOomAdjLocked(s.app);
9961 }
9962
9963 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
9964 + ": received=" + b.intent.received
9965 + " apps=" + b.intent.apps.size()
9966 + " doRebind=" + b.intent.doRebind);
9967
9968 if (s.app != null && b.intent.received) {
9969 // Service is already running, so we can immediately
9970 // publish the connection.
9971 try {
9972 c.conn.connected(s.name, b.intent.binder);
9973 } catch (Exception e) {
9974 Log.w(TAG, "Failure sending service " + s.shortName
9975 + " to connection " + c.conn.asBinder()
9976 + " (in " + c.binding.client.processName + ")", e);
9977 }
9978
9979 // If this is the first app connected back to this binding,
9980 // and the service had previously asked to be told when
9981 // rebound, then do so.
9982 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
9983 requestServiceBindingLocked(s, b.intent, true);
9984 }
9985 } else if (!b.intent.requested) {
9986 requestServiceBindingLocked(s, b.intent, false);
9987 }
9988
9989 Binder.restoreCallingIdentity(origId);
9990 }
9991
9992 return 1;
9993 }
9994
9995 private void removeConnectionLocked(
9996 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
9997 IBinder binder = c.conn.asBinder();
9998 AppBindRecord b = c.binding;
9999 ServiceRecord s = b.service;
10000 s.connections.remove(binder);
10001 b.connections.remove(c);
10002 if (c.activity != null && c.activity != skipAct) {
10003 if (c.activity.connections != null) {
10004 c.activity.connections.remove(c);
10005 }
10006 }
10007 if (b.client != skipApp) {
10008 b.client.connections.remove(c);
10009 }
10010 mServiceConnections.remove(binder);
10011
10012 if (b.connections.size() == 0) {
10013 b.intent.apps.remove(b.client);
10014 }
10015
10016 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10017 + ": shouldUnbind=" + b.intent.hasBound);
10018 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10019 && b.intent.hasBound) {
10020 try {
10021 bumpServiceExecutingLocked(s);
10022 updateOomAdjLocked(s.app);
10023 b.intent.hasBound = false;
10024 // Assume the client doesn't want to know about a rebind;
10025 // we will deal with that later if it asks for one.
10026 b.intent.doRebind = false;
10027 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10028 } catch (Exception e) {
10029 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10030 serviceDoneExecutingLocked(s, true);
10031 }
10032 }
10033
10034 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10035 bringDownServiceLocked(s, false);
10036 }
10037 }
10038
10039 public boolean unbindService(IServiceConnection connection) {
10040 synchronized (this) {
10041 IBinder binder = connection.asBinder();
10042 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10043 ConnectionRecord r = mServiceConnections.get(binder);
10044 if (r == null) {
10045 Log.w(TAG, "Unbind failed: could not find connection for "
10046 + connection.asBinder());
10047 return false;
10048 }
10049
10050 final long origId = Binder.clearCallingIdentity();
10051
10052 removeConnectionLocked(r, null, null);
10053
10054 if (r.binding.service.app != null) {
10055 // This could have made the service less important.
10056 updateOomAdjLocked(r.binding.service.app);
10057 }
10058
10059 Binder.restoreCallingIdentity(origId);
10060 }
10061
10062 return true;
10063 }
10064
10065 public void publishService(IBinder token, Intent intent, IBinder service) {
10066 // Refuse possible leaked file descriptors
10067 if (intent != null && intent.hasFileDescriptors() == true) {
10068 throw new IllegalArgumentException("File descriptors passed in Intent");
10069 }
10070
10071 synchronized(this) {
10072 if (!(token instanceof ServiceRecord)) {
10073 throw new IllegalArgumentException("Invalid service token");
10074 }
10075 ServiceRecord r = (ServiceRecord)token;
10076
10077 final long origId = Binder.clearCallingIdentity();
10078
10079 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10080 + " " + intent + ": " + service);
10081 if (r != null) {
10082 Intent.FilterComparison filter
10083 = new Intent.FilterComparison(intent);
10084 IntentBindRecord b = r.bindings.get(filter);
10085 if (b != null && !b.received) {
10086 b.binder = service;
10087 b.requested = true;
10088 b.received = true;
10089 if (r.connections.size() > 0) {
10090 Iterator<ConnectionRecord> it
10091 = r.connections.values().iterator();
10092 while (it.hasNext()) {
10093 ConnectionRecord c = it.next();
10094 if (!filter.equals(c.binding.intent.intent)) {
10095 if (DEBUG_SERVICE) Log.v(
10096 TAG, "Not publishing to: " + c);
10097 if (DEBUG_SERVICE) Log.v(
10098 TAG, "Bound intent: " + c.binding.intent.intent);
10099 if (DEBUG_SERVICE) Log.v(
10100 TAG, "Published intent: " + intent);
10101 continue;
10102 }
10103 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10104 try {
10105 c.conn.connected(r.name, service);
10106 } catch (Exception e) {
10107 Log.w(TAG, "Failure sending service " + r.name +
10108 " to connection " + c.conn.asBinder() +
10109 " (in " + c.binding.client.processName + ")", e);
10110 }
10111 }
10112 }
10113 }
10114
10115 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10116
10117 Binder.restoreCallingIdentity(origId);
10118 }
10119 }
10120 }
10121
10122 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10123 // Refuse possible leaked file descriptors
10124 if (intent != null && intent.hasFileDescriptors() == true) {
10125 throw new IllegalArgumentException("File descriptors passed in Intent");
10126 }
10127
10128 synchronized(this) {
10129 if (!(token instanceof ServiceRecord)) {
10130 throw new IllegalArgumentException("Invalid service token");
10131 }
10132 ServiceRecord r = (ServiceRecord)token;
10133
10134 final long origId = Binder.clearCallingIdentity();
10135
10136 if (r != null) {
10137 Intent.FilterComparison filter
10138 = new Intent.FilterComparison(intent);
10139 IntentBindRecord b = r.bindings.get(filter);
10140 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10141 + " at " + b + ": apps="
10142 + (b != null ? b.apps.size() : 0));
10143 if (b != null) {
10144 if (b.apps.size() > 0) {
10145 // Applications have already bound since the last
10146 // unbind, so just rebind right here.
10147 requestServiceBindingLocked(r, b, true);
10148 } else {
10149 // Note to tell the service the next time there is
10150 // a new client.
10151 b.doRebind = true;
10152 }
10153 }
10154
10155 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10156
10157 Binder.restoreCallingIdentity(origId);
10158 }
10159 }
10160 }
10161
10162 public void serviceDoneExecuting(IBinder token) {
10163 synchronized(this) {
10164 if (!(token instanceof ServiceRecord)) {
10165 throw new IllegalArgumentException("Invalid service token");
10166 }
10167 ServiceRecord r = (ServiceRecord)token;
10168 boolean inStopping = mStoppingServices.contains(token);
10169 if (r != null) {
10170 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10171 + ": nesting=" + r.executeNesting
10172 + ", inStopping=" + inStopping);
10173 if (r != token) {
10174 Log.w(TAG, "Done executing service " + r.name
10175 + " with incorrect token: given " + token
10176 + ", expected " + r);
10177 return;
10178 }
10179
10180 final long origId = Binder.clearCallingIdentity();
10181 serviceDoneExecutingLocked(r, inStopping);
10182 Binder.restoreCallingIdentity(origId);
10183 } else {
10184 Log.w(TAG, "Done executing unknown service " + r.name
10185 + " with token " + token);
10186 }
10187 }
10188 }
10189
10190 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10191 r.executeNesting--;
10192 if (r.executeNesting <= 0 && r.app != null) {
10193 r.app.executingServices.remove(r);
10194 if (r.app.executingServices.size() == 0) {
10195 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10196 }
10197 if (inStopping) {
10198 mStoppingServices.remove(r);
10199 }
10200 updateOomAdjLocked(r.app);
10201 }
10202 }
10203
10204 void serviceTimeout(ProcessRecord proc) {
10205 synchronized(this) {
10206 if (proc.executingServices.size() == 0 || proc.thread == null) {
10207 return;
10208 }
10209 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10210 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10211 ServiceRecord timeout = null;
10212 long nextTime = 0;
10213 while (it.hasNext()) {
10214 ServiceRecord sr = it.next();
10215 if (sr.executingStart < maxTime) {
10216 timeout = sr;
10217 break;
10218 }
10219 if (sr.executingStart > nextTime) {
10220 nextTime = sr.executingStart;
10221 }
10222 }
10223 if (timeout != null && mLRUProcesses.contains(proc)) {
10224 Log.w(TAG, "Timeout executing service: " + timeout);
10225 appNotRespondingLocked(proc, null, "Executing service "
10226 + timeout.name);
10227 } else {
10228 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10229 msg.obj = proc;
10230 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10231 }
10232 }
10233 }
10234
10235 // =========================================================
10236 // BROADCASTS
10237 // =========================================================
10238
10239 private final List getStickies(String action, IntentFilter filter,
10240 List cur) {
10241 final ContentResolver resolver = mContext.getContentResolver();
10242 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10243 if (list == null) {
10244 return cur;
10245 }
10246 int N = list.size();
10247 for (int i=0; i<N; i++) {
10248 Intent intent = list.get(i);
10249 if (filter.match(resolver, intent, true, TAG) >= 0) {
10250 if (cur == null) {
10251 cur = new ArrayList<Intent>();
10252 }
10253 cur.add(intent);
10254 }
10255 }
10256 return cur;
10257 }
10258
10259 private final void scheduleBroadcastsLocked() {
10260 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10261 + mBroadcastsScheduled);
10262
10263 if (mBroadcastsScheduled) {
10264 return;
10265 }
10266 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10267 mBroadcastsScheduled = true;
10268 }
10269
10270 public Intent registerReceiver(IApplicationThread caller,
10271 IIntentReceiver receiver, IntentFilter filter, String permission) {
10272 synchronized(this) {
10273 ProcessRecord callerApp = null;
10274 if (caller != null) {
10275 callerApp = getRecordForAppLocked(caller);
10276 if (callerApp == null) {
10277 throw new SecurityException(
10278 "Unable to find app for caller " + caller
10279 + " (pid=" + Binder.getCallingPid()
10280 + ") when registering receiver " + receiver);
10281 }
10282 }
10283
10284 List allSticky = null;
10285
10286 // Look for any matching sticky broadcasts...
10287 Iterator actions = filter.actionsIterator();
10288 if (actions != null) {
10289 while (actions.hasNext()) {
10290 String action = (String)actions.next();
10291 allSticky = getStickies(action, filter, allSticky);
10292 }
10293 } else {
10294 allSticky = getStickies(null, filter, allSticky);
10295 }
10296
10297 // The first sticky in the list is returned directly back to
10298 // the client.
10299 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10300
10301 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10302 + ": " + sticky);
10303
10304 if (receiver == null) {
10305 return sticky;
10306 }
10307
10308 ReceiverList rl
10309 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10310 if (rl == null) {
10311 rl = new ReceiverList(this, callerApp,
10312 Binder.getCallingPid(),
10313 Binder.getCallingUid(), receiver);
10314 if (rl.app != null) {
10315 rl.app.receivers.add(rl);
10316 } else {
10317 try {
10318 receiver.asBinder().linkToDeath(rl, 0);
10319 } catch (RemoteException e) {
10320 return sticky;
10321 }
10322 rl.linkedToDeath = true;
10323 }
10324 mRegisteredReceivers.put(receiver.asBinder(), rl);
10325 }
10326 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10327 rl.add(bf);
10328 if (!bf.debugCheck()) {
10329 Log.w(TAG, "==> For Dynamic broadast");
10330 }
10331 mReceiverResolver.addFilter(bf);
10332
10333 // Enqueue broadcasts for all existing stickies that match
10334 // this filter.
10335 if (allSticky != null) {
10336 ArrayList receivers = new ArrayList();
10337 receivers.add(bf);
10338
10339 int N = allSticky.size();
10340 for (int i=0; i<N; i++) {
10341 Intent intent = (Intent)allSticky.get(i);
10342 BroadcastRecord r = new BroadcastRecord(intent, null,
10343 null, -1, -1, null, receivers, null, 0, null, null,
10344 false);
10345 if (mParallelBroadcasts.size() == 0) {
10346 scheduleBroadcastsLocked();
10347 }
10348 mParallelBroadcasts.add(r);
10349 }
10350 }
10351
10352 return sticky;
10353 }
10354 }
10355
10356 public void unregisterReceiver(IIntentReceiver receiver) {
10357 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10358
10359 boolean doNext = false;
10360
10361 synchronized(this) {
10362 ReceiverList rl
10363 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10364 if (rl != null) {
10365 if (rl.curBroadcast != null) {
10366 BroadcastRecord r = rl.curBroadcast;
10367 doNext = finishReceiverLocked(
10368 receiver.asBinder(), r.resultCode, r.resultData,
10369 r.resultExtras, r.resultAbort, true);
10370 }
10371
10372 if (rl.app != null) {
10373 rl.app.receivers.remove(rl);
10374 }
10375 removeReceiverLocked(rl);
10376 if (rl.linkedToDeath) {
10377 rl.linkedToDeath = false;
10378 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10379 }
10380 }
10381 }
10382
10383 if (!doNext) {
10384 return;
10385 }
10386
10387 final long origId = Binder.clearCallingIdentity();
10388 processNextBroadcast(false);
10389 trimApplications();
10390 Binder.restoreCallingIdentity(origId);
10391 }
10392
10393 void removeReceiverLocked(ReceiverList rl) {
10394 mRegisteredReceivers.remove(rl.receiver.asBinder());
10395 int N = rl.size();
10396 for (int i=0; i<N; i++) {
10397 mReceiverResolver.removeFilter(rl.get(i));
10398 }
10399 }
10400
10401 private final int broadcastIntentLocked(ProcessRecord callerApp,
10402 String callerPackage, Intent intent, String resolvedType,
10403 IIntentReceiver resultTo, int resultCode, String resultData,
10404 Bundle map, String requiredPermission,
10405 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10406 intent = new Intent(intent);
10407
10408 if (DEBUG_BROADCAST) Log.v(
10409 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10410 + " ordered=" + ordered);
10411 if ((resultTo != null) && !ordered) {
10412 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10413 }
10414
10415 // Handle special intents: if this broadcast is from the package
10416 // manager about a package being removed, we need to remove all of
10417 // its activities from the history stack.
10418 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10419 intent.getAction());
10420 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10421 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10422 || uidRemoved) {
10423 if (checkComponentPermission(
10424 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10425 callingPid, callingUid, -1)
10426 == PackageManager.PERMISSION_GRANTED) {
10427 if (uidRemoved) {
10428 final Bundle intentExtras = intent.getExtras();
10429 final int uid = intentExtras != null
10430 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10431 if (uid >= 0) {
10432 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10433 synchronized (bs) {
10434 bs.removeUidStatsLocked(uid);
10435 }
10436 }
10437 } else {
10438 Uri data = intent.getData();
10439 String ssp;
10440 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10441 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10442 uninstallPackageLocked(ssp,
10443 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10444 }
10445 }
10446 }
10447 } else {
10448 String msg = "Permission Denial: " + intent.getAction()
10449 + " broadcast from " + callerPackage + " (pid=" + callingPid
10450 + ", uid=" + callingUid + ")"
10451 + " requires "
10452 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10453 Log.w(TAG, msg);
10454 throw new SecurityException(msg);
10455 }
10456 }
10457
10458 /*
10459 * If this is the time zone changed action, queue up a message that will reset the timezone
10460 * of all currently running processes. This message will get queued up before the broadcast
10461 * happens.
10462 */
10463 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10464 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10465 }
10466
10467 // Add to the sticky list if requested.
10468 if (sticky) {
10469 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10470 callingPid, callingUid)
10471 != PackageManager.PERMISSION_GRANTED) {
10472 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10473 + callingPid + ", uid=" + callingUid
10474 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10475 Log.w(TAG, msg);
10476 throw new SecurityException(msg);
10477 }
10478 if (requiredPermission != null) {
10479 Log.w(TAG, "Can't broadcast sticky intent " + intent
10480 + " and enforce permission " + requiredPermission);
10481 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10482 }
10483 if (intent.getComponent() != null) {
10484 throw new SecurityException(
10485 "Sticky broadcasts can't target a specific component");
10486 }
10487 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10488 if (list == null) {
10489 list = new ArrayList<Intent>();
10490 mStickyBroadcasts.put(intent.getAction(), list);
10491 }
10492 int N = list.size();
10493 int i;
10494 for (i=0; i<N; i++) {
10495 if (intent.filterEquals(list.get(i))) {
10496 // This sticky already exists, replace it.
10497 list.set(i, new Intent(intent));
10498 break;
10499 }
10500 }
10501 if (i >= N) {
10502 list.add(new Intent(intent));
10503 }
10504 }
10505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010506 // Figure out who all will receive this broadcast.
10507 List receivers = null;
10508 List<BroadcastFilter> registeredReceivers = null;
10509 try {
10510 if (intent.getComponent() != null) {
10511 // Broadcast is going to one specific receiver class...
10512 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010513 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010514 if (ai != null) {
10515 receivers = new ArrayList();
10516 ResolveInfo ri = new ResolveInfo();
10517 ri.activityInfo = ai;
10518 receivers.add(ri);
10519 }
10520 } else {
10521 // Need to resolve the intent to interested receivers...
10522 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10523 == 0) {
10524 receivers =
10525 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010526 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010527 }
Mihai Preda074edef2009-05-18 17:13:31 +020010528 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010529 }
10530 } catch (RemoteException ex) {
10531 // pm is in same process, this will never happen.
10532 }
10533
10534 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10535 if (!ordered && NR > 0) {
10536 // If we are not serializing this broadcast, then send the
10537 // registered receivers separately so they don't wait for the
10538 // components to be launched.
10539 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10540 callerPackage, callingPid, callingUid, requiredPermission,
10541 registeredReceivers, resultTo, resultCode, resultData, map,
10542 ordered);
10543 if (DEBUG_BROADCAST) Log.v(
10544 TAG, "Enqueueing parallel broadcast " + r
10545 + ": prev had " + mParallelBroadcasts.size());
10546 mParallelBroadcasts.add(r);
10547 scheduleBroadcastsLocked();
10548 registeredReceivers = null;
10549 NR = 0;
10550 }
10551
10552 // Merge into one list.
10553 int ir = 0;
10554 if (receivers != null) {
10555 // A special case for PACKAGE_ADDED: do not allow the package
10556 // being added to see this broadcast. This prevents them from
10557 // using this as a back door to get run as soon as they are
10558 // installed. Maybe in the future we want to have a special install
10559 // broadcast or such for apps, but we'd like to deliberately make
10560 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010561 boolean skip = false;
10562 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010563 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010564 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10565 skip = true;
10566 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10567 skip = true;
10568 }
10569 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010570 ? intent.getData().getSchemeSpecificPart()
10571 : null;
10572 if (skipPackage != null && receivers != null) {
10573 int NT = receivers.size();
10574 for (int it=0; it<NT; it++) {
10575 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10576 if (curt.activityInfo.packageName.equals(skipPackage)) {
10577 receivers.remove(it);
10578 it--;
10579 NT--;
10580 }
10581 }
10582 }
10583
10584 int NT = receivers != null ? receivers.size() : 0;
10585 int it = 0;
10586 ResolveInfo curt = null;
10587 BroadcastFilter curr = null;
10588 while (it < NT && ir < NR) {
10589 if (curt == null) {
10590 curt = (ResolveInfo)receivers.get(it);
10591 }
10592 if (curr == null) {
10593 curr = registeredReceivers.get(ir);
10594 }
10595 if (curr.getPriority() >= curt.priority) {
10596 // Insert this broadcast record into the final list.
10597 receivers.add(it, curr);
10598 ir++;
10599 curr = null;
10600 it++;
10601 NT++;
10602 } else {
10603 // Skip to the next ResolveInfo in the final list.
10604 it++;
10605 curt = null;
10606 }
10607 }
10608 }
10609 while (ir < NR) {
10610 if (receivers == null) {
10611 receivers = new ArrayList();
10612 }
10613 receivers.add(registeredReceivers.get(ir));
10614 ir++;
10615 }
10616
10617 if ((receivers != null && receivers.size() > 0)
10618 || resultTo != null) {
10619 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10620 callerPackage, callingPid, callingUid, requiredPermission,
10621 receivers, resultTo, resultCode, resultData, map, ordered);
10622 if (DEBUG_BROADCAST) Log.v(
10623 TAG, "Enqueueing ordered broadcast " + r
10624 + ": prev had " + mOrderedBroadcasts.size());
10625 if (DEBUG_BROADCAST) {
10626 int seq = r.intent.getIntExtra("seq", -1);
10627 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10628 }
10629 mOrderedBroadcasts.add(r);
10630 scheduleBroadcastsLocked();
10631 }
10632
10633 return BROADCAST_SUCCESS;
10634 }
10635
10636 public final int broadcastIntent(IApplicationThread caller,
10637 Intent intent, String resolvedType, IIntentReceiver resultTo,
10638 int resultCode, String resultData, Bundle map,
10639 String requiredPermission, boolean serialized, boolean sticky) {
10640 // Refuse possible leaked file descriptors
10641 if (intent != null && intent.hasFileDescriptors() == true) {
10642 throw new IllegalArgumentException("File descriptors passed in Intent");
10643 }
10644
10645 synchronized(this) {
10646 if (!mSystemReady) {
10647 // if the caller really truly claims to know what they're doing, go
10648 // ahead and allow the broadcast without launching any receivers
10649 int flags = intent.getFlags();
10650 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10651 intent = new Intent(intent);
10652 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10653 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10654 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10655 + " before boot completion");
10656 throw new IllegalStateException("Cannot broadcast before boot completed");
10657 }
10658 }
10659
10660 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10661 final int callingPid = Binder.getCallingPid();
10662 final int callingUid = Binder.getCallingUid();
10663 final long origId = Binder.clearCallingIdentity();
10664 int res = broadcastIntentLocked(callerApp,
10665 callerApp != null ? callerApp.info.packageName : null,
10666 intent, resolvedType, resultTo,
10667 resultCode, resultData, map, requiredPermission, serialized,
10668 sticky, callingPid, callingUid);
10669 Binder.restoreCallingIdentity(origId);
10670 return res;
10671 }
10672 }
10673
10674 int broadcastIntentInPackage(String packageName, int uid,
10675 Intent intent, String resolvedType, IIntentReceiver resultTo,
10676 int resultCode, String resultData, Bundle map,
10677 String requiredPermission, boolean serialized, boolean sticky) {
10678 synchronized(this) {
10679 final long origId = Binder.clearCallingIdentity();
10680 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10681 resultTo, resultCode, resultData, map, requiredPermission,
10682 serialized, sticky, -1, uid);
10683 Binder.restoreCallingIdentity(origId);
10684 return res;
10685 }
10686 }
10687
10688 public final void unbroadcastIntent(IApplicationThread caller,
10689 Intent intent) {
10690 // Refuse possible leaked file descriptors
10691 if (intent != null && intent.hasFileDescriptors() == true) {
10692 throw new IllegalArgumentException("File descriptors passed in Intent");
10693 }
10694
10695 synchronized(this) {
10696 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10697 != PackageManager.PERMISSION_GRANTED) {
10698 String msg = "Permission Denial: unbroadcastIntent() from pid="
10699 + Binder.getCallingPid()
10700 + ", uid=" + Binder.getCallingUid()
10701 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10702 Log.w(TAG, msg);
10703 throw new SecurityException(msg);
10704 }
10705 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10706 if (list != null) {
10707 int N = list.size();
10708 int i;
10709 for (i=0; i<N; i++) {
10710 if (intent.filterEquals(list.get(i))) {
10711 list.remove(i);
10712 break;
10713 }
10714 }
10715 }
10716 }
10717 }
10718
10719 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10720 String resultData, Bundle resultExtras, boolean resultAbort,
10721 boolean explicit) {
10722 if (mOrderedBroadcasts.size() == 0) {
10723 if (explicit) {
10724 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10725 }
10726 return false;
10727 }
10728 BroadcastRecord r = mOrderedBroadcasts.get(0);
10729 if (r.receiver == null) {
10730 if (explicit) {
10731 Log.w(TAG, "finishReceiver called but none active");
10732 }
10733 return false;
10734 }
10735 if (r.receiver != receiver) {
10736 Log.w(TAG, "finishReceiver called but active receiver is different");
10737 return false;
10738 }
10739 int state = r.state;
10740 r.state = r.IDLE;
10741 if (state == r.IDLE) {
10742 if (explicit) {
10743 Log.w(TAG, "finishReceiver called but state is IDLE");
10744 }
10745 }
10746 r.receiver = null;
10747 r.intent.setComponent(null);
10748 if (r.curApp != null) {
10749 r.curApp.curReceiver = null;
10750 }
10751 if (r.curFilter != null) {
10752 r.curFilter.receiverList.curBroadcast = null;
10753 }
10754 r.curFilter = null;
10755 r.curApp = null;
10756 r.curComponent = null;
10757 r.curReceiver = null;
10758 mPendingBroadcast = null;
10759
10760 r.resultCode = resultCode;
10761 r.resultData = resultData;
10762 r.resultExtras = resultExtras;
10763 r.resultAbort = resultAbort;
10764
10765 // We will process the next receiver right now if this is finishing
10766 // an app receiver (which is always asynchronous) or after we have
10767 // come back from calling a receiver.
10768 return state == BroadcastRecord.APP_RECEIVE
10769 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10770 }
10771
10772 public void finishReceiver(IBinder who, int resultCode, String resultData,
10773 Bundle resultExtras, boolean resultAbort) {
10774 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10775
10776 // Refuse possible leaked file descriptors
10777 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10778 throw new IllegalArgumentException("File descriptors passed in Bundle");
10779 }
10780
10781 boolean doNext;
10782
10783 final long origId = Binder.clearCallingIdentity();
10784
10785 synchronized(this) {
10786 doNext = finishReceiverLocked(
10787 who, resultCode, resultData, resultExtras, resultAbort, true);
10788 }
10789
10790 if (doNext) {
10791 processNextBroadcast(false);
10792 }
10793 trimApplications();
10794
10795 Binder.restoreCallingIdentity(origId);
10796 }
10797
10798 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10799 if (r.nextReceiver > 0) {
10800 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10801 if (curReceiver instanceof BroadcastFilter) {
10802 BroadcastFilter bf = (BroadcastFilter) curReceiver;
10803 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
10804 System.identityHashCode(r),
10805 r.intent.getAction(),
10806 r.nextReceiver - 1,
10807 System.identityHashCode(bf));
10808 } else {
10809 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10810 System.identityHashCode(r),
10811 r.intent.getAction(),
10812 r.nextReceiver - 1,
10813 ((ResolveInfo)curReceiver).toString());
10814 }
10815 } else {
10816 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
10817 + r);
10818 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10819 System.identityHashCode(r),
10820 r.intent.getAction(),
10821 r.nextReceiver,
10822 "NONE");
10823 }
10824 }
10825
10826 private final void broadcastTimeout() {
10827 synchronized (this) {
10828 if (mOrderedBroadcasts.size() == 0) {
10829 return;
10830 }
10831 long now = SystemClock.uptimeMillis();
10832 BroadcastRecord r = mOrderedBroadcasts.get(0);
10833 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
10834 if (DEBUG_BROADCAST) Log.v(TAG,
10835 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
10836 + (r.startTime + BROADCAST_TIMEOUT));
10837 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
10838 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
10839 return;
10840 }
10841
10842 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
10843 r.startTime = now;
10844 r.anrCount++;
10845
10846 // Current receiver has passed its expiration date.
10847 if (r.nextReceiver <= 0) {
10848 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
10849 return;
10850 }
10851
10852 ProcessRecord app = null;
10853
10854 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10855 Log.w(TAG, "Receiver during timeout: " + curReceiver);
10856 logBroadcastReceiverDiscard(r);
10857 if (curReceiver instanceof BroadcastFilter) {
10858 BroadcastFilter bf = (BroadcastFilter)curReceiver;
10859 if (bf.receiverList.pid != 0
10860 && bf.receiverList.pid != MY_PID) {
10861 synchronized (this.mPidsSelfLocked) {
10862 app = this.mPidsSelfLocked.get(
10863 bf.receiverList.pid);
10864 }
10865 }
10866 } else {
10867 app = r.curApp;
10868 }
10869
10870 if (app != null) {
10871 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
10872 }
10873
10874 if (mPendingBroadcast == r) {
10875 mPendingBroadcast = null;
10876 }
10877
10878 // Move on to the next receiver.
10879 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
10880 r.resultExtras, r.resultAbort, true);
10881 scheduleBroadcastsLocked();
10882 }
10883 }
10884
10885 private final void processCurBroadcastLocked(BroadcastRecord r,
10886 ProcessRecord app) throws RemoteException {
10887 if (app.thread == null) {
10888 throw new RemoteException();
10889 }
10890 r.receiver = app.thread.asBinder();
10891 r.curApp = app;
10892 app.curReceiver = r;
10893 updateLRUListLocked(app, true);
10894
10895 // Tell the application to launch this receiver.
10896 r.intent.setComponent(r.curComponent);
10897
10898 boolean started = false;
10899 try {
10900 if (DEBUG_BROADCAST) Log.v(TAG,
10901 "Delivering to component " + r.curComponent
10902 + ": " + r);
10903 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
10904 r.resultCode, r.resultData, r.resultExtras, r.ordered);
10905 started = true;
10906 } finally {
10907 if (!started) {
10908 r.receiver = null;
10909 r.curApp = null;
10910 app.curReceiver = null;
10911 }
10912 }
10913
10914 }
10915
10916 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
10917 Intent intent, int resultCode, String data,
10918 Bundle extras, boolean ordered) throws RemoteException {
10919 if (app != null && app.thread != null) {
10920 // If we have an app thread, do the call through that so it is
10921 // correctly ordered with other one-way calls.
10922 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
10923 data, extras, ordered);
10924 } else {
10925 receiver.performReceive(intent, resultCode, data, extras, ordered);
10926 }
10927 }
10928
10929 private final void deliverToRegisteredReceiver(BroadcastRecord r,
10930 BroadcastFilter filter, boolean ordered) {
10931 boolean skip = false;
10932 if (filter.requiredPermission != null) {
10933 int perm = checkComponentPermission(filter.requiredPermission,
10934 r.callingPid, r.callingUid, -1);
10935 if (perm != PackageManager.PERMISSION_GRANTED) {
10936 Log.w(TAG, "Permission Denial: broadcasting "
10937 + r.intent.toString()
10938 + " from " + r.callerPackage + " (pid="
10939 + r.callingPid + ", uid=" + r.callingUid + ")"
10940 + " requires " + filter.requiredPermission
10941 + " due to registered receiver " + filter);
10942 skip = true;
10943 }
10944 }
10945 if (r.requiredPermission != null) {
10946 int perm = checkComponentPermission(r.requiredPermission,
10947 filter.receiverList.pid, filter.receiverList.uid, -1);
10948 if (perm != PackageManager.PERMISSION_GRANTED) {
10949 Log.w(TAG, "Permission Denial: receiving "
10950 + r.intent.toString()
10951 + " to " + filter.receiverList.app
10952 + " (pid=" + filter.receiverList.pid
10953 + ", uid=" + filter.receiverList.uid + ")"
10954 + " requires " + r.requiredPermission
10955 + " due to sender " + r.callerPackage
10956 + " (uid " + r.callingUid + ")");
10957 skip = true;
10958 }
10959 }
10960
10961 if (!skip) {
10962 // If this is not being sent as an ordered broadcast, then we
10963 // don't want to touch the fields that keep track of the current
10964 // state of ordered broadcasts.
10965 if (ordered) {
10966 r.receiver = filter.receiverList.receiver.asBinder();
10967 r.curFilter = filter;
10968 filter.receiverList.curBroadcast = r;
10969 r.state = BroadcastRecord.CALL_IN_RECEIVE;
10970 }
10971 try {
10972 if (DEBUG_BROADCAST) {
10973 int seq = r.intent.getIntExtra("seq", -1);
10974 Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
10975 + " app=" + filter.receiverList.app);
10976 }
10977 performReceive(filter.receiverList.app, filter.receiverList.receiver,
10978 new Intent(r.intent), r.resultCode,
10979 r.resultData, r.resultExtras, r.ordered);
10980 if (ordered) {
10981 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
10982 }
10983 } catch (RemoteException e) {
10984 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
10985 if (ordered) {
10986 r.receiver = null;
10987 r.curFilter = null;
10988 filter.receiverList.curBroadcast = null;
10989 }
10990 }
10991 }
10992 }
10993
10994 private final void processNextBroadcast(boolean fromMsg) {
10995 synchronized(this) {
10996 BroadcastRecord r;
10997
10998 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
10999 + mParallelBroadcasts.size() + " broadcasts, "
11000 + mOrderedBroadcasts.size() + " serialized broadcasts");
11001
11002 updateCpuStats();
11003
11004 if (fromMsg) {
11005 mBroadcastsScheduled = false;
11006 }
11007
11008 // First, deliver any non-serialized broadcasts right away.
11009 while (mParallelBroadcasts.size() > 0) {
11010 r = mParallelBroadcasts.remove(0);
11011 final int N = r.receivers.size();
11012 for (int i=0; i<N; i++) {
11013 Object target = r.receivers.get(i);
11014 if (DEBUG_BROADCAST) Log.v(TAG,
11015 "Delivering non-serialized to registered "
11016 + target + ": " + r);
11017 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11018 }
11019 }
11020
11021 // Now take care of the next serialized one...
11022
11023 // If we are waiting for a process to come up to handle the next
11024 // broadcast, then do nothing at this point. Just in case, we
11025 // check that the process we're waiting for still exists.
11026 if (mPendingBroadcast != null) {
11027 Log.i(TAG, "processNextBroadcast: waiting for "
11028 + mPendingBroadcast.curApp);
11029
11030 boolean isDead;
11031 synchronized (mPidsSelfLocked) {
11032 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11033 }
11034 if (!isDead) {
11035 // It's still alive, so keep waiting
11036 return;
11037 } else {
11038 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11039 + " died before responding to broadcast");
11040 mPendingBroadcast = null;
11041 }
11042 }
11043
11044 do {
11045 if (mOrderedBroadcasts.size() == 0) {
11046 // No more broadcasts pending, so all done!
11047 scheduleAppGcsLocked();
11048 return;
11049 }
11050 r = mOrderedBroadcasts.get(0);
11051 boolean forceReceive = false;
11052
11053 // Ensure that even if something goes awry with the timeout
11054 // detection, we catch "hung" broadcasts here, discard them,
11055 // and continue to make progress.
11056 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11057 long now = SystemClock.uptimeMillis();
11058 if (r.dispatchTime > 0) {
11059 if ((numReceivers > 0) &&
11060 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11061 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11062 + " now=" + now
11063 + " dispatchTime=" + r.dispatchTime
11064 + " startTime=" + r.startTime
11065 + " intent=" + r.intent
11066 + " numReceivers=" + numReceivers
11067 + " nextReceiver=" + r.nextReceiver
11068 + " state=" + r.state);
11069 broadcastTimeout(); // forcibly finish this broadcast
11070 forceReceive = true;
11071 r.state = BroadcastRecord.IDLE;
11072 }
11073 }
11074
11075 if (r.state != BroadcastRecord.IDLE) {
11076 if (DEBUG_BROADCAST) Log.d(TAG,
11077 "processNextBroadcast() called when not idle (state="
11078 + r.state + ")");
11079 return;
11080 }
11081
11082 if (r.receivers == null || r.nextReceiver >= numReceivers
11083 || r.resultAbort || forceReceive) {
11084 // No more receivers for this broadcast! Send the final
11085 // result if requested...
11086 if (r.resultTo != null) {
11087 try {
11088 if (DEBUG_BROADCAST) {
11089 int seq = r.intent.getIntExtra("seq", -1);
11090 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11091 + " seq=" + seq + " app=" + r.callerApp);
11092 }
11093 performReceive(r.callerApp, r.resultTo,
11094 new Intent(r.intent), r.resultCode,
11095 r.resultData, r.resultExtras, false);
11096 } catch (RemoteException e) {
11097 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11098 }
11099 }
11100
11101 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11102 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11103
11104 // ... and on to the next...
11105 mOrderedBroadcasts.remove(0);
11106 r = null;
11107 continue;
11108 }
11109 } while (r == null);
11110
11111 // Get the next receiver...
11112 int recIdx = r.nextReceiver++;
11113
11114 // Keep track of when this receiver started, and make sure there
11115 // is a timeout message pending to kill it if need be.
11116 r.startTime = SystemClock.uptimeMillis();
11117 if (recIdx == 0) {
11118 r.dispatchTime = r.startTime;
11119
11120 if (DEBUG_BROADCAST) Log.v(TAG,
11121 "Submitting BROADCAST_TIMEOUT_MSG for "
11122 + (r.startTime + BROADCAST_TIMEOUT));
11123 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11124 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11125 }
11126
11127 Object nextReceiver = r.receivers.get(recIdx);
11128 if (nextReceiver instanceof BroadcastFilter) {
11129 // Simple case: this is a registered receiver who gets
11130 // a direct call.
11131 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11132 if (DEBUG_BROADCAST) Log.v(TAG,
11133 "Delivering serialized to registered "
11134 + filter + ": " + r);
11135 deliverToRegisteredReceiver(r, filter, r.ordered);
11136 if (r.receiver == null || !r.ordered) {
11137 // The receiver has already finished, so schedule to
11138 // process the next one.
11139 r.state = BroadcastRecord.IDLE;
11140 scheduleBroadcastsLocked();
11141 }
11142 return;
11143 }
11144
11145 // Hard case: need to instantiate the receiver, possibly
11146 // starting its application process to host it.
11147
11148 ResolveInfo info =
11149 (ResolveInfo)nextReceiver;
11150
11151 boolean skip = false;
11152 int perm = checkComponentPermission(info.activityInfo.permission,
11153 r.callingPid, r.callingUid,
11154 info.activityInfo.exported
11155 ? -1 : info.activityInfo.applicationInfo.uid);
11156 if (perm != PackageManager.PERMISSION_GRANTED) {
11157 Log.w(TAG, "Permission Denial: broadcasting "
11158 + r.intent.toString()
11159 + " from " + r.callerPackage + " (pid=" + r.callingPid
11160 + ", uid=" + r.callingUid + ")"
11161 + " requires " + info.activityInfo.permission
11162 + " due to receiver " + info.activityInfo.packageName
11163 + "/" + info.activityInfo.name);
11164 skip = true;
11165 }
11166 if (r.callingUid != Process.SYSTEM_UID &&
11167 r.requiredPermission != null) {
11168 try {
11169 perm = ActivityThread.getPackageManager().
11170 checkPermission(r.requiredPermission,
11171 info.activityInfo.applicationInfo.packageName);
11172 } catch (RemoteException e) {
11173 perm = PackageManager.PERMISSION_DENIED;
11174 }
11175 if (perm != PackageManager.PERMISSION_GRANTED) {
11176 Log.w(TAG, "Permission Denial: receiving "
11177 + r.intent + " to "
11178 + info.activityInfo.applicationInfo.packageName
11179 + " requires " + r.requiredPermission
11180 + " due to sender " + r.callerPackage
11181 + " (uid " + r.callingUid + ")");
11182 skip = true;
11183 }
11184 }
11185 if (r.curApp != null && r.curApp.crashing) {
11186 // If the target process is crashing, just skip it.
11187 skip = true;
11188 }
11189
11190 if (skip) {
11191 r.receiver = null;
11192 r.curFilter = null;
11193 r.state = BroadcastRecord.IDLE;
11194 scheduleBroadcastsLocked();
11195 return;
11196 }
11197
11198 r.state = BroadcastRecord.APP_RECEIVE;
11199 String targetProcess = info.activityInfo.processName;
11200 r.curComponent = new ComponentName(
11201 info.activityInfo.applicationInfo.packageName,
11202 info.activityInfo.name);
11203 r.curReceiver = info.activityInfo;
11204
11205 // Is this receiver's application already running?
11206 ProcessRecord app = getProcessRecordLocked(targetProcess,
11207 info.activityInfo.applicationInfo.uid);
11208 if (app != null && app.thread != null) {
11209 try {
11210 processCurBroadcastLocked(r, app);
11211 return;
11212 } catch (RemoteException e) {
11213 Log.w(TAG, "Exception when sending broadcast to "
11214 + r.curComponent, e);
11215 }
11216
11217 // If a dead object exception was thrown -- fall through to
11218 // restart the application.
11219 }
11220
11221 // Not running -- get it started, and enqueue this history record
11222 // to be executed when the app comes up.
11223 if ((r.curApp=startProcessLocked(targetProcess,
11224 info.activityInfo.applicationInfo, true,
11225 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11226 "broadcast", r.curComponent)) == null) {
11227 // Ah, this recipient is unavailable. Finish it if necessary,
11228 // and mark the broadcast record as ready for the next.
11229 Log.w(TAG, "Unable to launch app "
11230 + info.activityInfo.applicationInfo.packageName + "/"
11231 + info.activityInfo.applicationInfo.uid + " for broadcast "
11232 + r.intent + ": process is bad");
11233 logBroadcastReceiverDiscard(r);
11234 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11235 r.resultExtras, r.resultAbort, true);
11236 scheduleBroadcastsLocked();
11237 r.state = BroadcastRecord.IDLE;
11238 return;
11239 }
11240
11241 mPendingBroadcast = r;
11242 }
11243 }
11244
11245 // =========================================================
11246 // INSTRUMENTATION
11247 // =========================================================
11248
11249 public boolean startInstrumentation(ComponentName className,
11250 String profileFile, int flags, Bundle arguments,
11251 IInstrumentationWatcher watcher) {
11252 // Refuse possible leaked file descriptors
11253 if (arguments != null && arguments.hasFileDescriptors()) {
11254 throw new IllegalArgumentException("File descriptors passed in Bundle");
11255 }
11256
11257 synchronized(this) {
11258 InstrumentationInfo ii = null;
11259 ApplicationInfo ai = null;
11260 try {
11261 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011262 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011263 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011264 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011265 } catch (PackageManager.NameNotFoundException e) {
11266 }
11267 if (ii == null) {
11268 reportStartInstrumentationFailure(watcher, className,
11269 "Unable to find instrumentation info for: " + className);
11270 return false;
11271 }
11272 if (ai == null) {
11273 reportStartInstrumentationFailure(watcher, className,
11274 "Unable to find instrumentation target package: " + ii.targetPackage);
11275 return false;
11276 }
11277
11278 int match = mContext.getPackageManager().checkSignatures(
11279 ii.targetPackage, ii.packageName);
11280 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11281 String msg = "Permission Denial: starting instrumentation "
11282 + className + " from pid="
11283 + Binder.getCallingPid()
11284 + ", uid=" + Binder.getCallingPid()
11285 + " not allowed because package " + ii.packageName
11286 + " does not have a signature matching the target "
11287 + ii.targetPackage;
11288 reportStartInstrumentationFailure(watcher, className, msg);
11289 throw new SecurityException(msg);
11290 }
11291
11292 final long origId = Binder.clearCallingIdentity();
11293 uninstallPackageLocked(ii.targetPackage, -1, true);
11294 ProcessRecord app = addAppLocked(ai);
11295 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011296 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011297 app.instrumentationProfileFile = profileFile;
11298 app.instrumentationArguments = arguments;
11299 app.instrumentationWatcher = watcher;
11300 app.instrumentationResultClass = className;
11301 Binder.restoreCallingIdentity(origId);
11302 }
11303
11304 return true;
11305 }
11306
11307 /**
11308 * Report errors that occur while attempting to start Instrumentation. Always writes the
11309 * error to the logs, but if somebody is watching, send the report there too. This enables
11310 * the "am" command to report errors with more information.
11311 *
11312 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11313 * @param cn The component name of the instrumentation.
11314 * @param report The error report.
11315 */
11316 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11317 ComponentName cn, String report) {
11318 Log.w(TAG, report);
11319 try {
11320 if (watcher != null) {
11321 Bundle results = new Bundle();
11322 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11323 results.putString("Error", report);
11324 watcher.instrumentationStatus(cn, -1, results);
11325 }
11326 } catch (RemoteException e) {
11327 Log.w(TAG, e);
11328 }
11329 }
11330
11331 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11332 if (app.instrumentationWatcher != null) {
11333 try {
11334 // NOTE: IInstrumentationWatcher *must* be oneway here
11335 app.instrumentationWatcher.instrumentationFinished(
11336 app.instrumentationClass,
11337 resultCode,
11338 results);
11339 } catch (RemoteException e) {
11340 }
11341 }
11342 app.instrumentationWatcher = null;
11343 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011344 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011345 app.instrumentationProfileFile = null;
11346 app.instrumentationArguments = null;
11347
11348 uninstallPackageLocked(app.processName, -1, false);
11349 }
11350
11351 public void finishInstrumentation(IApplicationThread target,
11352 int resultCode, Bundle results) {
11353 // Refuse possible leaked file descriptors
11354 if (results != null && results.hasFileDescriptors()) {
11355 throw new IllegalArgumentException("File descriptors passed in Intent");
11356 }
11357
11358 synchronized(this) {
11359 ProcessRecord app = getRecordForAppLocked(target);
11360 if (app == null) {
11361 Log.w(TAG, "finishInstrumentation: no app for " + target);
11362 return;
11363 }
11364 final long origId = Binder.clearCallingIdentity();
11365 finishInstrumentationLocked(app, resultCode, results);
11366 Binder.restoreCallingIdentity(origId);
11367 }
11368 }
11369
11370 // =========================================================
11371 // CONFIGURATION
11372 // =========================================================
11373
11374 public ConfigurationInfo getDeviceConfigurationInfo() {
11375 ConfigurationInfo config = new ConfigurationInfo();
11376 synchronized (this) {
11377 config.reqTouchScreen = mConfiguration.touchscreen;
11378 config.reqKeyboardType = mConfiguration.keyboard;
11379 config.reqNavigation = mConfiguration.navigation;
11380 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11381 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11382 }
11383 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11384 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11385 }
11386 }
11387 return config;
11388 }
11389
11390 public Configuration getConfiguration() {
11391 Configuration ci;
11392 synchronized(this) {
11393 ci = new Configuration(mConfiguration);
11394 }
11395 return ci;
11396 }
11397
11398 public void updateConfiguration(Configuration values) {
11399 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11400 "updateConfiguration()");
11401
11402 synchronized(this) {
11403 if (values == null && mWindowManager != null) {
11404 // sentinel: fetch the current configuration from the window manager
11405 values = mWindowManager.computeNewConfiguration();
11406 }
11407
11408 final long origId = Binder.clearCallingIdentity();
11409 updateConfigurationLocked(values, null);
11410 Binder.restoreCallingIdentity(origId);
11411 }
11412 }
11413
11414 /**
11415 * Do either or both things: (1) change the current configuration, and (2)
11416 * make sure the given activity is running with the (now) current
11417 * configuration. Returns true if the activity has been left running, or
11418 * false if <var>starting</var> is being destroyed to match the new
11419 * configuration.
11420 */
11421 public boolean updateConfigurationLocked(Configuration values,
11422 HistoryRecord starting) {
11423 int changes = 0;
11424
11425 boolean kept = true;
11426
11427 if (values != null) {
11428 Configuration newConfig = new Configuration(mConfiguration);
11429 changes = newConfig.updateFrom(values);
11430 if (changes != 0) {
11431 if (DEBUG_SWITCH) {
11432 Log.i(TAG, "Updating configuration to: " + values);
11433 }
11434
11435 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11436
11437 if (values.locale != null) {
11438 saveLocaleLocked(values.locale,
11439 !values.locale.equals(mConfiguration.locale),
11440 values.userSetLocale);
11441 }
11442
11443 mConfiguration = newConfig;
11444
11445 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11446 msg.obj = new Configuration(mConfiguration);
11447 mHandler.sendMessage(msg);
11448
11449 final int N = mLRUProcesses.size();
11450 for (int i=0; i<N; i++) {
11451 ProcessRecord app = mLRUProcesses.get(i);
11452 try {
11453 if (app.thread != null) {
11454 app.thread.scheduleConfigurationChanged(mConfiguration);
11455 }
11456 } catch (Exception e) {
11457 }
11458 }
11459 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11460 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11461 null, false, false, MY_PID, Process.SYSTEM_UID);
11462 }
11463 }
11464
11465 if (changes != 0 && starting == null) {
11466 // If the configuration changed, and the caller is not already
11467 // in the process of starting an activity, then find the top
11468 // activity to check if its configuration needs to change.
11469 starting = topRunningActivityLocked(null);
11470 }
11471
11472 if (starting != null) {
11473 kept = ensureActivityConfigurationLocked(starting, changes);
11474 if (kept) {
11475 // If this didn't result in the starting activity being
11476 // destroyed, then we need to make sure at this point that all
11477 // other activities are made visible.
11478 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11479 + ", ensuring others are correct.");
11480 ensureActivitiesVisibleLocked(starting, changes);
11481 }
11482 }
11483
11484 return kept;
11485 }
11486
11487 private final boolean relaunchActivityLocked(HistoryRecord r,
11488 int changes, boolean andResume) {
11489 List<ResultInfo> results = null;
11490 List<Intent> newIntents = null;
11491 if (andResume) {
11492 results = r.results;
11493 newIntents = r.newIntents;
11494 }
11495 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11496 + " with results=" + results + " newIntents=" + newIntents
11497 + " andResume=" + andResume);
11498 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11499 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11500 r.task.taskId, r.shortComponentName);
11501
11502 r.startFreezingScreenLocked(r.app, 0);
11503
11504 try {
11505 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11506 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11507 changes, !andResume);
11508 // Note: don't need to call pauseIfSleepingLocked() here, because
11509 // the caller will only pass in 'andResume' if this activity is
11510 // currently resumed, which implies we aren't sleeping.
11511 } catch (RemoteException e) {
11512 return false;
11513 }
11514
11515 if (andResume) {
11516 r.results = null;
11517 r.newIntents = null;
11518 }
11519
11520 return true;
11521 }
11522
11523 /**
11524 * Make sure the given activity matches the current configuration. Returns
11525 * false if the activity had to be destroyed. Returns true if the
11526 * configuration is the same, or the activity will remain running as-is
11527 * for whatever reason. Ensures the HistoryRecord is updated with the
11528 * correct configuration and all other bookkeeping is handled.
11529 */
11530 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11531 int globalChanges) {
11532 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11533
11534 // Short circuit: if the two configurations are the exact same
11535 // object (the common case), then there is nothing to do.
11536 Configuration newConfig = mConfiguration;
11537 if (r.configuration == newConfig) {
11538 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11539 return true;
11540 }
11541
11542 // We don't worry about activities that are finishing.
11543 if (r.finishing) {
11544 if (DEBUG_SWITCH) Log.i(TAG,
11545 "Configuration doesn't matter in finishing " + r);
11546 r.stopFreezingScreenLocked(false);
11547 return true;
11548 }
11549
11550 // Okay we now are going to make this activity have the new config.
11551 // But then we need to figure out how it needs to deal with that.
11552 Configuration oldConfig = r.configuration;
11553 r.configuration = newConfig;
11554
11555 // If the activity isn't currently running, just leave the new
11556 // configuration and it will pick that up next time it starts.
11557 if (r.app == null || r.app.thread == null) {
11558 if (DEBUG_SWITCH) Log.i(TAG,
11559 "Configuration doesn't matter not running " + r);
11560 r.stopFreezingScreenLocked(false);
11561 return true;
11562 }
11563
11564 // If the activity isn't persistent, there is a chance we will
11565 // need to restart it.
11566 if (!r.persistent) {
11567
11568 // Figure out what has changed between the two configurations.
11569 int changes = oldConfig.diff(newConfig);
11570 if (DEBUG_SWITCH) {
11571 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11572 + Integer.toHexString(changes) + ", handles=0x"
11573 + Integer.toHexString(r.info.configChanges));
11574 }
11575 if ((changes&(~r.info.configChanges)) != 0) {
11576 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11577 r.configChangeFlags |= changes;
11578 r.startFreezingScreenLocked(r.app, globalChanges);
11579 if (r.app == null || r.app.thread == null) {
11580 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11581 destroyActivityLocked(r, true);
11582 } else if (r.state == ActivityState.PAUSING) {
11583 // A little annoying: we are waiting for this activity to
11584 // finish pausing. Let's not do anything now, but just
11585 // flag that it needs to be restarted when done pausing.
11586 r.configDestroy = true;
11587 return true;
11588 } else if (r.state == ActivityState.RESUMED) {
11589 // Try to optimize this case: the configuration is changing
11590 // and we need to restart the top, resumed activity.
11591 // Instead of doing the normal handshaking, just say
11592 // "restart!".
11593 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11594 relaunchActivityLocked(r, r.configChangeFlags, true);
11595 r.configChangeFlags = 0;
11596 } else {
11597 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11598 relaunchActivityLocked(r, r.configChangeFlags, false);
11599 r.configChangeFlags = 0;
11600 }
11601
11602 // All done... tell the caller we weren't able to keep this
11603 // activity around.
11604 return false;
11605 }
11606 }
11607
11608 // Default case: the activity can handle this new configuration, so
11609 // hand it over. Note that we don't need to give it the new
11610 // configuration, since we always send configuration changes to all
11611 // process when they happen so it can just use whatever configuration
11612 // it last got.
11613 if (r.app != null && r.app.thread != null) {
11614 try {
11615 r.app.thread.scheduleActivityConfigurationChanged(r);
11616 } catch (RemoteException e) {
11617 // If process died, whatever.
11618 }
11619 }
11620 r.stopFreezingScreenLocked(false);
11621
11622 return true;
11623 }
11624
11625 /**
11626 * Save the locale. You must be inside a synchronized (this) block.
11627 */
11628 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11629 if(isDiff) {
11630 SystemProperties.set("user.language", l.getLanguage());
11631 SystemProperties.set("user.region", l.getCountry());
11632 }
11633
11634 if(isPersist) {
11635 SystemProperties.set("persist.sys.language", l.getLanguage());
11636 SystemProperties.set("persist.sys.country", l.getCountry());
11637 SystemProperties.set("persist.sys.localevar", l.getVariant());
11638 }
11639 }
11640
11641 // =========================================================
11642 // LIFETIME MANAGEMENT
11643 // =========================================================
11644
11645 private final int computeOomAdjLocked(
11646 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11647 if (mAdjSeq == app.adjSeq) {
11648 // This adjustment has already been computed.
11649 return app.curAdj;
11650 }
11651
11652 if (app.thread == null) {
11653 app.adjSeq = mAdjSeq;
11654 return (app.curAdj=EMPTY_APP_ADJ);
11655 }
11656
11657 app.isForeground = false;
11658
The Android Open Source Project4df24232009-03-05 14:34:35 -080011659 // Determine the importance of the process, starting with most
11660 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011661 int adj;
11662 int N;
11663 if (app == TOP_APP || app.instrumentationClass != null
11664 || app.persistentActivities > 0) {
11665 // The last app on the list is the foreground app.
11666 adj = FOREGROUND_APP_ADJ;
11667 app.isForeground = true;
11668 } else if (app.curReceiver != null ||
11669 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11670 // An app that is currently receiving a broadcast also
11671 // counts as being in the foreground.
11672 adj = FOREGROUND_APP_ADJ;
11673 } else if (app.executingServices.size() > 0) {
11674 // An app that is currently executing a service callback also
11675 // counts as being in the foreground.
11676 adj = FOREGROUND_APP_ADJ;
11677 } else if (app.foregroundServices || app.forcingToForeground != null) {
11678 // The user is aware of this app, so make it visible.
11679 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011680 } else if (app == mHomeProcess) {
11681 // This process is hosting what we currently consider to be the
11682 // home app, so we don't want to let it go into the background.
11683 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011684 } else if ((N=app.activities.size()) != 0) {
11685 // This app is in the background with paused activities.
11686 adj = hiddenAdj;
11687 for (int j=0; j<N; j++) {
11688 if (((HistoryRecord)app.activities.get(j)).visible) {
11689 // This app has a visible activity!
11690 adj = VISIBLE_APP_ADJ;
11691 break;
11692 }
11693 }
11694 } else {
11695 // A very not-needed process.
11696 adj = EMPTY_APP_ADJ;
11697 }
11698
The Android Open Source Project4df24232009-03-05 14:34:35 -080011699 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011700 // there are applications dependent on our services or providers, but
11701 // this gives us a baseline and makes sure we don't get into an
11702 // infinite recursion.
11703 app.adjSeq = mAdjSeq;
11704 app.curRawAdj = adj;
11705 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11706
11707 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11708 // If this process has active services running in it, we would
11709 // like to avoid killing it unless it would prevent the current
11710 // application from running.
11711 if (adj > hiddenAdj) {
11712 adj = hiddenAdj;
11713 }
11714 final long now = SystemClock.uptimeMillis();
11715 // This process is more important if the top activity is
11716 // bound to the service.
11717 Iterator jt = app.services.iterator();
11718 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11719 ServiceRecord s = (ServiceRecord)jt.next();
11720 if (s.startRequested) {
11721 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11722 // This service has seen some activity within
11723 // recent memory, so we will keep its process ahead
11724 // of the background processes.
11725 if (adj > SECONDARY_SERVER_ADJ) {
11726 adj = SECONDARY_SERVER_ADJ;
11727 }
11728 } else {
11729 // This service has been inactive for too long, just
11730 // put it with the rest of the background processes.
11731 if (adj > hiddenAdj) {
11732 adj = hiddenAdj;
11733 }
11734 }
11735 }
11736 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11737 Iterator<ConnectionRecord> kt
11738 = s.connections.values().iterator();
11739 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11740 // XXX should compute this based on the max of
11741 // all connected clients.
11742 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011743 if (cr.binding.client == app) {
11744 // Binding to ourself is not interesting.
11745 continue;
11746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011747 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11748 ProcessRecord client = cr.binding.client;
11749 int myHiddenAdj = hiddenAdj;
11750 if (myHiddenAdj > client.hiddenAdj) {
11751 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11752 myHiddenAdj = client.hiddenAdj;
11753 } else {
11754 myHiddenAdj = VISIBLE_APP_ADJ;
11755 }
11756 }
11757 int clientAdj = computeOomAdjLocked(
11758 client, myHiddenAdj, TOP_APP);
11759 if (adj > clientAdj) {
11760 adj = clientAdj > VISIBLE_APP_ADJ
11761 ? clientAdj : VISIBLE_APP_ADJ;
11762 }
11763 }
11764 HistoryRecord a = cr.activity;
11765 //if (a != null) {
11766 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11767 //}
11768 if (a != null && adj > FOREGROUND_APP_ADJ &&
11769 (a.state == ActivityState.RESUMED
11770 || a.state == ActivityState.PAUSING)) {
11771 adj = FOREGROUND_APP_ADJ;
11772 }
11773 }
11774 }
11775 }
11776 }
11777
11778 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11779 // If this process has published any content providers, then
11780 // its adjustment makes it at least as important as any of the
11781 // processes using those providers, and no less important than
11782 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
11783 if (adj > CONTENT_PROVIDER_ADJ) {
11784 adj = CONTENT_PROVIDER_ADJ;
11785 }
11786 Iterator jt = app.pubProviders.values().iterator();
11787 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11788 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
11789 if (cpr.clients.size() != 0) {
11790 Iterator<ProcessRecord> kt = cpr.clients.iterator();
11791 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11792 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011793 if (client == app) {
11794 // Being our own client is not interesting.
11795 continue;
11796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011797 int myHiddenAdj = hiddenAdj;
11798 if (myHiddenAdj > client.hiddenAdj) {
11799 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
11800 myHiddenAdj = client.hiddenAdj;
11801 } else {
11802 myHiddenAdj = FOREGROUND_APP_ADJ;
11803 }
11804 }
11805 int clientAdj = computeOomAdjLocked(
11806 client, myHiddenAdj, TOP_APP);
11807 if (adj > clientAdj) {
11808 adj = clientAdj > FOREGROUND_APP_ADJ
11809 ? clientAdj : FOREGROUND_APP_ADJ;
11810 }
11811 }
11812 }
11813 // If the provider has external (non-framework) process
11814 // dependencies, ensure that its adjustment is at least
11815 // FOREGROUND_APP_ADJ.
11816 if (cpr.externals != 0) {
11817 if (adj > FOREGROUND_APP_ADJ) {
11818 adj = FOREGROUND_APP_ADJ;
11819 }
11820 }
11821 }
11822 }
11823
11824 app.curRawAdj = adj;
11825
11826 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
11827 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
11828 if (adj > app.maxAdj) {
11829 adj = app.maxAdj;
11830 }
11831
11832 app.curAdj = adj;
11833
11834 return adj;
11835 }
11836
11837 /**
11838 * Ask a given process to GC right now.
11839 */
11840 final void performAppGcLocked(ProcessRecord app) {
11841 try {
11842 app.lastRequestedGc = SystemClock.uptimeMillis();
11843 if (app.thread != null) {
11844 app.thread.processInBackground();
11845 }
11846 } catch (Exception e) {
11847 // whatever.
11848 }
11849 }
11850
11851 /**
11852 * Returns true if things are idle enough to perform GCs.
11853 */
11854 private final boolean canGcNow() {
11855 return mParallelBroadcasts.size() == 0
11856 && mOrderedBroadcasts.size() == 0
11857 && (mSleeping || (mResumedActivity != null &&
11858 mResumedActivity.idle));
11859 }
11860
11861 /**
11862 * Perform GCs on all processes that are waiting for it, but only
11863 * if things are idle.
11864 */
11865 final void performAppGcsLocked() {
11866 final int N = mProcessesToGc.size();
11867 if (N <= 0) {
11868 return;
11869 }
11870 if (canGcNow()) {
11871 while (mProcessesToGc.size() > 0) {
11872 ProcessRecord proc = mProcessesToGc.remove(0);
11873 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
11874 // To avoid spamming the system, we will GC processes one
11875 // at a time, waiting a few seconds between each.
11876 performAppGcLocked(proc);
11877 scheduleAppGcsLocked();
11878 return;
11879 }
11880 }
11881 }
11882 }
11883
11884 /**
11885 * If all looks good, perform GCs on all processes waiting for them.
11886 */
11887 final void performAppGcsIfAppropriateLocked() {
11888 if (canGcNow()) {
11889 performAppGcsLocked();
11890 return;
11891 }
11892 // Still not idle, wait some more.
11893 scheduleAppGcsLocked();
11894 }
11895
11896 /**
11897 * Schedule the execution of all pending app GCs.
11898 */
11899 final void scheduleAppGcsLocked() {
11900 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
11901 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
11902 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
11903 }
11904
11905 /**
11906 * Set up to ask a process to GC itself. This will either do it
11907 * immediately, or put it on the list of processes to gc the next
11908 * time things are idle.
11909 */
11910 final void scheduleAppGcLocked(ProcessRecord app) {
11911 long now = SystemClock.uptimeMillis();
11912 if ((app.lastRequestedGc+5000) > now) {
11913 return;
11914 }
11915 if (!mProcessesToGc.contains(app)) {
11916 mProcessesToGc.add(app);
11917 scheduleAppGcsLocked();
11918 }
11919 }
11920
11921 private final boolean updateOomAdjLocked(
11922 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11923 app.hiddenAdj = hiddenAdj;
11924
11925 if (app.thread == null) {
11926 return true;
11927 }
11928
11929 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
11930
11931 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
11932 //Thread priority adjustment is disabled out to see
11933 //how the kernel scheduler performs.
11934 if (false) {
11935 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
11936 app.setIsForeground = app.isForeground;
11937 if (app.pid != MY_PID) {
11938 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
11939 + " to " + (app.isForeground
11940 ? Process.THREAD_PRIORITY_FOREGROUND
11941 : Process.THREAD_PRIORITY_DEFAULT));
11942 try {
11943 Process.setThreadPriority(app.pid, app.isForeground
11944 ? Process.THREAD_PRIORITY_FOREGROUND
11945 : Process.THREAD_PRIORITY_DEFAULT);
11946 } catch (RuntimeException e) {
11947 Log.w(TAG, "Exception trying to set priority of application thread "
11948 + app.pid, e);
11949 }
11950 }
11951 }
11952 }
11953 if (app.pid != 0 && app.pid != MY_PID) {
11954 if (app.curRawAdj != app.setRawAdj) {
11955 if (app.curRawAdj > FOREGROUND_APP_ADJ
11956 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
11957 // If this app is transitioning from foreground to
11958 // non-foreground, have it do a gc.
11959 scheduleAppGcLocked(app);
11960 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
11961 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
11962 // Likewise do a gc when an app is moving in to the
11963 // background (such as a service stopping).
11964 scheduleAppGcLocked(app);
11965 }
11966 app.setRawAdj = app.curRawAdj;
11967 }
11968 if (adj != app.setAdj) {
11969 if (Process.setOomAdj(app.pid, adj)) {
11970 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
11971 TAG, "Set app " + app.processName +
11972 " oom adj to " + adj);
11973 app.setAdj = adj;
11974 } else {
11975 return false;
11976 }
11977 }
11978 }
11979
11980 return true;
11981 }
11982
11983 private final HistoryRecord resumedAppLocked() {
11984 HistoryRecord resumedActivity = mResumedActivity;
11985 if (resumedActivity == null || resumedActivity.app == null) {
11986 resumedActivity = mPausingActivity;
11987 if (resumedActivity == null || resumedActivity.app == null) {
11988 resumedActivity = topRunningActivityLocked(null);
11989 }
11990 }
11991 return resumedActivity;
11992 }
11993
11994 private final boolean updateOomAdjLocked(ProcessRecord app) {
11995 final HistoryRecord TOP_ACT = resumedAppLocked();
11996 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
11997 int curAdj = app.curAdj;
11998 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
11999 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12000
12001 mAdjSeq++;
12002
12003 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12004 if (res) {
12005 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12006 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12007 if (nowHidden != wasHidden) {
12008 // Changed to/from hidden state, so apps after it in the LRU
12009 // list may also be changed.
12010 updateOomAdjLocked();
12011 }
12012 }
12013 return res;
12014 }
12015
12016 private final boolean updateOomAdjLocked() {
12017 boolean didOomAdj = true;
12018 final HistoryRecord TOP_ACT = resumedAppLocked();
12019 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12020
12021 if (false) {
12022 RuntimeException e = new RuntimeException();
12023 e.fillInStackTrace();
12024 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12025 }
12026
12027 mAdjSeq++;
12028
12029 // First try updating the OOM adjustment for each of the
12030 // application processes based on their current state.
12031 int i = mLRUProcesses.size();
12032 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12033 while (i > 0) {
12034 i--;
12035 ProcessRecord app = mLRUProcesses.get(i);
12036 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12037 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12038 && app.curAdj == curHiddenAdj) {
12039 curHiddenAdj++;
12040 }
12041 } else {
12042 didOomAdj = false;
12043 }
12044 }
12045
12046 // todo: for now pretend like OOM ADJ didn't work, because things
12047 // aren't behaving as expected on Linux -- it's not killing processes.
12048 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12049 }
12050
12051 private final void trimApplications() {
12052 synchronized (this) {
12053 int i;
12054
12055 // First remove any unused application processes whose package
12056 // has been removed.
12057 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12058 final ProcessRecord app = mRemovedProcesses.get(i);
12059 if (app.activities.size() == 0
12060 && app.curReceiver == null && app.services.size() == 0) {
12061 Log.i(
12062 TAG, "Exiting empty application process "
12063 + app.processName + " ("
12064 + (app.thread != null ? app.thread.asBinder() : null)
12065 + ")\n");
12066 if (app.pid > 0 && app.pid != MY_PID) {
12067 Process.killProcess(app.pid);
12068 } else {
12069 try {
12070 app.thread.scheduleExit();
12071 } catch (Exception e) {
12072 // Ignore exceptions.
12073 }
12074 }
12075 cleanUpApplicationRecordLocked(app, false, -1);
12076 mRemovedProcesses.remove(i);
12077
12078 if (app.persistent) {
12079 if (app.persistent) {
12080 addAppLocked(app.info);
12081 }
12082 }
12083 }
12084 }
12085
12086 // Now try updating the OOM adjustment for each of the
12087 // application processes based on their current state.
12088 // If the setOomAdj() API is not supported, then go with our
12089 // back-up plan...
12090 if (!updateOomAdjLocked()) {
12091
12092 // Count how many processes are running services.
12093 int numServiceProcs = 0;
12094 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12095 final ProcessRecord app = mLRUProcesses.get(i);
12096
12097 if (app.persistent || app.services.size() != 0
12098 || app.curReceiver != null
12099 || app.persistentActivities > 0) {
12100 // Don't count processes holding services against our
12101 // maximum process count.
12102 if (localLOGV) Log.v(
12103 TAG, "Not trimming app " + app + " with services: "
12104 + app.services);
12105 numServiceProcs++;
12106 }
12107 }
12108
12109 int curMaxProcs = mProcessLimit;
12110 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12111 if (mAlwaysFinishActivities) {
12112 curMaxProcs = 1;
12113 }
12114 curMaxProcs += numServiceProcs;
12115
12116 // Quit as many processes as we can to get down to the desired
12117 // process count. First remove any processes that no longer
12118 // have activites running in them.
12119 for ( i=0;
12120 i<mLRUProcesses.size()
12121 && mLRUProcesses.size() > curMaxProcs;
12122 i++) {
12123 final ProcessRecord app = mLRUProcesses.get(i);
12124 // Quit an application only if it is not currently
12125 // running any activities.
12126 if (!app.persistent && app.activities.size() == 0
12127 && app.curReceiver == null && app.services.size() == 0) {
12128 Log.i(
12129 TAG, "Exiting empty application process "
12130 + app.processName + " ("
12131 + (app.thread != null ? app.thread.asBinder() : null)
12132 + ")\n");
12133 if (app.pid > 0 && app.pid != MY_PID) {
12134 Process.killProcess(app.pid);
12135 } else {
12136 try {
12137 app.thread.scheduleExit();
12138 } catch (Exception e) {
12139 // Ignore exceptions.
12140 }
12141 }
12142 // todo: For now we assume the application is not buggy
12143 // or evil, and will quit as a result of our request.
12144 // Eventually we need to drive this off of the death
12145 // notification, and kill the process if it takes too long.
12146 cleanUpApplicationRecordLocked(app, false, i);
12147 i--;
12148 }
12149 }
12150
12151 // If we still have too many processes, now from the least
12152 // recently used process we start finishing activities.
12153 if (Config.LOGV) Log.v(
12154 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12155 " of " + curMaxProcs + " processes");
12156 for ( i=0;
12157 i<mLRUProcesses.size()
12158 && mLRUProcesses.size() > curMaxProcs;
12159 i++) {
12160 final ProcessRecord app = mLRUProcesses.get(i);
12161 // Quit the application only if we have a state saved for
12162 // all of its activities.
12163 boolean canQuit = !app.persistent && app.curReceiver == null
12164 && app.services.size() == 0
12165 && app.persistentActivities == 0;
12166 int NUMA = app.activities.size();
12167 int j;
12168 if (Config.LOGV) Log.v(
12169 TAG, "Looking to quit " + app.processName);
12170 for (j=0; j<NUMA && canQuit; j++) {
12171 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12172 if (Config.LOGV) Log.v(
12173 TAG, " " + r.intent.getComponent().flattenToShortString()
12174 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12175 canQuit = (r.haveState || !r.stateNotNeeded)
12176 && !r.visible && r.stopped;
12177 }
12178 if (canQuit) {
12179 // Finish all of the activities, and then the app itself.
12180 for (j=0; j<NUMA; j++) {
12181 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12182 if (!r.finishing) {
12183 destroyActivityLocked(r, false);
12184 }
12185 r.resultTo = null;
12186 }
12187 Log.i(TAG, "Exiting application process "
12188 + app.processName + " ("
12189 + (app.thread != null ? app.thread.asBinder() : null)
12190 + ")\n");
12191 if (app.pid > 0 && app.pid != MY_PID) {
12192 Process.killProcess(app.pid);
12193 } else {
12194 try {
12195 app.thread.scheduleExit();
12196 } catch (Exception e) {
12197 // Ignore exceptions.
12198 }
12199 }
12200 // todo: For now we assume the application is not buggy
12201 // or evil, and will quit as a result of our request.
12202 // Eventually we need to drive this off of the death
12203 // notification, and kill the process if it takes too long.
12204 cleanUpApplicationRecordLocked(app, false, i);
12205 i--;
12206 //dump();
12207 }
12208 }
12209
12210 }
12211
12212 int curMaxActivities = MAX_ACTIVITIES;
12213 if (mAlwaysFinishActivities) {
12214 curMaxActivities = 1;
12215 }
12216
12217 // Finally, if there are too many activities now running, try to
12218 // finish as many as we can to get back down to the limit.
12219 for ( i=0;
12220 i<mLRUActivities.size()
12221 && mLRUActivities.size() > curMaxActivities;
12222 i++) {
12223 final HistoryRecord r
12224 = (HistoryRecord)mLRUActivities.get(i);
12225
12226 // We can finish this one if we have its icicle saved and
12227 // it is not persistent.
12228 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12229 && r.stopped && !r.persistent && !r.finishing) {
12230 final int origSize = mLRUActivities.size();
12231 destroyActivityLocked(r, true);
12232
12233 // This will remove it from the LRU list, so keep
12234 // our index at the same value. Note that this check to
12235 // see if the size changes is just paranoia -- if
12236 // something unexpected happens, we don't want to end up
12237 // in an infinite loop.
12238 if (origSize > mLRUActivities.size()) {
12239 i--;
12240 }
12241 }
12242 }
12243 }
12244 }
12245
12246 /** This method sends the specified signal to each of the persistent apps */
12247 public void signalPersistentProcesses(int sig) throws RemoteException {
12248 if (sig != Process.SIGNAL_USR1) {
12249 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12250 }
12251
12252 synchronized (this) {
12253 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12254 != PackageManager.PERMISSION_GRANTED) {
12255 throw new SecurityException("Requires permission "
12256 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12257 }
12258
12259 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12260 ProcessRecord r = mLRUProcesses.get(i);
12261 if (r.thread != null && r.persistent) {
12262 Process.sendSignal(r.pid, sig);
12263 }
12264 }
12265 }
12266 }
12267
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012268 public boolean profileControl(String process, boolean start,
12269 String path) throws RemoteException {
12270
12271 synchronized (this) {
12272 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12273 // its own permission.
12274 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12275 != PackageManager.PERMISSION_GRANTED) {
12276 throw new SecurityException("Requires permission "
12277 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12278 }
12279
12280 ProcessRecord proc = null;
12281 try {
12282 int pid = Integer.parseInt(process);
12283 synchronized (mPidsSelfLocked) {
12284 proc = mPidsSelfLocked.get(pid);
12285 }
12286 } catch (NumberFormatException e) {
12287 }
12288
12289 if (proc == null) {
12290 HashMap<String, SparseArray<ProcessRecord>> all
12291 = mProcessNames.getMap();
12292 SparseArray<ProcessRecord> procs = all.get(process);
12293 if (procs != null && procs.size() > 0) {
12294 proc = procs.valueAt(0);
12295 }
12296 }
12297
12298 if (proc == null || proc.thread == null) {
12299 throw new IllegalArgumentException("Unknown process: " + process);
12300 }
12301
12302 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12303 if (isSecure) {
12304 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12305 throw new SecurityException("Process not debuggable: " + proc);
12306 }
12307 }
12308
12309 try {
12310 proc.thread.profilerControl(start, path);
12311 return true;
12312 } catch (RemoteException e) {
12313 throw new IllegalStateException("Process disappeared");
12314 }
12315 }
12316 }
12317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012318 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12319 public void monitor() {
12320 synchronized (this) { }
12321 }
12322}