blob: d1c40b436040f95735270a9bfb297a744ee41ba8 [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;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004736 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 app.forcingToForeground = null;
4738 app.foregroundServices = false;
4739 app.debugging = false;
4740
4741 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4742
4743 List providers = generateApplicationProvidersLocked(app);
4744
4745 if (localLOGV) Log.v(
4746 TAG, "New app record " + app
4747 + " thread=" + thread.asBinder() + " pid=" + pid);
4748 try {
4749 int testMode = IApplicationThread.DEBUG_OFF;
4750 if (mDebugApp != null && mDebugApp.equals(processName)) {
4751 testMode = mWaitForDebugger
4752 ? IApplicationThread.DEBUG_WAIT
4753 : IApplicationThread.DEBUG_ON;
4754 app.debugging = true;
4755 if (mDebugTransient) {
4756 mDebugApp = mOrigDebugApp;
4757 mWaitForDebugger = mOrigWaitForDebugger;
4758 }
4759 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004760 thread.bindApplication(processName, app.instrumentationInfo != null
4761 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004762 app.instrumentationClass, app.instrumentationProfileFile,
4763 app.instrumentationArguments, app.instrumentationWatcher, testMode,
4764 mConfiguration, getCommonServicesLocked());
4765 updateLRUListLocked(app, false);
4766 app.lastRequestedGc = SystemClock.uptimeMillis();
4767 } catch (Exception e) {
4768 // todo: Yikes! What should we do? For now we will try to
4769 // start another process, but that could easily get us in
4770 // an infinite loop of restarting processes...
4771 Log.w(TAG, "Exception thrown during bind!", e);
4772
4773 app.resetPackageList();
4774 startProcessLocked(app, "bind fail", processName);
4775 return false;
4776 }
4777
4778 // Remove this record from the list of starting applications.
4779 mPersistentStartingProcesses.remove(app);
4780 mProcessesOnHold.remove(app);
4781
4782 boolean badApp = false;
4783 boolean didSomething = false;
4784
4785 // See if the top visible activity is waiting to run in this process...
4786 HistoryRecord hr = topRunningActivityLocked(null);
4787 if (hr != null) {
4788 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4789 && processName.equals(hr.processName)) {
4790 try {
4791 if (realStartActivityLocked(hr, app, true, true)) {
4792 didSomething = true;
4793 }
4794 } catch (Exception e) {
4795 Log.w(TAG, "Exception in new application when starting activity "
4796 + hr.intent.getComponent().flattenToShortString(), e);
4797 badApp = true;
4798 }
4799 } else {
4800 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4801 }
4802 }
4803
4804 // Find any services that should be running in this process...
4805 if (!badApp && mPendingServices.size() > 0) {
4806 ServiceRecord sr = null;
4807 try {
4808 for (int i=0; i<mPendingServices.size(); i++) {
4809 sr = mPendingServices.get(i);
4810 if (app.info.uid != sr.appInfo.uid
4811 || !processName.equals(sr.processName)) {
4812 continue;
4813 }
4814
4815 mPendingServices.remove(i);
4816 i--;
4817 realStartServiceLocked(sr, app);
4818 didSomething = true;
4819 }
4820 } catch (Exception e) {
4821 Log.w(TAG, "Exception in new application when starting service "
4822 + sr.shortName, e);
4823 badApp = true;
4824 }
4825 }
4826
4827 // Check if the next broadcast receiver is in this process...
4828 BroadcastRecord br = mPendingBroadcast;
4829 if (!badApp && br != null && br.curApp == app) {
4830 try {
4831 mPendingBroadcast = null;
4832 processCurBroadcastLocked(br, app);
4833 didSomething = true;
4834 } catch (Exception e) {
4835 Log.w(TAG, "Exception in new application when starting receiver "
4836 + br.curComponent.flattenToShortString(), e);
4837 badApp = true;
4838 logBroadcastReceiverDiscard(br);
4839 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4840 br.resultExtras, br.resultAbort, true);
4841 scheduleBroadcastsLocked();
4842 }
4843 }
4844
4845 if (badApp) {
4846 // todo: Also need to kill application to deal with all
4847 // kinds of exceptions.
4848 handleAppDiedLocked(app, false);
4849 return false;
4850 }
4851
4852 if (!didSomething) {
4853 updateOomAdjLocked();
4854 }
4855
4856 return true;
4857 }
4858
4859 public final void attachApplication(IApplicationThread thread) {
4860 synchronized (this) {
4861 int callingPid = Binder.getCallingPid();
4862 final long origId = Binder.clearCallingIdentity();
4863 attachApplicationLocked(thread, callingPid);
4864 Binder.restoreCallingIdentity(origId);
4865 }
4866 }
4867
4868 public final void activityIdle(IBinder token) {
4869 final long origId = Binder.clearCallingIdentity();
4870 activityIdleInternal(token, false);
4871 Binder.restoreCallingIdentity(origId);
4872 }
4873
4874 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4875 boolean remove) {
4876 int N = mStoppingActivities.size();
4877 if (N <= 0) return null;
4878
4879 ArrayList<HistoryRecord> stops = null;
4880
4881 final boolean nowVisible = mResumedActivity != null
4882 && mResumedActivity.nowVisible
4883 && !mResumedActivity.waitingVisible;
4884 for (int i=0; i<N; i++) {
4885 HistoryRecord s = mStoppingActivities.get(i);
4886 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4887 + nowVisible + " waitingVisible=" + s.waitingVisible
4888 + " finishing=" + s.finishing);
4889 if (s.waitingVisible && nowVisible) {
4890 mWaitingVisibleActivities.remove(s);
4891 s.waitingVisible = false;
4892 if (s.finishing) {
4893 // If this activity is finishing, it is sitting on top of
4894 // everyone else but we now know it is no longer needed...
4895 // so get rid of it. Otherwise, we need to go through the
4896 // normal flow and hide it once we determine that it is
4897 // hidden by the activities in front of it.
4898 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4899 mWindowManager.setAppVisibility(s, false);
4900 }
4901 }
4902 if (!s.waitingVisible && remove) {
4903 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4904 if (stops == null) {
4905 stops = new ArrayList<HistoryRecord>();
4906 }
4907 stops.add(s);
4908 mStoppingActivities.remove(i);
4909 N--;
4910 i--;
4911 }
4912 }
4913
4914 return stops;
4915 }
4916
4917 void enableScreenAfterBoot() {
4918 mWindowManager.enableScreenAfterBoot();
4919 }
4920
4921 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4922 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4923
4924 ArrayList<HistoryRecord> stops = null;
4925 ArrayList<HistoryRecord> finishes = null;
4926 ArrayList<HistoryRecord> thumbnails = null;
4927 int NS = 0;
4928 int NF = 0;
4929 int NT = 0;
4930 IApplicationThread sendThumbnail = null;
4931 boolean booting = false;
4932 boolean enableScreen = false;
4933
4934 synchronized (this) {
4935 if (token != null) {
4936 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
4937 }
4938
4939 // Get the activity record.
4940 int index = indexOfTokenLocked(token, false);
4941 if (index >= 0) {
4942 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4943
4944 // No longer need to keep the device awake.
4945 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
4946 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
4947 mLaunchingActivity.release();
4948 }
4949
4950 // We are now idle. If someone is waiting for a thumbnail from
4951 // us, we can now deliver.
4952 r.idle = true;
4953 scheduleAppGcsLocked();
4954 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
4955 sendThumbnail = r.app.thread;
4956 r.thumbnailNeeded = false;
4957 }
4958
4959 // If this activity is fullscreen, set up to hide those under it.
4960
4961 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
4962 ensureActivitiesVisibleLocked(null, 0);
4963
4964 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
4965 if (!mBooted && !fromTimeout) {
4966 mBooted = true;
4967 enableScreen = true;
4968 }
4969 }
4970
4971 // Atomically retrieve all of the other things to do.
4972 stops = processStoppingActivitiesLocked(true);
4973 NS = stops != null ? stops.size() : 0;
4974 if ((NF=mFinishingActivities.size()) > 0) {
4975 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
4976 mFinishingActivities.clear();
4977 }
4978 if ((NT=mCancelledThumbnails.size()) > 0) {
4979 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
4980 mCancelledThumbnails.clear();
4981 }
4982
4983 booting = mBooting;
4984 mBooting = false;
4985 }
4986
4987 int i;
4988
4989 // Send thumbnail if requested.
4990 if (sendThumbnail != null) {
4991 try {
4992 sendThumbnail.requestThumbnail(token);
4993 } catch (Exception e) {
4994 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
4995 sendPendingThumbnail(null, token, null, null, true);
4996 }
4997 }
4998
4999 // Stop any activities that are scheduled to do so but have been
5000 // waiting for the next one to start.
5001 for (i=0; i<NS; i++) {
5002 HistoryRecord r = (HistoryRecord)stops.get(i);
5003 synchronized (this) {
5004 if (r.finishing) {
5005 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5006 } else {
5007 stopActivityLocked(r);
5008 }
5009 }
5010 }
5011
5012 // Finish any activities that are scheduled to do so but have been
5013 // waiting for the next one to start.
5014 for (i=0; i<NF; i++) {
5015 HistoryRecord r = (HistoryRecord)finishes.get(i);
5016 synchronized (this) {
5017 destroyActivityLocked(r, true);
5018 }
5019 }
5020
5021 // Report back to any thumbnail receivers.
5022 for (i=0; i<NT; i++) {
5023 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5024 sendPendingThumbnail(r, null, null, null, true);
5025 }
5026
5027 if (booting) {
5028 // Ensure that any processes we had put on hold are now started
5029 // up.
5030 final int NP = mProcessesOnHold.size();
5031 if (NP > 0) {
5032 ArrayList<ProcessRecord> procs =
5033 new ArrayList<ProcessRecord>(mProcessesOnHold);
5034 for (int ip=0; ip<NP; ip++) {
5035 this.startProcessLocked(procs.get(ip), "on-hold", null);
5036 }
5037 }
5038 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5039 // Tell anyone interested that we are done booting!
5040 synchronized (this) {
5041 broadcastIntentLocked(null, null,
5042 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5043 null, null, 0, null, null,
5044 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5045 false, false, MY_PID, Process.SYSTEM_UID);
5046 }
5047 }
5048 }
5049
5050 trimApplications();
5051 //dump();
5052 //mWindowManager.dump();
5053
5054 if (enableScreen) {
5055 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5056 SystemClock.uptimeMillis());
5057 enableScreenAfterBoot();
5058 }
5059 }
5060
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005061 final void ensureScreenEnabled() {
5062 boolean enableScreen;
5063 synchronized (this) {
5064 enableScreen = !mBooted;
5065 mBooted = true;
5066 }
5067
5068 if (enableScreen) {
5069 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5070 SystemClock.uptimeMillis());
5071 enableScreenAfterBoot();
5072 }
5073 }
5074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005075 public final void activityPaused(IBinder token, Bundle icicle) {
5076 // Refuse possible leaked file descriptors
5077 if (icicle != null && icicle.hasFileDescriptors()) {
5078 throw new IllegalArgumentException("File descriptors passed in Bundle");
5079 }
5080
5081 final long origId = Binder.clearCallingIdentity();
5082 activityPaused(token, icicle, false);
5083 Binder.restoreCallingIdentity(origId);
5084 }
5085
5086 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5087 if (DEBUG_PAUSE) Log.v(
5088 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5089 + ", timeout=" + timeout);
5090
5091 HistoryRecord r = null;
5092
5093 synchronized (this) {
5094 int index = indexOfTokenLocked(token, false);
5095 if (index >= 0) {
5096 r = (HistoryRecord)mHistory.get(index);
5097 if (!timeout) {
5098 r.icicle = icicle;
5099 r.haveState = true;
5100 }
5101 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5102 if (mPausingActivity == r) {
5103 r.state = ActivityState.PAUSED;
5104 completePauseLocked();
5105 } else {
5106 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5107 System.identityHashCode(r), r.shortComponentName,
5108 mPausingActivity != null
5109 ? mPausingActivity.shortComponentName : "(none)");
5110 }
5111 }
5112 }
5113 }
5114
5115 public final void activityStopped(IBinder token, Bitmap thumbnail,
5116 CharSequence description) {
5117 if (localLOGV) Log.v(
5118 TAG, "Activity stopped: token=" + token);
5119
5120 HistoryRecord r = null;
5121
5122 final long origId = Binder.clearCallingIdentity();
5123
5124 synchronized (this) {
5125 int index = indexOfTokenLocked(token, false);
5126 if (index >= 0) {
5127 r = (HistoryRecord)mHistory.get(index);
5128 r.thumbnail = thumbnail;
5129 r.description = description;
5130 r.stopped = true;
5131 r.state = ActivityState.STOPPED;
5132 if (!r.finishing) {
5133 if (r.configDestroy) {
5134 destroyActivityLocked(r, true);
5135 resumeTopActivityLocked(null);
5136 }
5137 }
5138 }
5139 }
5140
5141 if (r != null) {
5142 sendPendingThumbnail(r, null, null, null, false);
5143 }
5144
5145 trimApplications();
5146
5147 Binder.restoreCallingIdentity(origId);
5148 }
5149
5150 public final void activityDestroyed(IBinder token) {
5151 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5152 synchronized (this) {
5153 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5154
5155 int index = indexOfTokenLocked(token, false);
5156 if (index >= 0) {
5157 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5158 if (r.state == ActivityState.DESTROYING) {
5159 final long origId = Binder.clearCallingIdentity();
5160 removeActivityFromHistoryLocked(r);
5161 Binder.restoreCallingIdentity(origId);
5162 }
5163 }
5164 }
5165 }
5166
5167 public String getCallingPackage(IBinder token) {
5168 synchronized (this) {
5169 HistoryRecord r = getCallingRecordLocked(token);
5170 return r != null && r.app != null ? r.app.processName : null;
5171 }
5172 }
5173
5174 public ComponentName getCallingActivity(IBinder token) {
5175 synchronized (this) {
5176 HistoryRecord r = getCallingRecordLocked(token);
5177 return r != null ? r.intent.getComponent() : null;
5178 }
5179 }
5180
5181 private HistoryRecord getCallingRecordLocked(IBinder token) {
5182 int index = indexOfTokenLocked(token, true);
5183 if (index >= 0) {
5184 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5185 if (r != null) {
5186 return r.resultTo;
5187 }
5188 }
5189 return null;
5190 }
5191
5192 public ComponentName getActivityClassForToken(IBinder token) {
5193 synchronized(this) {
5194 int index = indexOfTokenLocked(token, false);
5195 if (index >= 0) {
5196 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5197 return r.intent.getComponent();
5198 }
5199 return null;
5200 }
5201 }
5202
5203 public String getPackageForToken(IBinder token) {
5204 synchronized(this) {
5205 int index = indexOfTokenLocked(token, false);
5206 if (index >= 0) {
5207 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5208 return r.packageName;
5209 }
5210 return null;
5211 }
5212 }
5213
5214 public IIntentSender getIntentSender(int type,
5215 String packageName, IBinder token, String resultWho,
5216 int requestCode, Intent intent, String resolvedType, int flags) {
5217 // Refuse possible leaked file descriptors
5218 if (intent != null && intent.hasFileDescriptors() == true) {
5219 throw new IllegalArgumentException("File descriptors passed in Intent");
5220 }
5221
5222 synchronized(this) {
5223 int callingUid = Binder.getCallingUid();
5224 try {
5225 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5226 Process.supportsProcesses()) {
5227 int uid = ActivityThread.getPackageManager()
5228 .getPackageUid(packageName);
5229 if (uid != Binder.getCallingUid()) {
5230 String msg = "Permission Denial: getIntentSender() from pid="
5231 + Binder.getCallingPid()
5232 + ", uid=" + Binder.getCallingUid()
5233 + ", (need uid=" + uid + ")"
5234 + " is not allowed to send as package " + packageName;
5235 Log.w(TAG, msg);
5236 throw new SecurityException(msg);
5237 }
5238 }
5239 } catch (RemoteException e) {
5240 throw new SecurityException(e);
5241 }
5242 HistoryRecord activity = null;
5243 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5244 int index = indexOfTokenLocked(token, false);
5245 if (index < 0) {
5246 return null;
5247 }
5248 activity = (HistoryRecord)mHistory.get(index);
5249 if (activity.finishing) {
5250 return null;
5251 }
5252 }
5253
5254 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5255 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5256 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5257 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5258 |PendingIntent.FLAG_UPDATE_CURRENT);
5259
5260 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5261 type, packageName, activity, resultWho,
5262 requestCode, intent, resolvedType, flags);
5263 WeakReference<PendingIntentRecord> ref;
5264 ref = mIntentSenderRecords.get(key);
5265 PendingIntentRecord rec = ref != null ? ref.get() : null;
5266 if (rec != null) {
5267 if (!cancelCurrent) {
5268 if (updateCurrent) {
5269 rec.key.requestIntent.replaceExtras(intent);
5270 }
5271 return rec;
5272 }
5273 rec.canceled = true;
5274 mIntentSenderRecords.remove(key);
5275 }
5276 if (noCreate) {
5277 return rec;
5278 }
5279 rec = new PendingIntentRecord(this, key, callingUid);
5280 mIntentSenderRecords.put(key, rec.ref);
5281 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5282 if (activity.pendingResults == null) {
5283 activity.pendingResults
5284 = new HashSet<WeakReference<PendingIntentRecord>>();
5285 }
5286 activity.pendingResults.add(rec.ref);
5287 }
5288 return rec;
5289 }
5290 }
5291
5292 public void cancelIntentSender(IIntentSender sender) {
5293 if (!(sender instanceof PendingIntentRecord)) {
5294 return;
5295 }
5296 synchronized(this) {
5297 PendingIntentRecord rec = (PendingIntentRecord)sender;
5298 try {
5299 int uid = ActivityThread.getPackageManager()
5300 .getPackageUid(rec.key.packageName);
5301 if (uid != Binder.getCallingUid()) {
5302 String msg = "Permission Denial: cancelIntentSender() from pid="
5303 + Binder.getCallingPid()
5304 + ", uid=" + Binder.getCallingUid()
5305 + " is not allowed to cancel packges "
5306 + rec.key.packageName;
5307 Log.w(TAG, msg);
5308 throw new SecurityException(msg);
5309 }
5310 } catch (RemoteException e) {
5311 throw new SecurityException(e);
5312 }
5313 cancelIntentSenderLocked(rec, true);
5314 }
5315 }
5316
5317 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5318 rec.canceled = true;
5319 mIntentSenderRecords.remove(rec.key);
5320 if (cleanActivity && rec.key.activity != null) {
5321 rec.key.activity.pendingResults.remove(rec.ref);
5322 }
5323 }
5324
5325 public String getPackageForIntentSender(IIntentSender pendingResult) {
5326 if (!(pendingResult instanceof PendingIntentRecord)) {
5327 return null;
5328 }
5329 synchronized(this) {
5330 try {
5331 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5332 return res.key.packageName;
5333 } catch (ClassCastException e) {
5334 }
5335 }
5336 return null;
5337 }
5338
5339 public void setProcessLimit(int max) {
5340 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5341 "setProcessLimit()");
5342 mProcessLimit = max;
5343 }
5344
5345 public int getProcessLimit() {
5346 return mProcessLimit;
5347 }
5348
5349 void foregroundTokenDied(ForegroundToken token) {
5350 synchronized (ActivityManagerService.this) {
5351 synchronized (mPidsSelfLocked) {
5352 ForegroundToken cur
5353 = mForegroundProcesses.get(token.pid);
5354 if (cur != token) {
5355 return;
5356 }
5357 mForegroundProcesses.remove(token.pid);
5358 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5359 if (pr == null) {
5360 return;
5361 }
5362 pr.forcingToForeground = null;
5363 pr.foregroundServices = false;
5364 }
5365 updateOomAdjLocked();
5366 }
5367 }
5368
5369 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5370 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5371 "setProcessForeground()");
5372 synchronized(this) {
5373 boolean changed = false;
5374
5375 synchronized (mPidsSelfLocked) {
5376 ProcessRecord pr = mPidsSelfLocked.get(pid);
5377 if (pr == null) {
5378 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5379 return;
5380 }
5381 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5382 if (oldToken != null) {
5383 oldToken.token.unlinkToDeath(oldToken, 0);
5384 mForegroundProcesses.remove(pid);
5385 pr.forcingToForeground = null;
5386 changed = true;
5387 }
5388 if (isForeground && token != null) {
5389 ForegroundToken newToken = new ForegroundToken() {
5390 public void binderDied() {
5391 foregroundTokenDied(this);
5392 }
5393 };
5394 newToken.pid = pid;
5395 newToken.token = token;
5396 try {
5397 token.linkToDeath(newToken, 0);
5398 mForegroundProcesses.put(pid, newToken);
5399 pr.forcingToForeground = token;
5400 changed = true;
5401 } catch (RemoteException e) {
5402 // If the process died while doing this, we will later
5403 // do the cleanup with the process death link.
5404 }
5405 }
5406 }
5407
5408 if (changed) {
5409 updateOomAdjLocked();
5410 }
5411 }
5412 }
5413
5414 // =========================================================
5415 // PERMISSIONS
5416 // =========================================================
5417
5418 static class PermissionController extends IPermissionController.Stub {
5419 ActivityManagerService mActivityManagerService;
5420 PermissionController(ActivityManagerService activityManagerService) {
5421 mActivityManagerService = activityManagerService;
5422 }
5423
5424 public boolean checkPermission(String permission, int pid, int uid) {
5425 return mActivityManagerService.checkPermission(permission, pid,
5426 uid) == PackageManager.PERMISSION_GRANTED;
5427 }
5428 }
5429
5430 /**
5431 * This can be called with or without the global lock held.
5432 */
5433 int checkComponentPermission(String permission, int pid, int uid,
5434 int reqUid) {
5435 // We might be performing an operation on behalf of an indirect binder
5436 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5437 // client identity accordingly before proceeding.
5438 Identity tlsIdentity = sCallerIdentity.get();
5439 if (tlsIdentity != null) {
5440 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5441 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5442 uid = tlsIdentity.uid;
5443 pid = tlsIdentity.pid;
5444 }
5445
5446 // Root, system server and our own process get to do everything.
5447 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5448 !Process.supportsProcesses()) {
5449 return PackageManager.PERMISSION_GRANTED;
5450 }
5451 // If the target requires a specific UID, always fail for others.
5452 if (reqUid >= 0 && uid != reqUid) {
5453 return PackageManager.PERMISSION_DENIED;
5454 }
5455 if (permission == null) {
5456 return PackageManager.PERMISSION_GRANTED;
5457 }
5458 try {
5459 return ActivityThread.getPackageManager()
5460 .checkUidPermission(permission, uid);
5461 } catch (RemoteException e) {
5462 // Should never happen, but if it does... deny!
5463 Log.e(TAG, "PackageManager is dead?!?", e);
5464 }
5465 return PackageManager.PERMISSION_DENIED;
5466 }
5467
5468 /**
5469 * As the only public entry point for permissions checking, this method
5470 * can enforce the semantic that requesting a check on a null global
5471 * permission is automatically denied. (Internally a null permission
5472 * string is used when calling {@link #checkComponentPermission} in cases
5473 * when only uid-based security is needed.)
5474 *
5475 * This can be called with or without the global lock held.
5476 */
5477 public int checkPermission(String permission, int pid, int uid) {
5478 if (permission == null) {
5479 return PackageManager.PERMISSION_DENIED;
5480 }
5481 return checkComponentPermission(permission, pid, uid, -1);
5482 }
5483
5484 /**
5485 * Binder IPC calls go through the public entry point.
5486 * This can be called with or without the global lock held.
5487 */
5488 int checkCallingPermission(String permission) {
5489 return checkPermission(permission,
5490 Binder.getCallingPid(),
5491 Binder.getCallingUid());
5492 }
5493
5494 /**
5495 * This can be called with or without the global lock held.
5496 */
5497 void enforceCallingPermission(String permission, String func) {
5498 if (checkCallingPermission(permission)
5499 == PackageManager.PERMISSION_GRANTED) {
5500 return;
5501 }
5502
5503 String msg = "Permission Denial: " + func + " from pid="
5504 + Binder.getCallingPid()
5505 + ", uid=" + Binder.getCallingUid()
5506 + " requires " + permission;
5507 Log.w(TAG, msg);
5508 throw new SecurityException(msg);
5509 }
5510
5511 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5512 ProviderInfo pi, int uid, int modeFlags) {
5513 try {
5514 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5515 if ((pi.readPermission != null) &&
5516 (pm.checkUidPermission(pi.readPermission, uid)
5517 != PackageManager.PERMISSION_GRANTED)) {
5518 return false;
5519 }
5520 }
5521 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5522 if ((pi.writePermission != null) &&
5523 (pm.checkUidPermission(pi.writePermission, uid)
5524 != PackageManager.PERMISSION_GRANTED)) {
5525 return false;
5526 }
5527 }
5528 return true;
5529 } catch (RemoteException e) {
5530 return false;
5531 }
5532 }
5533
5534 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5535 int modeFlags) {
5536 // Root gets to do everything.
5537 if (uid == 0 || !Process.supportsProcesses()) {
5538 return true;
5539 }
5540 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5541 if (perms == null) return false;
5542 UriPermission perm = perms.get(uri);
5543 if (perm == null) return false;
5544 return (modeFlags&perm.modeFlags) == modeFlags;
5545 }
5546
5547 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5548 // Another redirected-binder-call permissions check as in
5549 // {@link checkComponentPermission}.
5550 Identity tlsIdentity = sCallerIdentity.get();
5551 if (tlsIdentity != null) {
5552 uid = tlsIdentity.uid;
5553 pid = tlsIdentity.pid;
5554 }
5555
5556 // Our own process gets to do everything.
5557 if (pid == MY_PID) {
5558 return PackageManager.PERMISSION_GRANTED;
5559 }
5560 synchronized(this) {
5561 return checkUriPermissionLocked(uri, uid, modeFlags)
5562 ? PackageManager.PERMISSION_GRANTED
5563 : PackageManager.PERMISSION_DENIED;
5564 }
5565 }
5566
5567 private void grantUriPermissionLocked(int callingUid,
5568 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5569 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5570 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5571 if (modeFlags == 0) {
5572 return;
5573 }
5574
5575 final IPackageManager pm = ActivityThread.getPackageManager();
5576
5577 // If this is not a content: uri, we can't do anything with it.
5578 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5579 return;
5580 }
5581
5582 String name = uri.getAuthority();
5583 ProviderInfo pi = null;
5584 ContentProviderRecord cpr
5585 = (ContentProviderRecord)mProvidersByName.get(name);
5586 if (cpr != null) {
5587 pi = cpr.info;
5588 } else {
5589 try {
5590 pi = pm.resolveContentProvider(name,
5591 PackageManager.GET_URI_PERMISSION_PATTERNS);
5592 } catch (RemoteException ex) {
5593 }
5594 }
5595 if (pi == null) {
5596 Log.w(TAG, "No content provider found for: " + name);
5597 return;
5598 }
5599
5600 int targetUid;
5601 try {
5602 targetUid = pm.getPackageUid(targetPkg);
5603 if (targetUid < 0) {
5604 return;
5605 }
5606 } catch (RemoteException ex) {
5607 return;
5608 }
5609
5610 // First... does the target actually need this permission?
5611 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5612 // No need to grant the target this permission.
5613 return;
5614 }
5615
5616 // Second... maybe someone else has already granted the
5617 // permission?
5618 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5619 // No need to grant the target this permission.
5620 return;
5621 }
5622
5623 // Third... is the provider allowing granting of URI permissions?
5624 if (!pi.grantUriPermissions) {
5625 throw new SecurityException("Provider " + pi.packageName
5626 + "/" + pi.name
5627 + " does not allow granting of Uri permissions (uri "
5628 + uri + ")");
5629 }
5630 if (pi.uriPermissionPatterns != null) {
5631 final int N = pi.uriPermissionPatterns.length;
5632 boolean allowed = false;
5633 for (int i=0; i<N; i++) {
5634 if (pi.uriPermissionPatterns[i] != null
5635 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5636 allowed = true;
5637 break;
5638 }
5639 }
5640 if (!allowed) {
5641 throw new SecurityException("Provider " + pi.packageName
5642 + "/" + pi.name
5643 + " does not allow granting of permission to path of Uri "
5644 + uri);
5645 }
5646 }
5647
5648 // Fourth... does the caller itself have permission to access
5649 // this uri?
5650 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5651 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5652 throw new SecurityException("Uid " + callingUid
5653 + " does not have permission to uri " + uri);
5654 }
5655 }
5656
5657 // Okay! So here we are: the caller has the assumed permission
5658 // to the uri, and the target doesn't. Let's now give this to
5659 // the target.
5660
5661 HashMap<Uri, UriPermission> targetUris
5662 = mGrantedUriPermissions.get(targetUid);
5663 if (targetUris == null) {
5664 targetUris = new HashMap<Uri, UriPermission>();
5665 mGrantedUriPermissions.put(targetUid, targetUris);
5666 }
5667
5668 UriPermission perm = targetUris.get(uri);
5669 if (perm == null) {
5670 perm = new UriPermission(targetUid, uri);
5671 targetUris.put(uri, perm);
5672
5673 }
5674 perm.modeFlags |= modeFlags;
5675 if (activity == null) {
5676 perm.globalModeFlags |= modeFlags;
5677 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5678 perm.readActivities.add(activity);
5679 if (activity.readUriPermissions == null) {
5680 activity.readUriPermissions = new HashSet<UriPermission>();
5681 }
5682 activity.readUriPermissions.add(perm);
5683 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5684 perm.writeActivities.add(activity);
5685 if (activity.writeUriPermissions == null) {
5686 activity.writeUriPermissions = new HashSet<UriPermission>();
5687 }
5688 activity.writeUriPermissions.add(perm);
5689 }
5690 }
5691
5692 private void grantUriPermissionFromIntentLocked(int callingUid,
5693 String targetPkg, Intent intent, HistoryRecord activity) {
5694 if (intent == null) {
5695 return;
5696 }
5697 Uri data = intent.getData();
5698 if (data == null) {
5699 return;
5700 }
5701 grantUriPermissionLocked(callingUid, targetPkg, data,
5702 intent.getFlags(), activity);
5703 }
5704
5705 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5706 Uri uri, int modeFlags) {
5707 synchronized(this) {
5708 final ProcessRecord r = getRecordForAppLocked(caller);
5709 if (r == null) {
5710 throw new SecurityException("Unable to find app for caller "
5711 + caller
5712 + " when granting permission to uri " + uri);
5713 }
5714 if (targetPkg == null) {
5715 Log.w(TAG, "grantUriPermission: null target");
5716 return;
5717 }
5718 if (uri == null) {
5719 Log.w(TAG, "grantUriPermission: null uri");
5720 return;
5721 }
5722
5723 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5724 null);
5725 }
5726 }
5727
5728 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5729 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5730 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5731 HashMap<Uri, UriPermission> perms
5732 = mGrantedUriPermissions.get(perm.uid);
5733 if (perms != null) {
5734 perms.remove(perm.uri);
5735 if (perms.size() == 0) {
5736 mGrantedUriPermissions.remove(perm.uid);
5737 }
5738 }
5739 }
5740 }
5741
5742 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5743 if (activity.readUriPermissions != null) {
5744 for (UriPermission perm : activity.readUriPermissions) {
5745 perm.readActivities.remove(activity);
5746 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5747 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5748 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5749 removeUriPermissionIfNeededLocked(perm);
5750 }
5751 }
5752 }
5753 if (activity.writeUriPermissions != null) {
5754 for (UriPermission perm : activity.writeUriPermissions) {
5755 perm.writeActivities.remove(activity);
5756 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5757 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5758 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5759 removeUriPermissionIfNeededLocked(perm);
5760 }
5761 }
5762 }
5763 }
5764
5765 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5766 int modeFlags) {
5767 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5768 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5769 if (modeFlags == 0) {
5770 return;
5771 }
5772
5773 final IPackageManager pm = ActivityThread.getPackageManager();
5774
5775 final String authority = uri.getAuthority();
5776 ProviderInfo pi = null;
5777 ContentProviderRecord cpr
5778 = (ContentProviderRecord)mProvidersByName.get(authority);
5779 if (cpr != null) {
5780 pi = cpr.info;
5781 } else {
5782 try {
5783 pi = pm.resolveContentProvider(authority,
5784 PackageManager.GET_URI_PERMISSION_PATTERNS);
5785 } catch (RemoteException ex) {
5786 }
5787 }
5788 if (pi == null) {
5789 Log.w(TAG, "No content provider found for: " + authority);
5790 return;
5791 }
5792
5793 // Does the caller have this permission on the URI?
5794 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5795 // Right now, if you are not the original owner of the permission,
5796 // you are not allowed to revoke it.
5797 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5798 throw new SecurityException("Uid " + callingUid
5799 + " does not have permission to uri " + uri);
5800 //}
5801 }
5802
5803 // Go through all of the permissions and remove any that match.
5804 final List<String> SEGMENTS = uri.getPathSegments();
5805 if (SEGMENTS != null) {
5806 final int NS = SEGMENTS.size();
5807 int N = mGrantedUriPermissions.size();
5808 for (int i=0; i<N; i++) {
5809 HashMap<Uri, UriPermission> perms
5810 = mGrantedUriPermissions.valueAt(i);
5811 Iterator<UriPermission> it = perms.values().iterator();
5812 toploop:
5813 while (it.hasNext()) {
5814 UriPermission perm = it.next();
5815 Uri targetUri = perm.uri;
5816 if (!authority.equals(targetUri.getAuthority())) {
5817 continue;
5818 }
5819 List<String> targetSegments = targetUri.getPathSegments();
5820 if (targetSegments == null) {
5821 continue;
5822 }
5823 if (targetSegments.size() < NS) {
5824 continue;
5825 }
5826 for (int j=0; j<NS; j++) {
5827 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5828 continue toploop;
5829 }
5830 }
5831 perm.clearModes(modeFlags);
5832 if (perm.modeFlags == 0) {
5833 it.remove();
5834 }
5835 }
5836 if (perms.size() == 0) {
5837 mGrantedUriPermissions.remove(
5838 mGrantedUriPermissions.keyAt(i));
5839 N--;
5840 i--;
5841 }
5842 }
5843 }
5844 }
5845
5846 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5847 int modeFlags) {
5848 synchronized(this) {
5849 final ProcessRecord r = getRecordForAppLocked(caller);
5850 if (r == null) {
5851 throw new SecurityException("Unable to find app for caller "
5852 + caller
5853 + " when revoking permission to uri " + uri);
5854 }
5855 if (uri == null) {
5856 Log.w(TAG, "revokeUriPermission: null uri");
5857 return;
5858 }
5859
5860 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5861 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5862 if (modeFlags == 0) {
5863 return;
5864 }
5865
5866 final IPackageManager pm = ActivityThread.getPackageManager();
5867
5868 final String authority = uri.getAuthority();
5869 ProviderInfo pi = null;
5870 ContentProviderRecord cpr
5871 = (ContentProviderRecord)mProvidersByName.get(authority);
5872 if (cpr != null) {
5873 pi = cpr.info;
5874 } else {
5875 try {
5876 pi = pm.resolveContentProvider(authority,
5877 PackageManager.GET_URI_PERMISSION_PATTERNS);
5878 } catch (RemoteException ex) {
5879 }
5880 }
5881 if (pi == null) {
5882 Log.w(TAG, "No content provider found for: " + authority);
5883 return;
5884 }
5885
5886 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5887 }
5888 }
5889
5890 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5891 synchronized (this) {
5892 ProcessRecord app =
5893 who != null ? getRecordForAppLocked(who) : null;
5894 if (app == null) return;
5895
5896 Message msg = Message.obtain();
5897 msg.what = WAIT_FOR_DEBUGGER_MSG;
5898 msg.obj = app;
5899 msg.arg1 = waiting ? 1 : 0;
5900 mHandler.sendMessage(msg);
5901 }
5902 }
5903
5904 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5905 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005906 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005907 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005908 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005909 }
5910
5911 // =========================================================
5912 // TASK MANAGEMENT
5913 // =========================================================
5914
5915 public List getTasks(int maxNum, int flags,
5916 IThumbnailReceiver receiver) {
5917 ArrayList list = new ArrayList();
5918
5919 PendingThumbnailsRecord pending = null;
5920 IApplicationThread topThumbnail = null;
5921 HistoryRecord topRecord = null;
5922
5923 synchronized(this) {
5924 if (localLOGV) Log.v(
5925 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
5926 + ", receiver=" + receiver);
5927
5928 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
5929 != PackageManager.PERMISSION_GRANTED) {
5930 if (receiver != null) {
5931 // If the caller wants to wait for pending thumbnails,
5932 // it ain't gonna get them.
5933 try {
5934 receiver.finished();
5935 } catch (RemoteException ex) {
5936 }
5937 }
5938 String msg = "Permission Denial: getTasks() from pid="
5939 + Binder.getCallingPid()
5940 + ", uid=" + Binder.getCallingUid()
5941 + " requires " + android.Manifest.permission.GET_TASKS;
5942 Log.w(TAG, msg);
5943 throw new SecurityException(msg);
5944 }
5945
5946 int pos = mHistory.size()-1;
5947 HistoryRecord next =
5948 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5949 HistoryRecord top = null;
5950 CharSequence topDescription = null;
5951 TaskRecord curTask = null;
5952 int numActivities = 0;
5953 int numRunning = 0;
5954 while (pos >= 0 && maxNum > 0) {
5955 final HistoryRecord r = next;
5956 pos--;
5957 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5958
5959 // Initialize state for next task if needed.
5960 if (top == null ||
5961 (top.state == ActivityState.INITIALIZING
5962 && top.task == r.task)) {
5963 top = r;
5964 topDescription = r.description;
5965 curTask = r.task;
5966 numActivities = numRunning = 0;
5967 }
5968
5969 // Add 'r' into the current task.
5970 numActivities++;
5971 if (r.app != null && r.app.thread != null) {
5972 numRunning++;
5973 }
5974 if (topDescription == null) {
5975 topDescription = r.description;
5976 }
5977
5978 if (localLOGV) Log.v(
5979 TAG, r.intent.getComponent().flattenToShortString()
5980 + ": task=" + r.task);
5981
5982 // If the next one is a different task, generate a new
5983 // TaskInfo entry for what we have.
5984 if (next == null || next.task != curTask) {
5985 ActivityManager.RunningTaskInfo ci
5986 = new ActivityManager.RunningTaskInfo();
5987 ci.id = curTask.taskId;
5988 ci.baseActivity = r.intent.getComponent();
5989 ci.topActivity = top.intent.getComponent();
5990 ci.thumbnail = top.thumbnail;
5991 ci.description = topDescription;
5992 ci.numActivities = numActivities;
5993 ci.numRunning = numRunning;
5994 //System.out.println(
5995 // "#" + maxNum + ": " + " descr=" + ci.description);
5996 if (ci.thumbnail == null && receiver != null) {
5997 if (localLOGV) Log.v(
5998 TAG, "State=" + top.state + "Idle=" + top.idle
5999 + " app=" + top.app
6000 + " thr=" + (top.app != null ? top.app.thread : null));
6001 if (top.state == ActivityState.RESUMED
6002 || top.state == ActivityState.PAUSING) {
6003 if (top.idle && top.app != null
6004 && top.app.thread != null) {
6005 topRecord = top;
6006 topThumbnail = top.app.thread;
6007 } else {
6008 top.thumbnailNeeded = true;
6009 }
6010 }
6011 if (pending == null) {
6012 pending = new PendingThumbnailsRecord(receiver);
6013 }
6014 pending.pendingRecords.add(top);
6015 }
6016 list.add(ci);
6017 maxNum--;
6018 top = null;
6019 }
6020 }
6021
6022 if (pending != null) {
6023 mPendingThumbnails.add(pending);
6024 }
6025 }
6026
6027 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6028
6029 if (topThumbnail != null) {
6030 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6031 try {
6032 topThumbnail.requestThumbnail(topRecord);
6033 } catch (Exception e) {
6034 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6035 sendPendingThumbnail(null, topRecord, null, null, true);
6036 }
6037 }
6038
6039 if (pending == null && receiver != null) {
6040 // In this case all thumbnails were available and the client
6041 // is being asked to be told when the remaining ones come in...
6042 // which is unusually, since the top-most currently running
6043 // activity should never have a canned thumbnail! Oh well.
6044 try {
6045 receiver.finished();
6046 } catch (RemoteException ex) {
6047 }
6048 }
6049
6050 return list;
6051 }
6052
6053 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6054 int flags) {
6055 synchronized (this) {
6056 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6057 "getRecentTasks()");
6058
6059 final int N = mRecentTasks.size();
6060 ArrayList<ActivityManager.RecentTaskInfo> res
6061 = new ArrayList<ActivityManager.RecentTaskInfo>(
6062 maxNum < N ? maxNum : N);
6063 for (int i=0; i<N && maxNum > 0; i++) {
6064 TaskRecord tr = mRecentTasks.get(i);
6065 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6066 || (tr.intent == null)
6067 || ((tr.intent.getFlags()
6068 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6069 ActivityManager.RecentTaskInfo rti
6070 = new ActivityManager.RecentTaskInfo();
6071 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6072 rti.baseIntent = new Intent(
6073 tr.intent != null ? tr.intent : tr.affinityIntent);
6074 rti.origActivity = tr.origActivity;
6075 res.add(rti);
6076 maxNum--;
6077 }
6078 }
6079 return res;
6080 }
6081 }
6082
6083 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6084 int j;
6085 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6086 TaskRecord jt = startTask;
6087
6088 // First look backwards
6089 for (j=startIndex-1; j>=0; j--) {
6090 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6091 if (r.task != jt) {
6092 jt = r.task;
6093 if (affinity.equals(jt.affinity)) {
6094 return j;
6095 }
6096 }
6097 }
6098
6099 // Now look forwards
6100 final int N = mHistory.size();
6101 jt = startTask;
6102 for (j=startIndex+1; j<N; j++) {
6103 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6104 if (r.task != jt) {
6105 if (affinity.equals(jt.affinity)) {
6106 return j;
6107 }
6108 jt = r.task;
6109 }
6110 }
6111
6112 // Might it be at the top?
6113 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6114 return N-1;
6115 }
6116
6117 return -1;
6118 }
6119
6120 /**
6121 * Perform a reset of the given task, if needed as part of launching it.
6122 * Returns the new HistoryRecord at the top of the task.
6123 */
6124 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6125 HistoryRecord newActivity) {
6126 boolean forceReset = (newActivity.info.flags
6127 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6128 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6129 if ((newActivity.info.flags
6130 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6131 forceReset = true;
6132 }
6133 }
6134
6135 final TaskRecord task = taskTop.task;
6136
6137 // We are going to move through the history list so that we can look
6138 // at each activity 'target' with 'below' either the interesting
6139 // activity immediately below it in the stack or null.
6140 HistoryRecord target = null;
6141 int targetI = 0;
6142 int taskTopI = -1;
6143 int replyChainEnd = -1;
6144 int lastReparentPos = -1;
6145 for (int i=mHistory.size()-1; i>=-1; i--) {
6146 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6147
6148 if (below != null && below.finishing) {
6149 continue;
6150 }
6151 if (target == null) {
6152 target = below;
6153 targetI = i;
6154 // If we were in the middle of a reply chain before this
6155 // task, it doesn't appear like the root of the chain wants
6156 // anything interesting, so drop it.
6157 replyChainEnd = -1;
6158 continue;
6159 }
6160
6161 final int flags = target.info.flags;
6162
6163 final boolean finishOnTaskLaunch =
6164 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6165 final boolean allowTaskReparenting =
6166 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6167
6168 if (target.task == task) {
6169 // We are inside of the task being reset... we'll either
6170 // finish this activity, push it out for another task,
6171 // or leave it as-is. We only do this
6172 // for activities that are not the root of the task (since
6173 // if we finish the root, we may no longer have the task!).
6174 if (taskTopI < 0) {
6175 taskTopI = targetI;
6176 }
6177 if (below != null && below.task == task) {
6178 final boolean clearWhenTaskReset =
6179 (target.intent.getFlags()
6180 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006181 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006182 // If this activity is sending a reply to a previous
6183 // activity, we can't do anything with it now until
6184 // we reach the start of the reply chain.
6185 // XXX note that we are assuming the result is always
6186 // to the previous activity, which is almost always
6187 // the case but we really shouldn't count on.
6188 if (replyChainEnd < 0) {
6189 replyChainEnd = targetI;
6190 }
Ed Heyl73798232009-03-24 21:32:21 -07006191 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006192 && target.taskAffinity != null
6193 && !target.taskAffinity.equals(task.affinity)) {
6194 // If this activity has an affinity for another
6195 // task, then we need to move it out of here. We will
6196 // move it as far out of the way as possible, to the
6197 // bottom of the activity stack. This also keeps it
6198 // correctly ordered with any activities we previously
6199 // moved.
6200 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6201 if (target.taskAffinity != null
6202 && target.taskAffinity.equals(p.task.affinity)) {
6203 // If the activity currently at the bottom has the
6204 // same task affinity as the one we are moving,
6205 // then merge it into the same task.
6206 target.task = p.task;
6207 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6208 + " out to bottom task " + p.task);
6209 } else {
6210 mCurTask++;
6211 if (mCurTask <= 0) {
6212 mCurTask = 1;
6213 }
6214 target.task = new TaskRecord(mCurTask, target.info, null,
6215 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6216 target.task.affinityIntent = target.intent;
6217 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6218 + " out to new task " + target.task);
6219 }
6220 mWindowManager.setAppGroupId(target, task.taskId);
6221 if (replyChainEnd < 0) {
6222 replyChainEnd = targetI;
6223 }
6224 int dstPos = 0;
6225 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6226 p = (HistoryRecord)mHistory.get(srcPos);
6227 if (p.finishing) {
6228 continue;
6229 }
6230 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6231 + " out to target's task " + target.task);
6232 task.numActivities--;
6233 p.task = target.task;
6234 target.task.numActivities++;
6235 mHistory.remove(srcPos);
6236 mHistory.add(dstPos, p);
6237 mWindowManager.moveAppToken(dstPos, p);
6238 mWindowManager.setAppGroupId(p, p.task.taskId);
6239 dstPos++;
6240 if (VALIDATE_TOKENS) {
6241 mWindowManager.validateAppTokens(mHistory);
6242 }
6243 i++;
6244 }
6245 if (taskTop == p) {
6246 taskTop = below;
6247 }
6248 if (taskTopI == replyChainEnd) {
6249 taskTopI = -1;
6250 }
6251 replyChainEnd = -1;
6252 addRecentTask(target.task);
6253 } else if (forceReset || finishOnTaskLaunch
6254 || clearWhenTaskReset) {
6255 // If the activity should just be removed -- either
6256 // because it asks for it, or the task should be
6257 // cleared -- then finish it and anything that is
6258 // part of its reply chain.
6259 if (clearWhenTaskReset) {
6260 // In this case, we want to finish this activity
6261 // and everything above it, so be sneaky and pretend
6262 // like these are all in the reply chain.
6263 replyChainEnd = targetI+1;
6264 while (replyChainEnd < mHistory.size() &&
6265 ((HistoryRecord)mHistory.get(
6266 replyChainEnd)).task == task) {
6267 replyChainEnd++;
6268 }
6269 replyChainEnd--;
6270 } else if (replyChainEnd < 0) {
6271 replyChainEnd = targetI;
6272 }
6273 HistoryRecord p = null;
6274 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6275 p = (HistoryRecord)mHistory.get(srcPos);
6276 if (p.finishing) {
6277 continue;
6278 }
6279 if (finishActivityLocked(p, srcPos,
6280 Activity.RESULT_CANCELED, null, "reset")) {
6281 replyChainEnd--;
6282 srcPos--;
6283 }
6284 }
6285 if (taskTop == p) {
6286 taskTop = below;
6287 }
6288 if (taskTopI == replyChainEnd) {
6289 taskTopI = -1;
6290 }
6291 replyChainEnd = -1;
6292 } else {
6293 // If we were in the middle of a chain, well the
6294 // activity that started it all doesn't want anything
6295 // special, so leave it all as-is.
6296 replyChainEnd = -1;
6297 }
6298 } else {
6299 // Reached the bottom of the task -- any reply chain
6300 // should be left as-is.
6301 replyChainEnd = -1;
6302 }
6303
6304 } else if (target.resultTo != null) {
6305 // If this activity is sending a reply to a previous
6306 // activity, we can't do anything with it now until
6307 // we reach the start of the reply chain.
6308 // XXX note that we are assuming the result is always
6309 // to the previous activity, which is almost always
6310 // the case but we really shouldn't count on.
6311 if (replyChainEnd < 0) {
6312 replyChainEnd = targetI;
6313 }
6314
6315 } else if (taskTopI >= 0 && allowTaskReparenting
6316 && task.affinity != null
6317 && task.affinity.equals(target.taskAffinity)) {
6318 // We are inside of another task... if this activity has
6319 // an affinity for our task, then either remove it if we are
6320 // clearing or move it over to our task. Note that
6321 // we currently punt on the case where we are resetting a
6322 // task that is not at the top but who has activities above
6323 // with an affinity to it... this is really not a normal
6324 // case, and we will need to later pull that task to the front
6325 // and usually at that point we will do the reset and pick
6326 // up those remaining activities. (This only happens if
6327 // someone starts an activity in a new task from an activity
6328 // in a task that is not currently on top.)
6329 if (forceReset || finishOnTaskLaunch) {
6330 if (replyChainEnd < 0) {
6331 replyChainEnd = targetI;
6332 }
6333 HistoryRecord p = null;
6334 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6335 p = (HistoryRecord)mHistory.get(srcPos);
6336 if (p.finishing) {
6337 continue;
6338 }
6339 if (finishActivityLocked(p, srcPos,
6340 Activity.RESULT_CANCELED, null, "reset")) {
6341 taskTopI--;
6342 lastReparentPos--;
6343 replyChainEnd--;
6344 srcPos--;
6345 }
6346 }
6347 replyChainEnd = -1;
6348 } else {
6349 if (replyChainEnd < 0) {
6350 replyChainEnd = targetI;
6351 }
6352 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6353 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6354 if (p.finishing) {
6355 continue;
6356 }
6357 if (lastReparentPos < 0) {
6358 lastReparentPos = taskTopI;
6359 taskTop = p;
6360 } else {
6361 lastReparentPos--;
6362 }
6363 mHistory.remove(srcPos);
6364 p.task.numActivities--;
6365 p.task = task;
6366 mHistory.add(lastReparentPos, p);
6367 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6368 + " in to resetting task " + task);
6369 task.numActivities++;
6370 mWindowManager.moveAppToken(lastReparentPos, p);
6371 mWindowManager.setAppGroupId(p, p.task.taskId);
6372 if (VALIDATE_TOKENS) {
6373 mWindowManager.validateAppTokens(mHistory);
6374 }
6375 }
6376 replyChainEnd = -1;
6377
6378 // Now we've moved it in to place... but what if this is
6379 // a singleTop activity and we have put it on top of another
6380 // instance of the same activity? Then we drop the instance
6381 // below so it remains singleTop.
6382 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6383 for (int j=lastReparentPos-1; j>=0; j--) {
6384 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6385 if (p.finishing) {
6386 continue;
6387 }
6388 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6389 if (finishActivityLocked(p, j,
6390 Activity.RESULT_CANCELED, null, "replace")) {
6391 taskTopI--;
6392 lastReparentPos--;
6393 }
6394 }
6395 }
6396 }
6397 }
6398 }
6399
6400 target = below;
6401 targetI = i;
6402 }
6403
6404 return taskTop;
6405 }
6406
6407 /**
6408 * TODO: Add mWatcher hook
6409 */
6410 public void moveTaskToFront(int task) {
6411 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6412 "moveTaskToFront()");
6413
6414 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006415 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6416 Binder.getCallingUid(), "Task to front")) {
6417 return;
6418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006419 final long origId = Binder.clearCallingIdentity();
6420 try {
6421 int N = mRecentTasks.size();
6422 for (int i=0; i<N; i++) {
6423 TaskRecord tr = mRecentTasks.get(i);
6424 if (tr.taskId == task) {
6425 moveTaskToFrontLocked(tr);
6426 return;
6427 }
6428 }
6429 for (int i=mHistory.size()-1; i>=0; i--) {
6430 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6431 if (hr.task.taskId == task) {
6432 moveTaskToFrontLocked(hr.task);
6433 return;
6434 }
6435 }
6436 } finally {
6437 Binder.restoreCallingIdentity(origId);
6438 }
6439 }
6440 }
6441
6442 private final void moveTaskToFrontLocked(TaskRecord tr) {
6443 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6444
6445 final int task = tr.taskId;
6446 int top = mHistory.size()-1;
6447
6448 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6449 // nothing to do!
6450 return;
6451 }
6452
6453 if (DEBUG_TRANSITION) Log.v(TAG,
6454 "Prepare to front transition: task=" + tr);
6455 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6456
6457 ArrayList moved = new ArrayList();
6458
6459 // Applying the affinities may have removed entries from the history,
6460 // so get the size again.
6461 top = mHistory.size()-1;
6462 int pos = top;
6463
6464 // Shift all activities with this task up to the top
6465 // of the stack, keeping them in the same internal order.
6466 while (pos >= 0) {
6467 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6468 if (localLOGV) Log.v(
6469 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6470 boolean first = true;
6471 if (r.task.taskId == task) {
6472 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6473 mHistory.remove(pos);
6474 mHistory.add(top, r);
6475 moved.add(0, r);
6476 top--;
6477 if (first) {
6478 addRecentTask(r.task);
6479 first = false;
6480 }
6481 }
6482 pos--;
6483 }
6484
6485 mWindowManager.moveAppTokensToTop(moved);
6486 if (VALIDATE_TOKENS) {
6487 mWindowManager.validateAppTokens(mHistory);
6488 }
6489
6490 finishTaskMove(task);
6491 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6492 }
6493
6494 private final void finishTaskMove(int task) {
6495 resumeTopActivityLocked(null);
6496 }
6497
6498 public void moveTaskToBack(int task) {
6499 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6500 "moveTaskToBack()");
6501
6502 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006503 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6504 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6505 Binder.getCallingUid(), "Task to back")) {
6506 return;
6507 }
6508 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006509 final long origId = Binder.clearCallingIdentity();
6510 moveTaskToBackLocked(task);
6511 Binder.restoreCallingIdentity(origId);
6512 }
6513 }
6514
6515 /**
6516 * Moves an activity, and all of the other activities within the same task, to the bottom
6517 * of the history stack. The activity's order within the task is unchanged.
6518 *
6519 * @param token A reference to the activity we wish to move
6520 * @param nonRoot If false then this only works if the activity is the root
6521 * of a task; if true it will work for any activity in a task.
6522 * @return Returns true if the move completed, false if not.
6523 */
6524 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6525 synchronized(this) {
6526 final long origId = Binder.clearCallingIdentity();
6527 int taskId = getTaskForActivityLocked(token, !nonRoot);
6528 if (taskId >= 0) {
6529 return moveTaskToBackLocked(taskId);
6530 }
6531 Binder.restoreCallingIdentity(origId);
6532 }
6533 return false;
6534 }
6535
6536 /**
6537 * Worker method for rearranging history stack. Implements the function of moving all
6538 * activities for a specific task (gathering them if disjoint) into a single group at the
6539 * bottom of the stack.
6540 *
6541 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6542 * to premeptively cancel the move.
6543 *
6544 * @param task The taskId to collect and move to the bottom.
6545 * @return Returns true if the move completed, false if not.
6546 */
6547 private final boolean moveTaskToBackLocked(int task) {
6548 Log.i(TAG, "moveTaskToBack: " + task);
6549
6550 // If we have a watcher, preflight the move before committing to it. First check
6551 // for *other* available tasks, but if none are available, then try again allowing the
6552 // current task to be selected.
6553 if (mWatcher != null) {
6554 HistoryRecord next = topRunningActivityLocked(null, task);
6555 if (next == null) {
6556 next = topRunningActivityLocked(null, 0);
6557 }
6558 if (next != null) {
6559 // ask watcher if this is allowed
6560 boolean moveOK = true;
6561 try {
6562 moveOK = mWatcher.activityResuming(next.packageName);
6563 } catch (RemoteException e) {
6564 mWatcher = null;
6565 }
6566 if (!moveOK) {
6567 return false;
6568 }
6569 }
6570 }
6571
6572 ArrayList moved = new ArrayList();
6573
6574 if (DEBUG_TRANSITION) Log.v(TAG,
6575 "Prepare to back transition: task=" + task);
6576 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6577
6578 final int N = mHistory.size();
6579 int bottom = 0;
6580 int pos = 0;
6581
6582 // Shift all activities with this task down to the bottom
6583 // of the stack, keeping them in the same internal order.
6584 while (pos < N) {
6585 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6586 if (localLOGV) Log.v(
6587 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6588 if (r.task.taskId == task) {
6589 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6590 mHistory.remove(pos);
6591 mHistory.add(bottom, r);
6592 moved.add(r);
6593 bottom++;
6594 }
6595 pos++;
6596 }
6597
6598 mWindowManager.moveAppTokensToBottom(moved);
6599 if (VALIDATE_TOKENS) {
6600 mWindowManager.validateAppTokens(mHistory);
6601 }
6602
6603 finishTaskMove(task);
6604 return true;
6605 }
6606
6607 public void moveTaskBackwards(int task) {
6608 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6609 "moveTaskBackwards()");
6610
6611 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006612 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6613 Binder.getCallingUid(), "Task backwards")) {
6614 return;
6615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006616 final long origId = Binder.clearCallingIdentity();
6617 moveTaskBackwardsLocked(task);
6618 Binder.restoreCallingIdentity(origId);
6619 }
6620 }
6621
6622 private final void moveTaskBackwardsLocked(int task) {
6623 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6624 }
6625
6626 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6627 synchronized(this) {
6628 return getTaskForActivityLocked(token, onlyRoot);
6629 }
6630 }
6631
6632 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6633 final int N = mHistory.size();
6634 TaskRecord lastTask = null;
6635 for (int i=0; i<N; i++) {
6636 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6637 if (r == token) {
6638 if (!onlyRoot || lastTask != r.task) {
6639 return r.task.taskId;
6640 }
6641 return -1;
6642 }
6643 lastTask = r.task;
6644 }
6645
6646 return -1;
6647 }
6648
6649 /**
6650 * Returns the top activity in any existing task matching the given
6651 * Intent. Returns null if no such task is found.
6652 */
6653 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6654 ComponentName cls = intent.getComponent();
6655 if (info.targetActivity != null) {
6656 cls = new ComponentName(info.packageName, info.targetActivity);
6657 }
6658
6659 TaskRecord cp = null;
6660
6661 final int N = mHistory.size();
6662 for (int i=(N-1); i>=0; i--) {
6663 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6664 if (!r.finishing && r.task != cp
6665 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6666 cp = r.task;
6667 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6668 // + "/aff=" + r.task.affinity + " to new cls="
6669 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6670 if (r.task.affinity != null) {
6671 if (r.task.affinity.equals(info.taskAffinity)) {
6672 //Log.i(TAG, "Found matching affinity!");
6673 return r;
6674 }
6675 } else if (r.task.intent != null
6676 && r.task.intent.getComponent().equals(cls)) {
6677 //Log.i(TAG, "Found matching class!");
6678 //dump();
6679 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6680 return r;
6681 } else if (r.task.affinityIntent != null
6682 && r.task.affinityIntent.getComponent().equals(cls)) {
6683 //Log.i(TAG, "Found matching class!");
6684 //dump();
6685 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6686 return r;
6687 }
6688 }
6689 }
6690
6691 return null;
6692 }
6693
6694 /**
6695 * Returns the first activity (starting from the top of the stack) that
6696 * is the same as the given activity. Returns null if no such activity
6697 * is found.
6698 */
6699 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6700 ComponentName cls = intent.getComponent();
6701 if (info.targetActivity != null) {
6702 cls = new ComponentName(info.packageName, info.targetActivity);
6703 }
6704
6705 final int N = mHistory.size();
6706 for (int i=(N-1); i>=0; i--) {
6707 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6708 if (!r.finishing) {
6709 if (r.intent.getComponent().equals(cls)) {
6710 //Log.i(TAG, "Found matching class!");
6711 //dump();
6712 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6713 return r;
6714 }
6715 }
6716 }
6717
6718 return null;
6719 }
6720
6721 public void finishOtherInstances(IBinder token, ComponentName className) {
6722 synchronized(this) {
6723 final long origId = Binder.clearCallingIdentity();
6724
6725 int N = mHistory.size();
6726 TaskRecord lastTask = null;
6727 for (int i=0; i<N; i++) {
6728 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6729 if (r.realActivity.equals(className)
6730 && r != token && lastTask != r.task) {
6731 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6732 null, "others")) {
6733 i--;
6734 N--;
6735 }
6736 }
6737 lastTask = r.task;
6738 }
6739
6740 Binder.restoreCallingIdentity(origId);
6741 }
6742 }
6743
6744 // =========================================================
6745 // THUMBNAILS
6746 // =========================================================
6747
6748 public void reportThumbnail(IBinder token,
6749 Bitmap thumbnail, CharSequence description) {
6750 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6751 final long origId = Binder.clearCallingIdentity();
6752 sendPendingThumbnail(null, token, thumbnail, description, true);
6753 Binder.restoreCallingIdentity(origId);
6754 }
6755
6756 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6757 Bitmap thumbnail, CharSequence description, boolean always) {
6758 TaskRecord task = null;
6759 ArrayList receivers = null;
6760
6761 //System.out.println("Send pending thumbnail: " + r);
6762
6763 synchronized(this) {
6764 if (r == null) {
6765 int index = indexOfTokenLocked(token, false);
6766 if (index < 0) {
6767 return;
6768 }
6769 r = (HistoryRecord)mHistory.get(index);
6770 }
6771 if (thumbnail == null) {
6772 thumbnail = r.thumbnail;
6773 description = r.description;
6774 }
6775 if (thumbnail == null && !always) {
6776 // If there is no thumbnail, and this entry is not actually
6777 // going away, then abort for now and pick up the next
6778 // thumbnail we get.
6779 return;
6780 }
6781 task = r.task;
6782
6783 int N = mPendingThumbnails.size();
6784 int i=0;
6785 while (i<N) {
6786 PendingThumbnailsRecord pr =
6787 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6788 //System.out.println("Looking in " + pr.pendingRecords);
6789 if (pr.pendingRecords.remove(r)) {
6790 if (receivers == null) {
6791 receivers = new ArrayList();
6792 }
6793 receivers.add(pr);
6794 if (pr.pendingRecords.size() == 0) {
6795 pr.finished = true;
6796 mPendingThumbnails.remove(i);
6797 N--;
6798 continue;
6799 }
6800 }
6801 i++;
6802 }
6803 }
6804
6805 if (receivers != null) {
6806 final int N = receivers.size();
6807 for (int i=0; i<N; i++) {
6808 try {
6809 PendingThumbnailsRecord pr =
6810 (PendingThumbnailsRecord)receivers.get(i);
6811 pr.receiver.newThumbnail(
6812 task != null ? task.taskId : -1, thumbnail, description);
6813 if (pr.finished) {
6814 pr.receiver.finished();
6815 }
6816 } catch (Exception e) {
6817 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6818 }
6819 }
6820 }
6821 }
6822
6823 // =========================================================
6824 // CONTENT PROVIDERS
6825 // =========================================================
6826
6827 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6828 List providers = null;
6829 try {
6830 providers = ActivityThread.getPackageManager().
6831 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006832 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006833 } catch (RemoteException ex) {
6834 }
6835 if (providers != null) {
6836 final int N = providers.size();
6837 for (int i=0; i<N; i++) {
6838 ProviderInfo cpi =
6839 (ProviderInfo)providers.get(i);
6840 ContentProviderRecord cpr =
6841 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6842 if (cpr == null) {
6843 cpr = new ContentProviderRecord(cpi, app.info);
6844 mProvidersByClass.put(cpi.name, cpr);
6845 }
6846 app.pubProviders.put(cpi.name, cpr);
6847 app.addPackage(cpi.applicationInfo.packageName);
6848 }
6849 }
6850 return providers;
6851 }
6852
6853 private final String checkContentProviderPermissionLocked(
6854 ProviderInfo cpi, ProcessRecord r, int mode) {
6855 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6856 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6857 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6858 cpi.exported ? -1 : cpi.applicationInfo.uid)
6859 == PackageManager.PERMISSION_GRANTED
6860 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6861 return null;
6862 }
6863 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6864 cpi.exported ? -1 : cpi.applicationInfo.uid)
6865 == PackageManager.PERMISSION_GRANTED) {
6866 return null;
6867 }
6868 String msg = "Permission Denial: opening provider " + cpi.name
6869 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6870 + ", uid=" + callingUid + ") requires "
6871 + cpi.readPermission + " or " + cpi.writePermission;
6872 Log.w(TAG, msg);
6873 return msg;
6874 }
6875
6876 private final ContentProviderHolder getContentProviderImpl(
6877 IApplicationThread caller, String name) {
6878 ContentProviderRecord cpr;
6879 ProviderInfo cpi = null;
6880
6881 synchronized(this) {
6882 ProcessRecord r = null;
6883 if (caller != null) {
6884 r = getRecordForAppLocked(caller);
6885 if (r == null) {
6886 throw new SecurityException(
6887 "Unable to find app for caller " + caller
6888 + " (pid=" + Binder.getCallingPid()
6889 + ") when getting content provider " + name);
6890 }
6891 }
6892
6893 // First check if this content provider has been published...
6894 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6895 if (cpr != null) {
6896 cpi = cpr.info;
6897 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6898 return new ContentProviderHolder(cpi,
6899 cpi.readPermission != null
6900 ? cpi.readPermission : cpi.writePermission);
6901 }
6902
6903 if (r != null && cpr.canRunHere(r)) {
6904 // This provider has been published or is in the process
6905 // of being published... but it is also allowed to run
6906 // in the caller's process, so don't make a connection
6907 // and just let the caller instantiate its own instance.
6908 if (cpr.provider != null) {
6909 // don't give caller the provider object, it needs
6910 // to make its own.
6911 cpr = new ContentProviderRecord(cpr);
6912 }
6913 return cpr;
6914 }
6915
6916 final long origId = Binder.clearCallingIdentity();
6917
6918 // In this case the provider is a single instance, so we can
6919 // return it right away.
6920 if (r != null) {
6921 r.conProviders.add(cpr);
6922 cpr.clients.add(r);
6923 } else {
6924 cpr.externals++;
6925 }
6926
6927 if (cpr.app != null) {
6928 updateOomAdjLocked(cpr.app);
6929 }
6930
6931 Binder.restoreCallingIdentity(origId);
6932
6933 } else {
6934 try {
6935 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07006936 resolveContentProvider(name,
6937 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006938 } catch (RemoteException ex) {
6939 }
6940 if (cpi == null) {
6941 return null;
6942 }
6943
6944 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6945 return new ContentProviderHolder(cpi,
6946 cpi.readPermission != null
6947 ? cpi.readPermission : cpi.writePermission);
6948 }
6949
6950 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6951 final boolean firstClass = cpr == null;
6952 if (firstClass) {
6953 try {
6954 ApplicationInfo ai =
6955 ActivityThread.getPackageManager().
6956 getApplicationInfo(
6957 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006958 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006959 if (ai == null) {
6960 Log.w(TAG, "No package info for content provider "
6961 + cpi.name);
6962 return null;
6963 }
6964 cpr = new ContentProviderRecord(cpi, ai);
6965 } catch (RemoteException ex) {
6966 // pm is in same process, this will never happen.
6967 }
6968 }
6969
6970 if (r != null && cpr.canRunHere(r)) {
6971 // If this is a multiprocess provider, then just return its
6972 // info and allow the caller to instantiate it. Only do
6973 // this if the provider is the same user as the caller's
6974 // process, or can run as root (so can be in any process).
6975 return cpr;
6976 }
6977
6978 if (false) {
6979 RuntimeException e = new RuntimeException("foo");
6980 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
6981 // + " pruid " + ai.uid + "): " + cpi.className, e);
6982 }
6983
6984 // This is single process, and our app is now connecting to it.
6985 // See if we are already in the process of launching this
6986 // provider.
6987 final int N = mLaunchingProviders.size();
6988 int i;
6989 for (i=0; i<N; i++) {
6990 if (mLaunchingProviders.get(i) == cpr) {
6991 break;
6992 }
6993 if (false) {
6994 final ContentProviderRecord rec =
6995 (ContentProviderRecord)mLaunchingProviders.get(i);
6996 if (rec.info.name.equals(cpr.info.name)) {
6997 cpr = rec;
6998 break;
6999 }
7000 }
7001 }
7002
7003 // If the provider is not already being launched, then get it
7004 // started.
7005 if (i >= N) {
7006 final long origId = Binder.clearCallingIdentity();
7007 ProcessRecord proc = startProcessLocked(cpi.processName,
7008 cpr.appInfo, false, 0, "content provider",
7009 new ComponentName(cpi.applicationInfo.packageName,
7010 cpi.name));
7011 if (proc == null) {
7012 Log.w(TAG, "Unable to launch app "
7013 + cpi.applicationInfo.packageName + "/"
7014 + cpi.applicationInfo.uid + " for provider "
7015 + name + ": process is bad");
7016 return null;
7017 }
7018 cpr.launchingApp = proc;
7019 mLaunchingProviders.add(cpr);
7020 Binder.restoreCallingIdentity(origId);
7021 }
7022
7023 // Make sure the provider is published (the same provider class
7024 // may be published under multiple names).
7025 if (firstClass) {
7026 mProvidersByClass.put(cpi.name, cpr);
7027 }
7028 mProvidersByName.put(name, cpr);
7029
7030 if (r != null) {
7031 r.conProviders.add(cpr);
7032 cpr.clients.add(r);
7033 } else {
7034 cpr.externals++;
7035 }
7036 }
7037 }
7038
7039 // Wait for the provider to be published...
7040 synchronized (cpr) {
7041 while (cpr.provider == null) {
7042 if (cpr.launchingApp == null) {
7043 Log.w(TAG, "Unable to launch app "
7044 + cpi.applicationInfo.packageName + "/"
7045 + cpi.applicationInfo.uid + " for provider "
7046 + name + ": launching app became null");
7047 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7048 cpi.applicationInfo.packageName,
7049 cpi.applicationInfo.uid, name);
7050 return null;
7051 }
7052 try {
7053 cpr.wait();
7054 } catch (InterruptedException ex) {
7055 }
7056 }
7057 }
7058 return cpr;
7059 }
7060
7061 public final ContentProviderHolder getContentProvider(
7062 IApplicationThread caller, String name) {
7063 if (caller == null) {
7064 String msg = "null IApplicationThread when getting content provider "
7065 + name;
7066 Log.w(TAG, msg);
7067 throw new SecurityException(msg);
7068 }
7069
7070 return getContentProviderImpl(caller, name);
7071 }
7072
7073 private ContentProviderHolder getContentProviderExternal(String name) {
7074 return getContentProviderImpl(null, name);
7075 }
7076
7077 /**
7078 * Drop a content provider from a ProcessRecord's bookkeeping
7079 * @param cpr
7080 */
7081 public void removeContentProvider(IApplicationThread caller, String name) {
7082 synchronized (this) {
7083 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7084 if(cpr == null) {
7085 //remove from mProvidersByClass
7086 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7087 return;
7088 }
7089 final ProcessRecord r = getRecordForAppLocked(caller);
7090 if (r == null) {
7091 throw new SecurityException(
7092 "Unable to find app for caller " + caller +
7093 " when removing content provider " + name);
7094 }
7095 //update content provider record entry info
7096 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7097 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7098 r.info.processName+" from process "+localCpr.appInfo.processName);
7099 if(localCpr.appInfo.processName == r.info.processName) {
7100 //should not happen. taken care of as a local provider
7101 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7102 return;
7103 } else {
7104 localCpr.clients.remove(r);
7105 r.conProviders.remove(localCpr);
7106 }
7107 updateOomAdjLocked();
7108 }
7109 }
7110
7111 private void removeContentProviderExternal(String name) {
7112 synchronized (this) {
7113 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7114 if(cpr == null) {
7115 //remove from mProvidersByClass
7116 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7117 return;
7118 }
7119
7120 //update content provider record entry info
7121 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7122 localCpr.externals--;
7123 if (localCpr.externals < 0) {
7124 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7125 }
7126 updateOomAdjLocked();
7127 }
7128 }
7129
7130 public final void publishContentProviders(IApplicationThread caller,
7131 List<ContentProviderHolder> providers) {
7132 if (providers == null) {
7133 return;
7134 }
7135
7136 synchronized(this) {
7137 final ProcessRecord r = getRecordForAppLocked(caller);
7138 if (r == null) {
7139 throw new SecurityException(
7140 "Unable to find app for caller " + caller
7141 + " (pid=" + Binder.getCallingPid()
7142 + ") when publishing content providers");
7143 }
7144
7145 final long origId = Binder.clearCallingIdentity();
7146
7147 final int N = providers.size();
7148 for (int i=0; i<N; i++) {
7149 ContentProviderHolder src = providers.get(i);
7150 if (src == null || src.info == null || src.provider == null) {
7151 continue;
7152 }
7153 ContentProviderRecord dst =
7154 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7155 if (dst != null) {
7156 mProvidersByClass.put(dst.info.name, dst);
7157 String names[] = dst.info.authority.split(";");
7158 for (int j = 0; j < names.length; j++) {
7159 mProvidersByName.put(names[j], dst);
7160 }
7161
7162 int NL = mLaunchingProviders.size();
7163 int j;
7164 for (j=0; j<NL; j++) {
7165 if (mLaunchingProviders.get(j) == dst) {
7166 mLaunchingProviders.remove(j);
7167 j--;
7168 NL--;
7169 }
7170 }
7171 synchronized (dst) {
7172 dst.provider = src.provider;
7173 dst.app = r;
7174 dst.notifyAll();
7175 }
7176 updateOomAdjLocked(r);
7177 }
7178 }
7179
7180 Binder.restoreCallingIdentity(origId);
7181 }
7182 }
7183
7184 public static final void installSystemProviders() {
7185 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7186 List providers = mSelf.generateApplicationProvidersLocked(app);
7187 mSystemThread.installSystemProviders(providers);
7188 }
7189
7190 // =========================================================
7191 // GLOBAL MANAGEMENT
7192 // =========================================================
7193
7194 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7195 ApplicationInfo info, String customProcess) {
7196 String proc = customProcess != null ? customProcess : info.processName;
7197 BatteryStatsImpl.Uid.Proc ps = null;
7198 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7199 synchronized (stats) {
7200 ps = stats.getProcessStatsLocked(info.uid, proc);
7201 }
7202 return new ProcessRecord(ps, thread, info, proc);
7203 }
7204
7205 final ProcessRecord addAppLocked(ApplicationInfo info) {
7206 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7207
7208 if (app == null) {
7209 app = newProcessRecordLocked(null, info, null);
7210 mProcessNames.put(info.processName, info.uid, app);
7211 updateLRUListLocked(app, true);
7212 }
7213
7214 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7215 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7216 app.persistent = true;
7217 app.maxAdj = CORE_SERVER_ADJ;
7218 }
7219 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7220 mPersistentStartingProcesses.add(app);
7221 startProcessLocked(app, "added application", app.processName);
7222 }
7223
7224 return app;
7225 }
7226
7227 public void unhandledBack() {
7228 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7229 "unhandledBack()");
7230
7231 synchronized(this) {
7232 int count = mHistory.size();
7233 if (Config.LOGD) Log.d(
7234 TAG, "Performing unhandledBack(): stack size = " + count);
7235 if (count > 1) {
7236 final long origId = Binder.clearCallingIdentity();
7237 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7238 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7239 Binder.restoreCallingIdentity(origId);
7240 }
7241 }
7242 }
7243
7244 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7245 String name = uri.getAuthority();
7246 ContentProviderHolder cph = getContentProviderExternal(name);
7247 ParcelFileDescriptor pfd = null;
7248 if (cph != null) {
7249 // We record the binder invoker's uid in thread-local storage before
7250 // going to the content provider to open the file. Later, in the code
7251 // that handles all permissions checks, we look for this uid and use
7252 // that rather than the Activity Manager's own uid. The effect is that
7253 // we do the check against the caller's permissions even though it looks
7254 // to the content provider like the Activity Manager itself is making
7255 // the request.
7256 sCallerIdentity.set(new Identity(
7257 Binder.getCallingPid(), Binder.getCallingUid()));
7258 try {
7259 pfd = cph.provider.openFile(uri, "r");
7260 } catch (FileNotFoundException e) {
7261 // do nothing; pfd will be returned null
7262 } finally {
7263 // Ensure that whatever happens, we clean up the identity state
7264 sCallerIdentity.remove();
7265 }
7266
7267 // We've got the fd now, so we're done with the provider.
7268 removeContentProviderExternal(name);
7269 } else {
7270 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7271 }
7272 return pfd;
7273 }
7274
7275 public void goingToSleep() {
7276 synchronized(this) {
7277 mSleeping = true;
7278 mWindowManager.setEventDispatching(false);
7279
7280 if (mResumedActivity != null) {
7281 pauseIfSleepingLocked();
7282 } else {
7283 Log.w(TAG, "goingToSleep with no resumed activity!");
7284 }
7285 }
7286 }
7287
Dianne Hackborn55280a92009-05-07 15:53:46 -07007288 public boolean shutdown(int timeout) {
7289 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7290 != PackageManager.PERMISSION_GRANTED) {
7291 throw new SecurityException("Requires permission "
7292 + android.Manifest.permission.SHUTDOWN);
7293 }
7294
7295 boolean timedout = false;
7296
7297 synchronized(this) {
7298 mShuttingDown = true;
7299 mWindowManager.setEventDispatching(false);
7300
7301 if (mResumedActivity != null) {
7302 pauseIfSleepingLocked();
7303 final long endTime = System.currentTimeMillis() + timeout;
7304 while (mResumedActivity != null || mPausingActivity != null) {
7305 long delay = endTime - System.currentTimeMillis();
7306 if (delay <= 0) {
7307 Log.w(TAG, "Activity manager shutdown timed out");
7308 timedout = true;
7309 break;
7310 }
7311 try {
7312 this.wait();
7313 } catch (InterruptedException e) {
7314 }
7315 }
7316 }
7317 }
7318
7319 mUsageStatsService.shutdown();
7320 mBatteryStatsService.shutdown();
7321
7322 return timedout;
7323 }
7324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007325 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007326 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007327 if (!mGoingToSleep.isHeld()) {
7328 mGoingToSleep.acquire();
7329 if (mLaunchingActivity.isHeld()) {
7330 mLaunchingActivity.release();
7331 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7332 }
7333 }
7334
7335 // If we are not currently pausing an activity, get the current
7336 // one to pause. If we are pausing one, we will just let that stuff
7337 // run and release the wake lock when all done.
7338 if (mPausingActivity == null) {
7339 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7340 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7341 startPausingLocked(false, true);
7342 }
7343 }
7344 }
7345
7346 public void wakingUp() {
7347 synchronized(this) {
7348 if (mGoingToSleep.isHeld()) {
7349 mGoingToSleep.release();
7350 }
7351 mWindowManager.setEventDispatching(true);
7352 mSleeping = false;
7353 resumeTopActivityLocked(null);
7354 }
7355 }
7356
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007357 public void stopAppSwitches() {
7358 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7359 != PackageManager.PERMISSION_GRANTED) {
7360 throw new SecurityException("Requires permission "
7361 + android.Manifest.permission.STOP_APP_SWITCHES);
7362 }
7363
7364 synchronized(this) {
7365 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7366 + APP_SWITCH_DELAY_TIME;
7367 mDidAppSwitch = false;
7368 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7369 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7370 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7371 }
7372 }
7373
7374 public void resumeAppSwitches() {
7375 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7376 != PackageManager.PERMISSION_GRANTED) {
7377 throw new SecurityException("Requires permission "
7378 + android.Manifest.permission.STOP_APP_SWITCHES);
7379 }
7380
7381 synchronized(this) {
7382 // Note that we don't execute any pending app switches... we will
7383 // let those wait until either the timeout, or the next start
7384 // activity request.
7385 mAppSwitchesAllowedTime = 0;
7386 }
7387 }
7388
7389 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7390 String name) {
7391 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7392 return true;
7393 }
7394
7395 final int perm = checkComponentPermission(
7396 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7397 callingUid, -1);
7398 if (perm == PackageManager.PERMISSION_GRANTED) {
7399 return true;
7400 }
7401
7402 Log.w(TAG, name + " request from " + callingUid + " stopped");
7403 return false;
7404 }
7405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007406 public void setDebugApp(String packageName, boolean waitForDebugger,
7407 boolean persistent) {
7408 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7409 "setDebugApp()");
7410
7411 // Note that this is not really thread safe if there are multiple
7412 // callers into it at the same time, but that's not a situation we
7413 // care about.
7414 if (persistent) {
7415 final ContentResolver resolver = mContext.getContentResolver();
7416 Settings.System.putString(
7417 resolver, Settings.System.DEBUG_APP,
7418 packageName);
7419 Settings.System.putInt(
7420 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7421 waitForDebugger ? 1 : 0);
7422 }
7423
7424 synchronized (this) {
7425 if (!persistent) {
7426 mOrigDebugApp = mDebugApp;
7427 mOrigWaitForDebugger = mWaitForDebugger;
7428 }
7429 mDebugApp = packageName;
7430 mWaitForDebugger = waitForDebugger;
7431 mDebugTransient = !persistent;
7432 if (packageName != null) {
7433 final long origId = Binder.clearCallingIdentity();
7434 uninstallPackageLocked(packageName, -1, false);
7435 Binder.restoreCallingIdentity(origId);
7436 }
7437 }
7438 }
7439
7440 public void setAlwaysFinish(boolean enabled) {
7441 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7442 "setAlwaysFinish()");
7443
7444 Settings.System.putInt(
7445 mContext.getContentResolver(),
7446 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7447
7448 synchronized (this) {
7449 mAlwaysFinishActivities = enabled;
7450 }
7451 }
7452
7453 public void setActivityWatcher(IActivityWatcher watcher) {
7454 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7455 "setActivityWatcher()");
7456 synchronized (this) {
7457 mWatcher = watcher;
7458 }
7459 }
7460
7461 public final void enterSafeMode() {
7462 synchronized(this) {
7463 // It only makes sense to do this before the system is ready
7464 // and started launching other packages.
7465 if (!mSystemReady) {
7466 try {
7467 ActivityThread.getPackageManager().enterSafeMode();
7468 } catch (RemoteException e) {
7469 }
7470
7471 View v = LayoutInflater.from(mContext).inflate(
7472 com.android.internal.R.layout.safe_mode, null);
7473 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7474 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7475 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7476 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7477 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7478 lp.format = v.getBackground().getOpacity();
7479 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7480 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7481 ((WindowManager)mContext.getSystemService(
7482 Context.WINDOW_SERVICE)).addView(v, lp);
7483 }
7484 }
7485 }
7486
7487 public void noteWakeupAlarm(IIntentSender sender) {
7488 if (!(sender instanceof PendingIntentRecord)) {
7489 return;
7490 }
7491 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7492 synchronized (stats) {
7493 if (mBatteryStatsService.isOnBattery()) {
7494 mBatteryStatsService.enforceCallingPermission();
7495 PendingIntentRecord rec = (PendingIntentRecord)sender;
7496 int MY_UID = Binder.getCallingUid();
7497 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7498 BatteryStatsImpl.Uid.Pkg pkg =
7499 stats.getPackageStatsLocked(uid, rec.key.packageName);
7500 pkg.incWakeupsLocked();
7501 }
7502 }
7503 }
7504
7505 public boolean killPidsForMemory(int[] pids) {
7506 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7507 throw new SecurityException("killPidsForMemory only available to the system");
7508 }
7509
7510 // XXX Note: don't acquire main activity lock here, because the window
7511 // manager calls in with its locks held.
7512
7513 boolean killed = false;
7514 synchronized (mPidsSelfLocked) {
7515 int[] types = new int[pids.length];
7516 int worstType = 0;
7517 for (int i=0; i<pids.length; i++) {
7518 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7519 if (proc != null) {
7520 int type = proc.setAdj;
7521 types[i] = type;
7522 if (type > worstType) {
7523 worstType = type;
7524 }
7525 }
7526 }
7527
7528 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7529 // then constrain it so we will kill all hidden procs.
7530 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7531 worstType = HIDDEN_APP_MIN_ADJ;
7532 }
7533 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7534 for (int i=0; i<pids.length; i++) {
7535 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7536 if (proc == null) {
7537 continue;
7538 }
7539 int adj = proc.setAdj;
7540 if (adj >= worstType) {
7541 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7542 + adj + ")");
7543 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7544 proc.processName, adj);
7545 killed = true;
7546 Process.killProcess(pids[i]);
7547 }
7548 }
7549 }
7550 return killed;
7551 }
7552
7553 public void reportPss(IApplicationThread caller, int pss) {
7554 Watchdog.PssRequestor req;
7555 String name;
7556 ProcessRecord callerApp;
7557 synchronized (this) {
7558 if (caller == null) {
7559 return;
7560 }
7561 callerApp = getRecordForAppLocked(caller);
7562 if (callerApp == null) {
7563 return;
7564 }
7565 callerApp.lastPss = pss;
7566 req = callerApp;
7567 name = callerApp.processName;
7568 }
7569 Watchdog.getInstance().reportPss(req, name, pss);
7570 if (!callerApp.persistent) {
7571 removeRequestedPss(callerApp);
7572 }
7573 }
7574
7575 public void requestPss(Runnable completeCallback) {
7576 ArrayList<ProcessRecord> procs;
7577 synchronized (this) {
7578 mRequestPssCallback = completeCallback;
7579 mRequestPssList.clear();
7580 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7581 ProcessRecord proc = mLRUProcesses.get(i);
7582 if (!proc.persistent) {
7583 mRequestPssList.add(proc);
7584 }
7585 }
7586 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7587 }
7588
7589 int oldPri = Process.getThreadPriority(Process.myTid());
7590 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7591 for (int i=procs.size()-1; i>=0; i--) {
7592 ProcessRecord proc = procs.get(i);
7593 proc.lastPss = 0;
7594 proc.requestPss();
7595 }
7596 Process.setThreadPriority(oldPri);
7597 }
7598
7599 void removeRequestedPss(ProcessRecord proc) {
7600 Runnable callback = null;
7601 synchronized (this) {
7602 if (mRequestPssList.remove(proc)) {
7603 if (mRequestPssList.size() == 0) {
7604 callback = mRequestPssCallback;
7605 mRequestPssCallback = null;
7606 }
7607 }
7608 }
7609
7610 if (callback != null) {
7611 callback.run();
7612 }
7613 }
7614
7615 public void collectPss(Watchdog.PssStats stats) {
7616 stats.mEmptyPss = 0;
7617 stats.mEmptyCount = 0;
7618 stats.mBackgroundPss = 0;
7619 stats.mBackgroundCount = 0;
7620 stats.mServicePss = 0;
7621 stats.mServiceCount = 0;
7622 stats.mVisiblePss = 0;
7623 stats.mVisibleCount = 0;
7624 stats.mForegroundPss = 0;
7625 stats.mForegroundCount = 0;
7626 stats.mNoPssCount = 0;
7627 synchronized (this) {
7628 int i;
7629 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7630 ? mProcDeaths.length : stats.mProcDeaths.length;
7631 int aggr = 0;
7632 for (i=0; i<NPD; i++) {
7633 aggr += mProcDeaths[i];
7634 stats.mProcDeaths[i] = aggr;
7635 }
7636 while (i<stats.mProcDeaths.length) {
7637 stats.mProcDeaths[i] = 0;
7638 i++;
7639 }
7640
7641 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7642 ProcessRecord proc = mLRUProcesses.get(i);
7643 if (proc.persistent) {
7644 continue;
7645 }
7646 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7647 if (proc.lastPss == 0) {
7648 stats.mNoPssCount++;
7649 continue;
7650 }
7651 if (proc.setAdj == EMPTY_APP_ADJ) {
7652 stats.mEmptyPss += proc.lastPss;
7653 stats.mEmptyCount++;
7654 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7655 stats.mEmptyPss += proc.lastPss;
7656 stats.mEmptyCount++;
7657 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7658 stats.mBackgroundPss += proc.lastPss;
7659 stats.mBackgroundCount++;
7660 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7661 stats.mVisiblePss += proc.lastPss;
7662 stats.mVisibleCount++;
7663 } else {
7664 stats.mForegroundPss += proc.lastPss;
7665 stats.mForegroundCount++;
7666 }
7667 }
7668 }
7669 }
7670
7671 public final void startRunning(String pkg, String cls, String action,
7672 String data) {
7673 synchronized(this) {
7674 if (mStartRunning) {
7675 return;
7676 }
7677 mStartRunning = true;
7678 mTopComponent = pkg != null && cls != null
7679 ? new ComponentName(pkg, cls) : null;
7680 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7681 mTopData = data;
7682 if (!mSystemReady) {
7683 return;
7684 }
7685 }
7686
7687 systemReady();
7688 }
7689
7690 private void retrieveSettings() {
7691 final ContentResolver resolver = mContext.getContentResolver();
7692 String debugApp = Settings.System.getString(
7693 resolver, Settings.System.DEBUG_APP);
7694 boolean waitForDebugger = Settings.System.getInt(
7695 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7696 boolean alwaysFinishActivities = Settings.System.getInt(
7697 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7698
7699 Configuration configuration = new Configuration();
7700 Settings.System.getConfiguration(resolver, configuration);
7701
7702 synchronized (this) {
7703 mDebugApp = mOrigDebugApp = debugApp;
7704 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7705 mAlwaysFinishActivities = alwaysFinishActivities;
7706 // This happens before any activities are started, so we can
7707 // change mConfiguration in-place.
7708 mConfiguration.updateFrom(configuration);
7709 }
7710 }
7711
7712 public boolean testIsSystemReady() {
7713 // no need to synchronize(this) just to read & return the value
7714 return mSystemReady;
7715 }
7716
7717 public void systemReady() {
7718 // In the simulator, startRunning will never have been called, which
7719 // normally sets a few crucial variables. Do it here instead.
7720 if (!Process.supportsProcesses()) {
7721 mStartRunning = true;
7722 mTopAction = Intent.ACTION_MAIN;
7723 }
7724
7725 synchronized(this) {
7726 if (mSystemReady) {
7727 return;
7728 }
7729 mSystemReady = true;
7730 if (!mStartRunning) {
7731 return;
7732 }
7733 }
7734
7735 if (Config.LOGD) Log.d(TAG, "Start running!");
7736 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7737 SystemClock.uptimeMillis());
7738
7739 synchronized(this) {
7740 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7741 ResolveInfo ri = mContext.getPackageManager()
7742 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007743 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007744 CharSequence errorMsg = null;
7745 if (ri != null) {
7746 ActivityInfo ai = ri.activityInfo;
7747 ApplicationInfo app = ai.applicationInfo;
7748 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7749 mTopAction = Intent.ACTION_FACTORY_TEST;
7750 mTopData = null;
7751 mTopComponent = new ComponentName(app.packageName,
7752 ai.name);
7753 } else {
7754 errorMsg = mContext.getResources().getText(
7755 com.android.internal.R.string.factorytest_not_system);
7756 }
7757 } else {
7758 errorMsg = mContext.getResources().getText(
7759 com.android.internal.R.string.factorytest_no_action);
7760 }
7761 if (errorMsg != null) {
7762 mTopAction = null;
7763 mTopData = null;
7764 mTopComponent = null;
7765 Message msg = Message.obtain();
7766 msg.what = SHOW_FACTORY_ERROR_MSG;
7767 msg.getData().putCharSequence("msg", errorMsg);
7768 mHandler.sendMessage(msg);
7769 }
7770 }
7771 }
7772
7773 retrieveSettings();
7774
7775 synchronized (this) {
7776 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7777 try {
7778 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007779 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007780 if (apps != null) {
7781 int N = apps.size();
7782 int i;
7783 for (i=0; i<N; i++) {
7784 ApplicationInfo info
7785 = (ApplicationInfo)apps.get(i);
7786 if (info != null &&
7787 !info.packageName.equals("android")) {
7788 addAppLocked(info);
7789 }
7790 }
7791 }
7792 } catch (RemoteException ex) {
7793 // pm is in same process, this will never happen.
7794 }
7795 }
7796
7797 try {
7798 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7799 Message msg = Message.obtain();
7800 msg.what = SHOW_UID_ERROR_MSG;
7801 mHandler.sendMessage(msg);
7802 }
7803 } catch (RemoteException e) {
7804 }
7805
7806 // Start up initial activity.
7807 mBooting = true;
7808 resumeTopActivityLocked(null);
7809 }
7810 }
7811
7812 boolean makeAppCrashingLocked(ProcessRecord app,
7813 String tag, String shortMsg, String longMsg, byte[] crashData) {
7814 app.crashing = true;
7815 app.crashingReport = generateProcessError(app,
7816 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7817 startAppProblemLocked(app);
7818 app.stopFreezingAllLocked();
7819 return handleAppCrashLocked(app);
7820 }
7821
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007822 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7823 IPackageManager pm = ActivityThread.getPackageManager();
7824 try {
7825 // was an installer package name specified when this app was
7826 // installed?
7827 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7828 if (installerPackageName == null) {
7829 return null;
7830 }
7831
7832 // is there an Activity in this package that handles ACTION_APP_ERROR?
7833 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
7834 ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
7835 if (info == null || info.activityInfo == null) {
7836 return null;
7837 }
7838
7839 return new ComponentName(installerPackageName, info.activityInfo.name);
7840 } catch (RemoteException e) {
7841 // will return null and no error report will be delivered
7842 }
7843 return null;
7844 }
7845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007846 void makeAppNotRespondingLocked(ProcessRecord app,
7847 String tag, String shortMsg, String longMsg, byte[] crashData) {
7848 app.notResponding = true;
7849 app.notRespondingReport = generateProcessError(app,
7850 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7851 crashData);
7852 startAppProblemLocked(app);
7853 app.stopFreezingAllLocked();
7854 }
7855
7856 /**
7857 * Generate a process error record, suitable for attachment to a ProcessRecord.
7858 *
7859 * @param app The ProcessRecord in which the error occurred.
7860 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7861 * ActivityManager.AppErrorStateInfo
7862 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7863 * @param shortMsg Short message describing the crash.
7864 * @param longMsg Long message describing the crash.
7865 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7866 *
7867 * @return Returns a fully-formed AppErrorStateInfo record.
7868 */
7869 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7870 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7871 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7872
7873 report.condition = condition;
7874 report.processName = app.processName;
7875 report.pid = app.pid;
7876 report.uid = app.info.uid;
7877 report.tag = tag;
7878 report.shortMsg = shortMsg;
7879 report.longMsg = longMsg;
7880 report.crashData = crashData;
7881
7882 return report;
7883 }
7884
7885 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7886 boolean crashed) {
7887 synchronized (this) {
7888 app.crashing = false;
7889 app.crashingReport = null;
7890 app.notResponding = false;
7891 app.notRespondingReport = null;
7892 if (app.anrDialog == fromDialog) {
7893 app.anrDialog = null;
7894 }
7895 if (app.waitDialog == fromDialog) {
7896 app.waitDialog = null;
7897 }
7898 if (app.pid > 0 && app.pid != MY_PID) {
7899 if (crashed) {
7900 handleAppCrashLocked(app);
7901 }
7902 Log.i(ActivityManagerService.TAG, "Killing process "
7903 + app.processName
7904 + " (pid=" + app.pid + ") at user's request");
7905 Process.killProcess(app.pid);
7906 }
7907
7908 }
7909 }
7910
7911 boolean handleAppCrashLocked(ProcessRecord app) {
7912 long now = SystemClock.uptimeMillis();
7913
7914 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7915 app.info.uid);
7916 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7917 // This process loses!
7918 Log.w(TAG, "Process " + app.info.processName
7919 + " has crashed too many times: killing!");
7920 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7921 app.info.processName, app.info.uid);
7922 killServicesLocked(app, false);
7923 for (int i=mHistory.size()-1; i>=0; i--) {
7924 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7925 if (r.app == app) {
7926 if (Config.LOGD) Log.d(
7927 TAG, " Force finishing activity "
7928 + r.intent.getComponent().flattenToShortString());
7929 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
7930 }
7931 }
7932 if (!app.persistent) {
7933 // We don't want to start this process again until the user
7934 // explicitly does so... but for persistent process, we really
7935 // need to keep it running. If a persistent process is actually
7936 // repeatedly crashing, then badness for everyone.
7937 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
7938 app.info.processName);
7939 mBadProcesses.put(app.info.processName, app.info.uid, now);
7940 app.bad = true;
7941 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
7942 app.removed = true;
7943 removeProcessLocked(app, false);
7944 return false;
7945 }
7946 }
7947
7948 // Bump up the crash count of any services currently running in the proc.
7949 if (app.services.size() != 0) {
7950 // Any services running in the application need to be placed
7951 // back in the pending list.
7952 Iterator it = app.services.iterator();
7953 while (it.hasNext()) {
7954 ServiceRecord sr = (ServiceRecord)it.next();
7955 sr.crashCount++;
7956 }
7957 }
7958
7959 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
7960 return true;
7961 }
7962
7963 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007964 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007965 skipCurrentReceiverLocked(app);
7966 }
7967
7968 void skipCurrentReceiverLocked(ProcessRecord app) {
7969 boolean reschedule = false;
7970 BroadcastRecord r = app.curReceiver;
7971 if (r != null) {
7972 // The current broadcast is waiting for this app's receiver
7973 // to be finished. Looks like that's not going to happen, so
7974 // let the broadcast continue.
7975 logBroadcastReceiverDiscard(r);
7976 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
7977 r.resultExtras, r.resultAbort, true);
7978 reschedule = true;
7979 }
7980 r = mPendingBroadcast;
7981 if (r != null && r.curApp == app) {
7982 if (DEBUG_BROADCAST) Log.v(TAG,
7983 "skip & discard pending app " + r);
7984 logBroadcastReceiverDiscard(r);
7985 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
7986 r.resultExtras, r.resultAbort, true);
7987 reschedule = true;
7988 }
7989 if (reschedule) {
7990 scheduleBroadcastsLocked();
7991 }
7992 }
7993
7994 public int handleApplicationError(IBinder app, int flags,
7995 String tag, String shortMsg, String longMsg, byte[] crashData) {
7996 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007997 ProcessRecord r = null;
7998 synchronized (this) {
7999 if (app != null) {
8000 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8001 final int NA = apps.size();
8002 for (int ia=0; ia<NA; ia++) {
8003 ProcessRecord p = apps.valueAt(ia);
8004 if (p.thread != null && p.thread.asBinder() == app) {
8005 r = p;
8006 break;
8007 }
8008 }
8009 }
8010 }
8011
8012 if (r != null) {
8013 // The application has crashed. Send the SIGQUIT to the process so
8014 // that it can dump its state.
8015 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8016 //Log.i(TAG, "Current system threads:");
8017 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8018 }
8019
8020 if (mWatcher != null) {
8021 try {
8022 String name = r != null ? r.processName : null;
8023 int pid = r != null ? r.pid : Binder.getCallingPid();
8024 if (!mWatcher.appCrashed(name, pid,
8025 shortMsg, longMsg, crashData)) {
8026 Log.w(TAG, "Force-killing crashed app " + name
8027 + " at watcher's request");
8028 Process.killProcess(pid);
8029 return 0;
8030 }
8031 } catch (RemoteException e) {
8032 mWatcher = null;
8033 }
8034 }
8035
8036 final long origId = Binder.clearCallingIdentity();
8037
8038 // If this process is running instrumentation, finish it.
8039 if (r != null && r.instrumentationClass != null) {
8040 Log.w(TAG, "Error in app " + r.processName
8041 + " running instrumentation " + r.instrumentationClass + ":");
8042 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8043 if (longMsg != null) Log.w(TAG, " " + longMsg);
8044 Bundle info = new Bundle();
8045 info.putString("shortMsg", shortMsg);
8046 info.putString("longMsg", longMsg);
8047 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8048 Binder.restoreCallingIdentity(origId);
8049 return 0;
8050 }
8051
8052 if (r != null) {
8053 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8054 return 0;
8055 }
8056 } else {
8057 Log.w(TAG, "Some application object " + app + " tag " + tag
8058 + " has crashed, but I don't know who it is.");
8059 Log.w(TAG, "ShortMsg:" + shortMsg);
8060 Log.w(TAG, "LongMsg:" + longMsg);
8061 Binder.restoreCallingIdentity(origId);
8062 return 0;
8063 }
8064
8065 Message msg = Message.obtain();
8066 msg.what = SHOW_ERROR_MSG;
8067 HashMap data = new HashMap();
8068 data.put("result", result);
8069 data.put("app", r);
8070 data.put("flags", flags);
8071 data.put("shortMsg", shortMsg);
8072 data.put("longMsg", longMsg);
8073 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8074 // For system processes, submit crash data to the server.
8075 data.put("crashData", crashData);
8076 }
8077 msg.obj = data;
8078 mHandler.sendMessage(msg);
8079
8080 Binder.restoreCallingIdentity(origId);
8081 }
8082
8083 int res = result.get();
8084
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008085 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008086 synchronized (this) {
8087 if (r != null) {
8088 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8089 SystemClock.uptimeMillis());
8090 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008091 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8092 appErrorIntent = createAppErrorIntentLocked(r);
8093 res = AppErrorDialog.FORCE_QUIT;
8094 }
8095 }
8096
8097 if (appErrorIntent != null) {
8098 try {
8099 mContext.startActivity(appErrorIntent);
8100 } catch (ActivityNotFoundException e) {
8101 Log.w(TAG, "bug report receiver dissappeared", e);
8102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008103 }
8104
8105 return res;
8106 }
8107
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008108 Intent createAppErrorIntentLocked(ProcessRecord r) {
8109 ApplicationErrorReport report = createAppErrorReportLocked(r);
8110 if (report == null) {
8111 return null;
8112 }
8113 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8114 result.setComponent(r.errorReportReceiver);
8115 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8116 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8117 return result;
8118 }
8119
8120 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8121 if (r.errorReportReceiver == null) {
8122 return null;
8123 }
8124
8125 if (!r.crashing && !r.notResponding) {
8126 return null;
8127 }
8128
8129 try {
8130 ApplicationErrorReport report = new ApplicationErrorReport();
8131 report.packageName = r.info.packageName;
8132 report.installerPackageName = r.errorReportReceiver.getPackageName();
8133 report.processName = r.processName;
8134
8135 if (r.crashing) {
8136 report.type = ApplicationErrorReport.TYPE_CRASH;
8137 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8138
8139 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8140 r.crashingReport.crashData);
8141 DataInputStream dataStream = new DataInputStream(byteStream);
8142 CrashData crashData = new CrashData(dataStream);
8143 ThrowableData throwData = crashData.getThrowableData();
8144
8145 report.time = crashData.getTime();
8146 report.crashInfo.stackTrace = throwData.toString();
8147
8148 // extract the source of the exception, useful for report
8149 // clustering
8150 while (throwData.getCause() != null) {
8151 throwData = throwData.getCause();
8152 }
8153 StackTraceElementData trace = throwData.getStackTrace()[0];
8154 report.crashInfo.exceptionClassName = throwData.getType();
8155 report.crashInfo.throwFileName = trace.getFileName();
8156 report.crashInfo.throwClassName = trace.getClassName();
8157 report.crashInfo.throwMethodName = trace.getMethodName();
8158 } else if (r.notResponding) {
8159 report.type = ApplicationErrorReport.TYPE_ANR;
8160 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8161
8162 report.anrInfo.activity = r.notRespondingReport.tag;
8163 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8164 report.anrInfo.info = r.notRespondingReport.longMsg;
8165 }
8166
8167 return report;
8168 } catch (IOException e) {
8169 // we don't send it
8170 }
8171
8172 return null;
8173 }
8174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008175 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8176 // assume our apps are happy - lazy create the list
8177 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8178
8179 synchronized (this) {
8180
8181 // iterate across all processes
8182 final int N = mLRUProcesses.size();
8183 for (int i = 0; i < N; i++) {
8184 ProcessRecord app = mLRUProcesses.get(i);
8185 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8186 // This one's in trouble, so we'll generate a report for it
8187 // crashes are higher priority (in case there's a crash *and* an anr)
8188 ActivityManager.ProcessErrorStateInfo report = null;
8189 if (app.crashing) {
8190 report = app.crashingReport;
8191 } else if (app.notResponding) {
8192 report = app.notRespondingReport;
8193 }
8194
8195 if (report != null) {
8196 if (errList == null) {
8197 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8198 }
8199 errList.add(report);
8200 } else {
8201 Log.w(TAG, "Missing app error report, app = " + app.processName +
8202 " crashing = " + app.crashing +
8203 " notResponding = " + app.notResponding);
8204 }
8205 }
8206 }
8207 }
8208
8209 return errList;
8210 }
8211
8212 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8213 // Lazy instantiation of list
8214 List<ActivityManager.RunningAppProcessInfo> runList = null;
8215 synchronized (this) {
8216 // Iterate across all processes
8217 final int N = mLRUProcesses.size();
8218 for (int i = 0; i < N; i++) {
8219 ProcessRecord app = mLRUProcesses.get(i);
8220 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8221 // Generate process state info for running application
8222 ActivityManager.RunningAppProcessInfo currApp =
8223 new ActivityManager.RunningAppProcessInfo(app.processName,
8224 app.pid, app.getPackageList());
8225 int adj = app.curAdj;
8226 if (adj >= CONTENT_PROVIDER_ADJ) {
8227 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8228 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8229 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008230 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8231 } else if (adj >= HOME_APP_ADJ) {
8232 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8233 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008234 } else if (adj >= SECONDARY_SERVER_ADJ) {
8235 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8236 } else if (adj >= VISIBLE_APP_ADJ) {
8237 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8238 } else {
8239 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8240 }
8241 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8242 // + " lru=" + currApp.lru);
8243 if (runList == null) {
8244 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8245 }
8246 runList.add(currApp);
8247 }
8248 }
8249 }
8250 return runList;
8251 }
8252
8253 @Override
8254 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8255 synchronized (this) {
8256 if (checkCallingPermission(android.Manifest.permission.DUMP)
8257 != PackageManager.PERMISSION_GRANTED) {
8258 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8259 + Binder.getCallingPid()
8260 + ", uid=" + Binder.getCallingUid()
8261 + " without permission "
8262 + android.Manifest.permission.DUMP);
8263 return;
8264 }
8265 if (args.length != 0 && "service".equals(args[0])) {
8266 dumpService(fd, pw, args);
8267 return;
8268 }
8269 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008270 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008271 pw.println(" ");
8272 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008273 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008274 if (mWaitingVisibleActivities.size() > 0) {
8275 pw.println(" ");
8276 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008277 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008278 }
8279 if (mStoppingActivities.size() > 0) {
8280 pw.println(" ");
8281 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008282 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008283 }
8284 if (mFinishingActivities.size() > 0) {
8285 pw.println(" ");
8286 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008287 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008288 }
8289
8290 pw.println(" ");
8291 pw.println(" mPausingActivity: " + mPausingActivity);
8292 pw.println(" mResumedActivity: " + mResumedActivity);
8293 pw.println(" mFocusedActivity: " + mFocusedActivity);
8294 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8295
8296 if (mRecentTasks.size() > 0) {
8297 pw.println(" ");
8298 pw.println("Recent tasks in Current Activity Manager State:");
8299
8300 final int N = mRecentTasks.size();
8301 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008302 TaskRecord tr = mRecentTasks.get(i);
8303 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8304 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008305 mRecentTasks.get(i).dump(pw, " ");
8306 }
8307 }
8308
8309 pw.println(" ");
8310 pw.println(" mCurTask: " + mCurTask);
8311
8312 pw.println(" ");
8313 pw.println("Processes in Current Activity Manager State:");
8314
8315 boolean needSep = false;
8316 int numPers = 0;
8317
8318 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8319 final int NA = procs.size();
8320 for (int ia=0; ia<NA; ia++) {
8321 if (!needSep) {
8322 pw.println(" All known processes:");
8323 needSep = true;
8324 }
8325 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008326 pw.print(r.persistent ? " *PERS*" : " *APP*");
8327 pw.print(" UID "); pw.print(procs.keyAt(ia));
8328 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008329 r.dump(pw, " ");
8330 if (r.persistent) {
8331 numPers++;
8332 }
8333 }
8334 }
8335
8336 if (mLRUProcesses.size() > 0) {
8337 if (needSep) pw.println(" ");
8338 needSep = true;
8339 pw.println(" Running processes (most recent first):");
8340 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008341 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008342 needSep = true;
8343 }
8344
8345 synchronized (mPidsSelfLocked) {
8346 if (mPidsSelfLocked.size() > 0) {
8347 if (needSep) pw.println(" ");
8348 needSep = true;
8349 pw.println(" PID mappings:");
8350 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008351 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8352 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008353 }
8354 }
8355 }
8356
8357 if (mForegroundProcesses.size() > 0) {
8358 if (needSep) pw.println(" ");
8359 needSep = true;
8360 pw.println(" Foreground Processes:");
8361 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008362 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8363 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008364 }
8365 }
8366
8367 if (mPersistentStartingProcesses.size() > 0) {
8368 if (needSep) pw.println(" ");
8369 needSep = true;
8370 pw.println(" Persisent processes that are starting:");
8371 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008372 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008373 }
8374
8375 if (mStartingProcesses.size() > 0) {
8376 if (needSep) pw.println(" ");
8377 needSep = true;
8378 pw.println(" Processes that are starting:");
8379 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008380 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008381 }
8382
8383 if (mRemovedProcesses.size() > 0) {
8384 if (needSep) pw.println(" ");
8385 needSep = true;
8386 pw.println(" Processes that are being removed:");
8387 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008388 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008389 }
8390
8391 if (mProcessesOnHold.size() > 0) {
8392 if (needSep) pw.println(" ");
8393 needSep = true;
8394 pw.println(" Processes that are on old until the system is ready:");
8395 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008396 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008397 }
8398
8399 if (mProcessCrashTimes.getMap().size() > 0) {
8400 if (needSep) pw.println(" ");
8401 needSep = true;
8402 pw.println(" Time since processes crashed:");
8403 long now = SystemClock.uptimeMillis();
8404 for (Map.Entry<String, SparseArray<Long>> procs
8405 : mProcessCrashTimes.getMap().entrySet()) {
8406 SparseArray<Long> uids = procs.getValue();
8407 final int N = uids.size();
8408 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008409 pw.print(" Process "); pw.print(procs.getKey());
8410 pw.print(" uid "); pw.print(uids.keyAt(i));
8411 pw.print(": last crashed ");
8412 pw.print((now-uids.valueAt(i)));
8413 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008414 }
8415 }
8416 }
8417
8418 if (mBadProcesses.getMap().size() > 0) {
8419 if (needSep) pw.println(" ");
8420 needSep = true;
8421 pw.println(" Bad processes:");
8422 for (Map.Entry<String, SparseArray<Long>> procs
8423 : mBadProcesses.getMap().entrySet()) {
8424 SparseArray<Long> uids = procs.getValue();
8425 final int N = uids.size();
8426 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008427 pw.print(" Bad process "); pw.print(procs.getKey());
8428 pw.print(" uid "); pw.print(uids.keyAt(i));
8429 pw.print(": crashed at time ");
8430 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008431 }
8432 }
8433 }
8434
8435 pw.println(" ");
8436 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008437 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008438 pw.println(" mConfiguration: " + mConfiguration);
8439 pw.println(" mStartRunning=" + mStartRunning
8440 + " mSystemReady=" + mSystemReady
8441 + " mBooting=" + mBooting
8442 + " mBooted=" + mBooted
8443 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008444 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008445 pw.println(" mGoingToSleep=" + mGoingToSleep);
8446 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8447 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8448 + " mDebugTransient=" + mDebugTransient
8449 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8450 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8451 + " mWatcher=" + mWatcher);
8452 }
8453 }
8454
8455 /**
8456 * There are three ways to call this:
8457 * - no service specified: dump all the services
8458 * - a flattened component name that matched an existing service was specified as the
8459 * first arg: dump that one service
8460 * - the first arg isn't the flattened component name of an existing service:
8461 * dump all services whose component contains the first arg as a substring
8462 */
8463 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8464 String[] newArgs;
8465 String componentNameString;
8466 ServiceRecord r;
8467 if (args.length == 1) {
8468 componentNameString = null;
8469 newArgs = EMPTY_STRING_ARRAY;
8470 r = null;
8471 } else {
8472 componentNameString = args[1];
8473 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8474 r = componentName != null ? mServices.get(componentName) : null;
8475 newArgs = new String[args.length - 2];
8476 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8477 }
8478
8479 if (r != null) {
8480 dumpService(fd, pw, r, newArgs);
8481 } else {
8482 for (ServiceRecord r1 : mServices.values()) {
8483 if (componentNameString == null
8484 || r1.name.flattenToString().contains(componentNameString)) {
8485 dumpService(fd, pw, r1, newArgs);
8486 }
8487 }
8488 }
8489 }
8490
8491 /**
8492 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8493 * there is a thread associated with the service.
8494 */
8495 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8496 pw.println(" Service " + r.name.flattenToString());
8497 if (r.app != null && r.app.thread != null) {
8498 try {
8499 // flush anything that is already in the PrintWriter since the thread is going
8500 // to write to the file descriptor directly
8501 pw.flush();
8502 r.app.thread.dumpService(fd, r, args);
8503 pw.print("\n");
8504 } catch (RemoteException e) {
8505 pw.println("got a RemoteException while dumping the service");
8506 }
8507 }
8508 }
8509
8510 void dumpBroadcasts(PrintWriter pw) {
8511 synchronized (this) {
8512 if (checkCallingPermission(android.Manifest.permission.DUMP)
8513 != PackageManager.PERMISSION_GRANTED) {
8514 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8515 + Binder.getCallingPid()
8516 + ", uid=" + Binder.getCallingUid()
8517 + " without permission "
8518 + android.Manifest.permission.DUMP);
8519 return;
8520 }
8521 pw.println("Broadcasts in Current Activity Manager State:");
8522
8523 if (mRegisteredReceivers.size() > 0) {
8524 pw.println(" ");
8525 pw.println(" Registered Receivers:");
8526 Iterator it = mRegisteredReceivers.values().iterator();
8527 while (it.hasNext()) {
8528 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008529 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008530 r.dump(pw, " ");
8531 }
8532 }
8533
8534 pw.println(" ");
8535 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008536 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008537
8538 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8539 || mPendingBroadcast != null) {
8540 if (mParallelBroadcasts.size() > 0) {
8541 pw.println(" ");
8542 pw.println(" Active broadcasts:");
8543 }
8544 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8545 pw.println(" Broadcast #" + i + ":");
8546 mParallelBroadcasts.get(i).dump(pw, " ");
8547 }
8548 if (mOrderedBroadcasts.size() > 0) {
8549 pw.println(" ");
8550 pw.println(" Active serialized broadcasts:");
8551 }
8552 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8553 pw.println(" Serialized Broadcast #" + i + ":");
8554 mOrderedBroadcasts.get(i).dump(pw, " ");
8555 }
8556 pw.println(" ");
8557 pw.println(" Pending broadcast:");
8558 if (mPendingBroadcast != null) {
8559 mPendingBroadcast.dump(pw, " ");
8560 } else {
8561 pw.println(" (null)");
8562 }
8563 }
8564
8565 pw.println(" ");
8566 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8567 if (mStickyBroadcasts != null) {
8568 pw.println(" ");
8569 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008570 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008571 for (Map.Entry<String, ArrayList<Intent>> ent
8572 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008573 pw.print(" * Sticky action "); pw.print(ent.getKey());
8574 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008575 ArrayList<Intent> intents = ent.getValue();
8576 final int N = intents.size();
8577 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008578 sb.setLength(0);
8579 sb.append(" Intent: ");
8580 intents.get(i).toShortString(sb, true, false);
8581 pw.println(sb.toString());
8582 Bundle bundle = intents.get(i).getExtras();
8583 if (bundle != null) {
8584 pw.print(" ");
8585 pw.println(bundle.toString());
8586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008587 }
8588 }
8589 }
8590
8591 pw.println(" ");
8592 pw.println(" mHandler:");
8593 mHandler.dump(new PrintWriterPrinter(pw), " ");
8594 }
8595 }
8596
8597 void dumpServices(PrintWriter pw) {
8598 synchronized (this) {
8599 if (checkCallingPermission(android.Manifest.permission.DUMP)
8600 != PackageManager.PERMISSION_GRANTED) {
8601 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8602 + Binder.getCallingPid()
8603 + ", uid=" + Binder.getCallingUid()
8604 + " without permission "
8605 + android.Manifest.permission.DUMP);
8606 return;
8607 }
8608 pw.println("Services in Current Activity Manager State:");
8609
8610 boolean needSep = false;
8611
8612 if (mServices.size() > 0) {
8613 pw.println(" Active services:");
8614 Iterator<ServiceRecord> it = mServices.values().iterator();
8615 while (it.hasNext()) {
8616 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008617 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008618 r.dump(pw, " ");
8619 }
8620 needSep = true;
8621 }
8622
8623 if (mPendingServices.size() > 0) {
8624 if (needSep) pw.println(" ");
8625 pw.println(" Pending services:");
8626 for (int i=0; i<mPendingServices.size(); i++) {
8627 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008628 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008629 r.dump(pw, " ");
8630 }
8631 needSep = true;
8632 }
8633
8634 if (mRestartingServices.size() > 0) {
8635 if (needSep) pw.println(" ");
8636 pw.println(" Restarting services:");
8637 for (int i=0; i<mRestartingServices.size(); i++) {
8638 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008639 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008640 r.dump(pw, " ");
8641 }
8642 needSep = true;
8643 }
8644
8645 if (mStoppingServices.size() > 0) {
8646 if (needSep) pw.println(" ");
8647 pw.println(" Stopping services:");
8648 for (int i=0; i<mStoppingServices.size(); i++) {
8649 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008650 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008651 r.dump(pw, " ");
8652 }
8653 needSep = true;
8654 }
8655
8656 if (mServiceConnections.size() > 0) {
8657 if (needSep) pw.println(" ");
8658 pw.println(" Connection bindings to services:");
8659 Iterator<ConnectionRecord> it
8660 = mServiceConnections.values().iterator();
8661 while (it.hasNext()) {
8662 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008663 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008664 r.dump(pw, " ");
8665 }
8666 }
8667 }
8668 }
8669
8670 void dumpProviders(PrintWriter pw) {
8671 synchronized (this) {
8672 if (checkCallingPermission(android.Manifest.permission.DUMP)
8673 != PackageManager.PERMISSION_GRANTED) {
8674 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8675 + Binder.getCallingPid()
8676 + ", uid=" + Binder.getCallingUid()
8677 + " without permission "
8678 + android.Manifest.permission.DUMP);
8679 return;
8680 }
8681
8682 pw.println("Content Providers in Current Activity Manager State:");
8683
8684 boolean needSep = false;
8685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 if (mProvidersByClass.size() > 0) {
8687 if (needSep) pw.println(" ");
8688 pw.println(" Published content providers (by class):");
8689 Iterator it = mProvidersByClass.entrySet().iterator();
8690 while (it.hasNext()) {
8691 Map.Entry e = (Map.Entry)it.next();
8692 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008693 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008694 r.dump(pw, " ");
8695 }
8696 needSep = true;
8697 }
8698
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008699 if (mProvidersByName.size() > 0) {
8700 pw.println(" ");
8701 pw.println(" Authority to provider mappings:");
8702 Iterator it = mProvidersByName.entrySet().iterator();
8703 while (it.hasNext()) {
8704 Map.Entry e = (Map.Entry)it.next();
8705 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8706 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8707 pw.println(r);
8708 }
8709 needSep = true;
8710 }
8711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008712 if (mLaunchingProviders.size() > 0) {
8713 if (needSep) pw.println(" ");
8714 pw.println(" Launching content providers:");
8715 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008716 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8717 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008718 }
8719 needSep = true;
8720 }
8721
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008722 if (mGrantedUriPermissions.size() > 0) {
8723 pw.println();
8724 pw.println("Granted Uri Permissions:");
8725 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8726 int uid = mGrantedUriPermissions.keyAt(i);
8727 HashMap<Uri, UriPermission> perms
8728 = mGrantedUriPermissions.valueAt(i);
8729 pw.print(" * UID "); pw.print(uid);
8730 pw.println(" holds:");
8731 for (UriPermission perm : perms.values()) {
8732 pw.print(" "); pw.println(perm);
8733 perm.dump(pw, " ");
8734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008735 }
8736 }
8737 }
8738 }
8739
8740 void dumpSenders(PrintWriter pw) {
8741 synchronized (this) {
8742 if (checkCallingPermission(android.Manifest.permission.DUMP)
8743 != PackageManager.PERMISSION_GRANTED) {
8744 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8745 + Binder.getCallingPid()
8746 + ", uid=" + Binder.getCallingUid()
8747 + " without permission "
8748 + android.Manifest.permission.DUMP);
8749 return;
8750 }
8751
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008752 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008753
8754 if (this.mIntentSenderRecords.size() > 0) {
8755 Iterator<WeakReference<PendingIntentRecord>> it
8756 = mIntentSenderRecords.values().iterator();
8757 while (it.hasNext()) {
8758 WeakReference<PendingIntentRecord> ref = it.next();
8759 PendingIntentRecord rec = ref != null ? ref.get(): null;
8760 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008761 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008762 rec.dump(pw, " ");
8763 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008764 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008765 }
8766 }
8767 }
8768 }
8769 }
8770
8771 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008772 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008773 TaskRecord lastTask = null;
8774 for (int i=list.size()-1; i>=0; i--) {
8775 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008776 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008777 if (lastTask != r.task) {
8778 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008779 pw.print(prefix);
8780 pw.print(full ? "* " : " ");
8781 pw.println(lastTask);
8782 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008783 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008785 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008786 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8787 pw.print(" #"); pw.print(i); pw.print(": ");
8788 pw.println(r);
8789 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008790 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008792 }
8793 }
8794
8795 private static final int dumpProcessList(PrintWriter pw, List list,
8796 String prefix, String normalLabel, String persistentLabel,
8797 boolean inclOomAdj) {
8798 int numPers = 0;
8799 for (int i=list.size()-1; i>=0; i--) {
8800 ProcessRecord r = (ProcessRecord)list.get(i);
8801 if (false) {
8802 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8803 + " #" + i + ":");
8804 r.dump(pw, prefix + " ");
8805 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008806 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008807 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008808 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008809 } else {
8810 pw.println(String.format("%s%s #%2d: %s",
8811 prefix, (r.persistent ? persistentLabel : normalLabel),
8812 i, r.toString()));
8813 }
8814 if (r.persistent) {
8815 numPers++;
8816 }
8817 }
8818 return numPers;
8819 }
8820
8821 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8822 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008823 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008824 long uptime = SystemClock.uptimeMillis();
8825 long realtime = SystemClock.elapsedRealtime();
8826
8827 if (isCheckinRequest) {
8828 // short checkin version
8829 pw.println(uptime + "," + realtime);
8830 pw.flush();
8831 } else {
8832 pw.println("Applications Memory Usage (kB):");
8833 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8834 }
8835 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8836 ProcessRecord r = (ProcessRecord)list.get(i);
8837 if (r.thread != null) {
8838 if (!isCheckinRequest) {
8839 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8840 pw.flush();
8841 }
8842 try {
8843 r.thread.asBinder().dump(fd, args);
8844 } catch (RemoteException e) {
8845 if (!isCheckinRequest) {
8846 pw.println("Got RemoteException!");
8847 pw.flush();
8848 }
8849 }
8850 }
8851 }
8852 }
8853
8854 /**
8855 * Searches array of arguments for the specified string
8856 * @param args array of argument strings
8857 * @param value value to search for
8858 * @return true if the value is contained in the array
8859 */
8860 private static boolean scanArgs(String[] args, String value) {
8861 if (args != null) {
8862 for (String arg : args) {
8863 if (value.equals(arg)) {
8864 return true;
8865 }
8866 }
8867 }
8868 return false;
8869 }
8870
8871 private final int indexOfTokenLocked(IBinder token, boolean required) {
8872 int count = mHistory.size();
8873
8874 // convert the token to an entry in the history.
8875 HistoryRecord r = null;
8876 int index = -1;
8877 for (int i=count-1; i>=0; i--) {
8878 Object o = mHistory.get(i);
8879 if (o == token) {
8880 r = (HistoryRecord)o;
8881 index = i;
8882 break;
8883 }
8884 }
8885 if (index < 0 && required) {
8886 RuntimeInit.crash(TAG, new InvalidTokenException(token));
8887 }
8888
8889 return index;
8890 }
8891
8892 static class InvalidTokenException extends Exception {
8893 InvalidTokenException(IBinder token) {
8894 super("Bad activity token: " + token);
8895 }
8896 }
8897
8898 private final void killServicesLocked(ProcessRecord app,
8899 boolean allowRestart) {
8900 // Report disconnected services.
8901 if (false) {
8902 // XXX we are letting the client link to the service for
8903 // death notifications.
8904 if (app.services.size() > 0) {
8905 Iterator it = app.services.iterator();
8906 while (it.hasNext()) {
8907 ServiceRecord r = (ServiceRecord)it.next();
8908 if (r.connections.size() > 0) {
8909 Iterator<ConnectionRecord> jt
8910 = r.connections.values().iterator();
8911 while (jt.hasNext()) {
8912 ConnectionRecord c = jt.next();
8913 if (c.binding.client != app) {
8914 try {
8915 //c.conn.connected(r.className, null);
8916 } catch (Exception e) {
8917 // todo: this should be asynchronous!
8918 Log.w(TAG, "Exception thrown disconnected servce "
8919 + r.shortName
8920 + " from app " + app.processName, e);
8921 }
8922 }
8923 }
8924 }
8925 }
8926 }
8927 }
8928
8929 // Clean up any connections this application has to other services.
8930 if (app.connections.size() > 0) {
8931 Iterator<ConnectionRecord> it = app.connections.iterator();
8932 while (it.hasNext()) {
8933 ConnectionRecord r = it.next();
8934 removeConnectionLocked(r, app, null);
8935 }
8936 }
8937 app.connections.clear();
8938
8939 if (app.services.size() != 0) {
8940 // Any services running in the application need to be placed
8941 // back in the pending list.
8942 Iterator it = app.services.iterator();
8943 while (it.hasNext()) {
8944 ServiceRecord sr = (ServiceRecord)it.next();
8945 synchronized (sr.stats.getBatteryStats()) {
8946 sr.stats.stopLaunchedLocked();
8947 }
8948 sr.app = null;
8949 sr.executeNesting = 0;
8950 mStoppingServices.remove(sr);
8951 if (sr.bindings.size() > 0) {
8952 Iterator<IntentBindRecord> bindings
8953 = sr.bindings.values().iterator();
8954 while (bindings.hasNext()) {
8955 IntentBindRecord b = bindings.next();
8956 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
8957 + ": shouldUnbind=" + b.hasBound);
8958 b.binder = null;
8959 b.requested = b.received = b.hasBound = false;
8960 }
8961 }
8962
8963 if (sr.crashCount >= 2) {
8964 Log.w(TAG, "Service crashed " + sr.crashCount
8965 + " times, stopping: " + sr);
8966 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
8967 sr.crashCount, sr.shortName, app.pid);
8968 bringDownServiceLocked(sr, true);
8969 } else if (!allowRestart) {
8970 bringDownServiceLocked(sr, true);
8971 } else {
8972 scheduleServiceRestartLocked(sr);
8973 }
8974 }
8975
8976 if (!allowRestart) {
8977 app.services.clear();
8978 }
8979 }
8980
8981 app.executingServices.clear();
8982 }
8983
8984 private final void removeDyingProviderLocked(ProcessRecord proc,
8985 ContentProviderRecord cpr) {
8986 synchronized (cpr) {
8987 cpr.launchingApp = null;
8988 cpr.notifyAll();
8989 }
8990
8991 mProvidersByClass.remove(cpr.info.name);
8992 String names[] = cpr.info.authority.split(";");
8993 for (int j = 0; j < names.length; j++) {
8994 mProvidersByName.remove(names[j]);
8995 }
8996
8997 Iterator<ProcessRecord> cit = cpr.clients.iterator();
8998 while (cit.hasNext()) {
8999 ProcessRecord capp = cit.next();
9000 if (!capp.persistent && capp.thread != null
9001 && capp.pid != 0
9002 && capp.pid != MY_PID) {
9003 Log.i(TAG, "Killing app " + capp.processName
9004 + " (pid " + capp.pid
9005 + ") because provider " + cpr.info.name
9006 + " is in dying process " + proc.processName);
9007 Process.killProcess(capp.pid);
9008 }
9009 }
9010
9011 mLaunchingProviders.remove(cpr);
9012 }
9013
9014 /**
9015 * Main code for cleaning up a process when it has gone away. This is
9016 * called both as a result of the process dying, or directly when stopping
9017 * a process when running in single process mode.
9018 */
9019 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9020 boolean restarting, int index) {
9021 if (index >= 0) {
9022 mLRUProcesses.remove(index);
9023 }
9024
9025 // Dismiss any open dialogs.
9026 if (app.crashDialog != null) {
9027 app.crashDialog.dismiss();
9028 app.crashDialog = null;
9029 }
9030 if (app.anrDialog != null) {
9031 app.anrDialog.dismiss();
9032 app.anrDialog = null;
9033 }
9034 if (app.waitDialog != null) {
9035 app.waitDialog.dismiss();
9036 app.waitDialog = null;
9037 }
9038
9039 app.crashing = false;
9040 app.notResponding = false;
9041
9042 app.resetPackageList();
9043 app.thread = null;
9044 app.forcingToForeground = null;
9045 app.foregroundServices = false;
9046
9047 killServicesLocked(app, true);
9048
9049 boolean restart = false;
9050
9051 int NL = mLaunchingProviders.size();
9052
9053 // Remove published content providers.
9054 if (!app.pubProviders.isEmpty()) {
9055 Iterator it = app.pubProviders.values().iterator();
9056 while (it.hasNext()) {
9057 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9058 cpr.provider = null;
9059 cpr.app = null;
9060
9061 // See if someone is waiting for this provider... in which
9062 // case we don't remove it, but just let it restart.
9063 int i = 0;
9064 if (!app.bad) {
9065 for (; i<NL; i++) {
9066 if (mLaunchingProviders.get(i) == cpr) {
9067 restart = true;
9068 break;
9069 }
9070 }
9071 } else {
9072 i = NL;
9073 }
9074
9075 if (i >= NL) {
9076 removeDyingProviderLocked(app, cpr);
9077 NL = mLaunchingProviders.size();
9078 }
9079 }
9080 app.pubProviders.clear();
9081 }
9082
9083 // Look through the content providers we are waiting to have launched,
9084 // and if any run in this process then either schedule a restart of
9085 // the process or kill the client waiting for it if this process has
9086 // gone bad.
9087 for (int i=0; i<NL; i++) {
9088 ContentProviderRecord cpr = (ContentProviderRecord)
9089 mLaunchingProviders.get(i);
9090 if (cpr.launchingApp == app) {
9091 if (!app.bad) {
9092 restart = true;
9093 } else {
9094 removeDyingProviderLocked(app, cpr);
9095 NL = mLaunchingProviders.size();
9096 }
9097 }
9098 }
9099
9100 // Unregister from connected content providers.
9101 if (!app.conProviders.isEmpty()) {
9102 Iterator it = app.conProviders.iterator();
9103 while (it.hasNext()) {
9104 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9105 cpr.clients.remove(app);
9106 }
9107 app.conProviders.clear();
9108 }
9109
9110 skipCurrentReceiverLocked(app);
9111
9112 // Unregister any receivers.
9113 if (app.receivers.size() > 0) {
9114 Iterator<ReceiverList> it = app.receivers.iterator();
9115 while (it.hasNext()) {
9116 removeReceiverLocked(it.next());
9117 }
9118 app.receivers.clear();
9119 }
9120
9121 // If the caller is restarting this app, then leave it in its
9122 // current lists and let the caller take care of it.
9123 if (restarting) {
9124 return;
9125 }
9126
9127 if (!app.persistent) {
9128 if (DEBUG_PROCESSES) Log.v(TAG,
9129 "Removing non-persistent process during cleanup: " + app);
9130 mProcessNames.remove(app.processName, app.info.uid);
9131 } else if (!app.removed) {
9132 // This app is persistent, so we need to keep its record around.
9133 // If it is not already on the pending app list, add it there
9134 // and start a new process for it.
9135 app.thread = null;
9136 app.forcingToForeground = null;
9137 app.foregroundServices = false;
9138 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9139 mPersistentStartingProcesses.add(app);
9140 restart = true;
9141 }
9142 }
9143 mProcessesOnHold.remove(app);
9144
The Android Open Source Project4df24232009-03-05 14:34:35 -08009145 if (app == mHomeProcess) {
9146 mHomeProcess = null;
9147 }
9148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009149 if (restart) {
9150 // We have components that still need to be running in the
9151 // process, so re-launch it.
9152 mProcessNames.put(app.processName, app.info.uid, app);
9153 startProcessLocked(app, "restart", app.processName);
9154 } else if (app.pid > 0 && app.pid != MY_PID) {
9155 // Goodbye!
9156 synchronized (mPidsSelfLocked) {
9157 mPidsSelfLocked.remove(app.pid);
9158 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9159 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009160 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009161 }
9162 }
9163
9164 // =========================================================
9165 // SERVICES
9166 // =========================================================
9167
9168 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9169 ActivityManager.RunningServiceInfo info =
9170 new ActivityManager.RunningServiceInfo();
9171 info.service = r.name;
9172 if (r.app != null) {
9173 info.pid = r.app.pid;
9174 }
9175 info.process = r.processName;
9176 info.foreground = r.isForeground;
9177 info.activeSince = r.createTime;
9178 info.started = r.startRequested;
9179 info.clientCount = r.connections.size();
9180 info.crashCount = r.crashCount;
9181 info.lastActivityTime = r.lastActivity;
9182 return info;
9183 }
9184
9185 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9186 int flags) {
9187 synchronized (this) {
9188 ArrayList<ActivityManager.RunningServiceInfo> res
9189 = new ArrayList<ActivityManager.RunningServiceInfo>();
9190
9191 if (mServices.size() > 0) {
9192 Iterator<ServiceRecord> it = mServices.values().iterator();
9193 while (it.hasNext() && res.size() < maxNum) {
9194 res.add(makeRunningServiceInfoLocked(it.next()));
9195 }
9196 }
9197
9198 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9199 ServiceRecord r = mRestartingServices.get(i);
9200 ActivityManager.RunningServiceInfo info =
9201 makeRunningServiceInfoLocked(r);
9202 info.restarting = r.nextRestartTime;
9203 res.add(info);
9204 }
9205
9206 return res;
9207 }
9208 }
9209
9210 private final ServiceRecord findServiceLocked(ComponentName name,
9211 IBinder token) {
9212 ServiceRecord r = mServices.get(name);
9213 return r == token ? r : null;
9214 }
9215
9216 private final class ServiceLookupResult {
9217 final ServiceRecord record;
9218 final String permission;
9219
9220 ServiceLookupResult(ServiceRecord _record, String _permission) {
9221 record = _record;
9222 permission = _permission;
9223 }
9224 };
9225
9226 private ServiceLookupResult findServiceLocked(Intent service,
9227 String resolvedType) {
9228 ServiceRecord r = null;
9229 if (service.getComponent() != null) {
9230 r = mServices.get(service.getComponent());
9231 }
9232 if (r == null) {
9233 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9234 r = mServicesByIntent.get(filter);
9235 }
9236
9237 if (r == null) {
9238 try {
9239 ResolveInfo rInfo =
9240 ActivityThread.getPackageManager().resolveService(
9241 service, resolvedType, 0);
9242 ServiceInfo sInfo =
9243 rInfo != null ? rInfo.serviceInfo : null;
9244 if (sInfo == null) {
9245 return null;
9246 }
9247
9248 ComponentName name = new ComponentName(
9249 sInfo.applicationInfo.packageName, sInfo.name);
9250 r = mServices.get(name);
9251 } catch (RemoteException ex) {
9252 // pm is in same process, this will never happen.
9253 }
9254 }
9255 if (r != null) {
9256 int callingPid = Binder.getCallingPid();
9257 int callingUid = Binder.getCallingUid();
9258 if (checkComponentPermission(r.permission,
9259 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9260 != PackageManager.PERMISSION_GRANTED) {
9261 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9262 + " from pid=" + callingPid
9263 + ", uid=" + callingUid
9264 + " requires " + r.permission);
9265 return new ServiceLookupResult(null, r.permission);
9266 }
9267 return new ServiceLookupResult(r, null);
9268 }
9269 return null;
9270 }
9271
9272 private class ServiceRestarter implements Runnable {
9273 private ServiceRecord mService;
9274
9275 void setService(ServiceRecord service) {
9276 mService = service;
9277 }
9278
9279 public void run() {
9280 synchronized(ActivityManagerService.this) {
9281 performServiceRestartLocked(mService);
9282 }
9283 }
9284 }
9285
9286 private ServiceLookupResult retrieveServiceLocked(Intent service,
9287 String resolvedType, int callingPid, int callingUid) {
9288 ServiceRecord r = null;
9289 if (service.getComponent() != null) {
9290 r = mServices.get(service.getComponent());
9291 }
9292 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9293 r = mServicesByIntent.get(filter);
9294 if (r == null) {
9295 try {
9296 ResolveInfo rInfo =
9297 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009298 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009299 ServiceInfo sInfo =
9300 rInfo != null ? rInfo.serviceInfo : null;
9301 if (sInfo == null) {
9302 Log.w(TAG, "Unable to start service " + service +
9303 ": not found");
9304 return null;
9305 }
9306
9307 ComponentName name = new ComponentName(
9308 sInfo.applicationInfo.packageName, sInfo.name);
9309 r = mServices.get(name);
9310 if (r == null) {
9311 filter = new Intent.FilterComparison(service.cloneFilter());
9312 ServiceRestarter res = new ServiceRestarter();
9313 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9314 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9315 synchronized (stats) {
9316 ss = stats.getServiceStatsLocked(
9317 sInfo.applicationInfo.uid, sInfo.packageName,
9318 sInfo.name);
9319 }
9320 r = new ServiceRecord(ss, name, filter, sInfo, res);
9321 res.setService(r);
9322 mServices.put(name, r);
9323 mServicesByIntent.put(filter, r);
9324
9325 // Make sure this component isn't in the pending list.
9326 int N = mPendingServices.size();
9327 for (int i=0; i<N; i++) {
9328 ServiceRecord pr = mPendingServices.get(i);
9329 if (pr.name.equals(name)) {
9330 mPendingServices.remove(i);
9331 i--;
9332 N--;
9333 }
9334 }
9335 }
9336 } catch (RemoteException ex) {
9337 // pm is in same process, this will never happen.
9338 }
9339 }
9340 if (r != null) {
9341 if (checkComponentPermission(r.permission,
9342 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9343 != PackageManager.PERMISSION_GRANTED) {
9344 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9345 + " from pid=" + Binder.getCallingPid()
9346 + ", uid=" + Binder.getCallingUid()
9347 + " requires " + r.permission);
9348 return new ServiceLookupResult(null, r.permission);
9349 }
9350 return new ServiceLookupResult(r, null);
9351 }
9352 return null;
9353 }
9354
9355 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9356 long now = SystemClock.uptimeMillis();
9357 if (r.executeNesting == 0 && r.app != null) {
9358 if (r.app.executingServices.size() == 0) {
9359 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9360 msg.obj = r.app;
9361 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9362 }
9363 r.app.executingServices.add(r);
9364 }
9365 r.executeNesting++;
9366 r.executingStart = now;
9367 }
9368
9369 private final void sendServiceArgsLocked(ServiceRecord r,
9370 boolean oomAdjusted) {
9371 final int N = r.startArgs.size();
9372 if (N == 0) {
9373 return;
9374 }
9375
9376 final int BASEID = r.lastStartId - N + 1;
9377 int i = 0;
9378 while (i < N) {
9379 try {
9380 Intent args = r.startArgs.get(i);
9381 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9382 + r.name + " " + r.intent + " args=" + args);
9383 bumpServiceExecutingLocked(r);
9384 if (!oomAdjusted) {
9385 oomAdjusted = true;
9386 updateOomAdjLocked(r.app);
9387 }
9388 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9389 i++;
9390 } catch (Exception e) {
9391 break;
9392 }
9393 }
9394 if (i == N) {
9395 r.startArgs.clear();
9396 } else {
9397 while (i > 0) {
9398 r.startArgs.remove(0);
9399 i--;
9400 }
9401 }
9402 }
9403
9404 private final boolean requestServiceBindingLocked(ServiceRecord r,
9405 IntentBindRecord i, boolean rebind) {
9406 if (r.app == null || r.app.thread == null) {
9407 // If service is not currently running, can't yet bind.
9408 return false;
9409 }
9410 if ((!i.requested || rebind) && i.apps.size() > 0) {
9411 try {
9412 bumpServiceExecutingLocked(r);
9413 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9414 + ": shouldUnbind=" + i.hasBound);
9415 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9416 if (!rebind) {
9417 i.requested = true;
9418 }
9419 i.hasBound = true;
9420 i.doRebind = false;
9421 } catch (RemoteException e) {
9422 return false;
9423 }
9424 }
9425 return true;
9426 }
9427
9428 private final void requestServiceBindingsLocked(ServiceRecord r) {
9429 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9430 while (bindings.hasNext()) {
9431 IntentBindRecord i = bindings.next();
9432 if (!requestServiceBindingLocked(r, i, false)) {
9433 break;
9434 }
9435 }
9436 }
9437
9438 private final void realStartServiceLocked(ServiceRecord r,
9439 ProcessRecord app) throws RemoteException {
9440 if (app.thread == null) {
9441 throw new RemoteException();
9442 }
9443
9444 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009445 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446
9447 app.services.add(r);
9448 bumpServiceExecutingLocked(r);
9449 updateLRUListLocked(app, true);
9450
9451 boolean created = false;
9452 try {
9453 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9454 + r.name + " " + r.intent);
9455 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9456 System.identityHashCode(r), r.shortName,
9457 r.intent.getIntent().toString(), r.app.pid);
9458 synchronized (r.stats.getBatteryStats()) {
9459 r.stats.startLaunchedLocked();
9460 }
9461 app.thread.scheduleCreateService(r, r.serviceInfo);
9462 created = true;
9463 } finally {
9464 if (!created) {
9465 app.services.remove(r);
9466 scheduleServiceRestartLocked(r);
9467 }
9468 }
9469
9470 requestServiceBindingsLocked(r);
9471 sendServiceArgsLocked(r, true);
9472 }
9473
9474 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9475 r.totalRestartCount++;
9476 if (r.restartDelay == 0) {
9477 r.restartCount++;
9478 r.restartDelay = SERVICE_RESTART_DURATION;
9479 } else {
9480 // If it has been a "reasonably long time" since the service
9481 // was started, then reset our restart duration back to
9482 // the beginning, so we don't infinitely increase the duration
9483 // on a service that just occasionally gets killed (which is
9484 // a normal case, due to process being killed to reclaim memory).
9485 long now = SystemClock.uptimeMillis();
9486 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9487 r.restartCount = 1;
9488 r.restartDelay = SERVICE_RESTART_DURATION;
9489 } else {
9490 r.restartDelay *= 2;
9491 }
9492 }
9493 if (!mRestartingServices.contains(r)) {
9494 mRestartingServices.add(r);
9495 }
9496 mHandler.removeCallbacks(r.restarter);
9497 mHandler.postDelayed(r.restarter, r.restartDelay);
9498 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9499 Log.w(TAG, "Scheduling restart of crashed service "
9500 + r.shortName + " in " + r.restartDelay + "ms");
9501 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9502 r.shortName, r.restartDelay);
9503
9504 Message msg = Message.obtain();
9505 msg.what = SERVICE_ERROR_MSG;
9506 msg.obj = r;
9507 mHandler.sendMessage(msg);
9508 }
9509
9510 final void performServiceRestartLocked(ServiceRecord r) {
9511 if (!mRestartingServices.contains(r)) {
9512 return;
9513 }
9514 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9515 }
9516
9517 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9518 if (r.restartDelay == 0) {
9519 return false;
9520 }
9521 r.resetRestartCounter();
9522 mRestartingServices.remove(r);
9523 mHandler.removeCallbacks(r.restarter);
9524 return true;
9525 }
9526
9527 private final boolean bringUpServiceLocked(ServiceRecord r,
9528 int intentFlags, boolean whileRestarting) {
9529 //Log.i(TAG, "Bring up service:");
9530 //r.dump(" ");
9531
9532 if (r.app != null) {
9533 sendServiceArgsLocked(r, false);
9534 return true;
9535 }
9536
9537 if (!whileRestarting && r.restartDelay > 0) {
9538 // If waiting for a restart, then do nothing.
9539 return true;
9540 }
9541
9542 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9543 + " " + r.intent);
9544
9545 final String appName = r.processName;
9546 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9547 if (app != null && app.thread != null) {
9548 try {
9549 realStartServiceLocked(r, app);
9550 return true;
9551 } catch (RemoteException e) {
9552 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9553 }
9554
9555 // If a dead object exception was thrown -- fall through to
9556 // restart the application.
9557 }
9558
9559 if (!mPendingServices.contains(r)) {
9560 // Not running -- get it started, and enqueue this service record
9561 // to be executed when the app comes up.
9562 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9563 "service", r.name) == null) {
9564 Log.w(TAG, "Unable to launch app "
9565 + r.appInfo.packageName + "/"
9566 + r.appInfo.uid + " for service "
9567 + r.intent.getIntent() + ": process is bad");
9568 bringDownServiceLocked(r, true);
9569 return false;
9570 }
9571 mPendingServices.add(r);
9572 }
9573 return true;
9574 }
9575
9576 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9577 //Log.i(TAG, "Bring down service:");
9578 //r.dump(" ");
9579
9580 // Does it still need to run?
9581 if (!force && r.startRequested) {
9582 return;
9583 }
9584 if (r.connections.size() > 0) {
9585 if (!force) {
9586 // XXX should probably keep a count of the number of auto-create
9587 // connections directly in the service.
9588 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9589 while (it.hasNext()) {
9590 ConnectionRecord cr = it.next();
9591 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9592 return;
9593 }
9594 }
9595 }
9596
9597 // Report to all of the connections that the service is no longer
9598 // available.
9599 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9600 while (it.hasNext()) {
9601 ConnectionRecord c = it.next();
9602 try {
9603 // todo: shouldn't be a synchronous call!
9604 c.conn.connected(r.name, null);
9605 } catch (Exception e) {
9606 Log.w(TAG, "Failure disconnecting service " + r.name +
9607 " to connection " + c.conn.asBinder() +
9608 " (in " + c.binding.client.processName + ")", e);
9609 }
9610 }
9611 }
9612
9613 // Tell the service that it has been unbound.
9614 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9615 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9616 while (it.hasNext()) {
9617 IntentBindRecord ibr = it.next();
9618 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9619 + ": hasBound=" + ibr.hasBound);
9620 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9621 try {
9622 bumpServiceExecutingLocked(r);
9623 updateOomAdjLocked(r.app);
9624 ibr.hasBound = false;
9625 r.app.thread.scheduleUnbindService(r,
9626 ibr.intent.getIntent());
9627 } catch (Exception e) {
9628 Log.w(TAG, "Exception when unbinding service "
9629 + r.shortName, e);
9630 serviceDoneExecutingLocked(r, true);
9631 }
9632 }
9633 }
9634 }
9635
9636 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9637 + " " + r.intent);
9638 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9639 System.identityHashCode(r), r.shortName,
9640 (r.app != null) ? r.app.pid : -1);
9641
9642 mServices.remove(r.name);
9643 mServicesByIntent.remove(r.intent);
9644 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9645 r.totalRestartCount = 0;
9646 unscheduleServiceRestartLocked(r);
9647
9648 // Also make sure it is not on the pending list.
9649 int N = mPendingServices.size();
9650 for (int i=0; i<N; i++) {
9651 if (mPendingServices.get(i) == r) {
9652 mPendingServices.remove(i);
9653 if (DEBUG_SERVICE) Log.v(
9654 TAG, "Removed pending service: " + r.shortName);
9655 i--;
9656 N--;
9657 }
9658 }
9659
9660 if (r.app != null) {
9661 synchronized (r.stats.getBatteryStats()) {
9662 r.stats.stopLaunchedLocked();
9663 }
9664 r.app.services.remove(r);
9665 if (r.app.thread != null) {
9666 updateServiceForegroundLocked(r.app, false);
9667 try {
9668 Log.i(TAG, "Stopping service: " + r.shortName);
9669 bumpServiceExecutingLocked(r);
9670 mStoppingServices.add(r);
9671 updateOomAdjLocked(r.app);
9672 r.app.thread.scheduleStopService(r);
9673 } catch (Exception e) {
9674 Log.w(TAG, "Exception when stopping service "
9675 + r.shortName, e);
9676 serviceDoneExecutingLocked(r, true);
9677 }
9678 } else {
9679 if (DEBUG_SERVICE) Log.v(
9680 TAG, "Removed service that has no process: " + r.shortName);
9681 }
9682 } else {
9683 if (DEBUG_SERVICE) Log.v(
9684 TAG, "Removed service that is not running: " + r.shortName);
9685 }
9686 }
9687
9688 ComponentName startServiceLocked(IApplicationThread caller,
9689 Intent service, String resolvedType,
9690 int callingPid, int callingUid) {
9691 synchronized(this) {
9692 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9693 + " type=" + resolvedType + " args=" + service.getExtras());
9694
9695 if (caller != null) {
9696 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9697 if (callerApp == null) {
9698 throw new SecurityException(
9699 "Unable to find app for caller " + caller
9700 + " (pid=" + Binder.getCallingPid()
9701 + ") when starting service " + service);
9702 }
9703 }
9704
9705 ServiceLookupResult res =
9706 retrieveServiceLocked(service, resolvedType,
9707 callingPid, callingUid);
9708 if (res == null) {
9709 return null;
9710 }
9711 if (res.record == null) {
9712 return new ComponentName("!", res.permission != null
9713 ? res.permission : "private to package");
9714 }
9715 ServiceRecord r = res.record;
9716 if (unscheduleServiceRestartLocked(r)) {
9717 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9718 + r.shortName);
9719 }
9720 r.startRequested = true;
9721 r.startArgs.add(service);
9722 r.lastStartId++;
9723 if (r.lastStartId < 1) {
9724 r.lastStartId = 1;
9725 }
9726 r.lastActivity = SystemClock.uptimeMillis();
9727 synchronized (r.stats.getBatteryStats()) {
9728 r.stats.startRunningLocked();
9729 }
9730 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9731 return new ComponentName("!", "Service process is bad");
9732 }
9733 return r.name;
9734 }
9735 }
9736
9737 public ComponentName startService(IApplicationThread caller, Intent service,
9738 String resolvedType) {
9739 // Refuse possible leaked file descriptors
9740 if (service != null && service.hasFileDescriptors() == true) {
9741 throw new IllegalArgumentException("File descriptors passed in Intent");
9742 }
9743
9744 synchronized(this) {
9745 final int callingPid = Binder.getCallingPid();
9746 final int callingUid = Binder.getCallingUid();
9747 final long origId = Binder.clearCallingIdentity();
9748 ComponentName res = startServiceLocked(caller, service,
9749 resolvedType, callingPid, callingUid);
9750 Binder.restoreCallingIdentity(origId);
9751 return res;
9752 }
9753 }
9754
9755 ComponentName startServiceInPackage(int uid,
9756 Intent service, String resolvedType) {
9757 synchronized(this) {
9758 final long origId = Binder.clearCallingIdentity();
9759 ComponentName res = startServiceLocked(null, service,
9760 resolvedType, -1, uid);
9761 Binder.restoreCallingIdentity(origId);
9762 return res;
9763 }
9764 }
9765
9766 public int stopService(IApplicationThread caller, Intent service,
9767 String resolvedType) {
9768 // Refuse possible leaked file descriptors
9769 if (service != null && service.hasFileDescriptors() == true) {
9770 throw new IllegalArgumentException("File descriptors passed in Intent");
9771 }
9772
9773 synchronized(this) {
9774 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9775 + " type=" + resolvedType);
9776
9777 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9778 if (caller != null && callerApp == null) {
9779 throw new SecurityException(
9780 "Unable to find app for caller " + caller
9781 + " (pid=" + Binder.getCallingPid()
9782 + ") when stopping service " + service);
9783 }
9784
9785 // If this service is active, make sure it is stopped.
9786 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9787 if (r != null) {
9788 if (r.record != null) {
9789 synchronized (r.record.stats.getBatteryStats()) {
9790 r.record.stats.stopRunningLocked();
9791 }
9792 r.record.startRequested = false;
9793 final long origId = Binder.clearCallingIdentity();
9794 bringDownServiceLocked(r.record, false);
9795 Binder.restoreCallingIdentity(origId);
9796 return 1;
9797 }
9798 return -1;
9799 }
9800 }
9801
9802 return 0;
9803 }
9804
9805 public IBinder peekService(Intent service, String resolvedType) {
9806 // Refuse possible leaked file descriptors
9807 if (service != null && service.hasFileDescriptors() == true) {
9808 throw new IllegalArgumentException("File descriptors passed in Intent");
9809 }
9810
9811 IBinder ret = null;
9812
9813 synchronized(this) {
9814 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9815
9816 if (r != null) {
9817 // r.record is null if findServiceLocked() failed the caller permission check
9818 if (r.record == null) {
9819 throw new SecurityException(
9820 "Permission Denial: Accessing service " + r.record.name
9821 + " from pid=" + Binder.getCallingPid()
9822 + ", uid=" + Binder.getCallingUid()
9823 + " requires " + r.permission);
9824 }
9825 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9826 if (ib != null) {
9827 ret = ib.binder;
9828 }
9829 }
9830 }
9831
9832 return ret;
9833 }
9834
9835 public boolean stopServiceToken(ComponentName className, IBinder token,
9836 int startId) {
9837 synchronized(this) {
9838 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9839 + " " + token + " startId=" + startId);
9840 ServiceRecord r = findServiceLocked(className, token);
9841 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9842 synchronized (r.stats.getBatteryStats()) {
9843 r.stats.stopRunningLocked();
9844 r.startRequested = false;
9845 }
9846 final long origId = Binder.clearCallingIdentity();
9847 bringDownServiceLocked(r, false);
9848 Binder.restoreCallingIdentity(origId);
9849 return true;
9850 }
9851 }
9852 return false;
9853 }
9854
9855 public void setServiceForeground(ComponentName className, IBinder token,
9856 boolean isForeground) {
9857 synchronized(this) {
9858 ServiceRecord r = findServiceLocked(className, token);
9859 if (r != null) {
9860 if (r.isForeground != isForeground) {
9861 final long origId = Binder.clearCallingIdentity();
9862 r.isForeground = isForeground;
9863 if (r.app != null) {
9864 updateServiceForegroundLocked(r.app, true);
9865 }
9866 Binder.restoreCallingIdentity(origId);
9867 }
9868 }
9869 }
9870 }
9871
9872 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9873 boolean anyForeground = false;
9874 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9875 if (sr.isForeground) {
9876 anyForeground = true;
9877 break;
9878 }
9879 }
9880 if (anyForeground != proc.foregroundServices) {
9881 proc.foregroundServices = anyForeground;
9882 if (oomAdj) {
9883 updateOomAdjLocked();
9884 }
9885 }
9886 }
9887
9888 public int bindService(IApplicationThread caller, IBinder token,
9889 Intent service, String resolvedType,
9890 IServiceConnection connection, int flags) {
9891 // Refuse possible leaked file descriptors
9892 if (service != null && service.hasFileDescriptors() == true) {
9893 throw new IllegalArgumentException("File descriptors passed in Intent");
9894 }
9895
9896 synchronized(this) {
9897 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9898 + " type=" + resolvedType + " conn=" + connection.asBinder()
9899 + " flags=0x" + Integer.toHexString(flags));
9900 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9901 if (callerApp == null) {
9902 throw new SecurityException(
9903 "Unable to find app for caller " + caller
9904 + " (pid=" + Binder.getCallingPid()
9905 + ") when binding service " + service);
9906 }
9907
9908 HistoryRecord activity = null;
9909 if (token != null) {
9910 int aindex = indexOfTokenLocked(token, false);
9911 if (aindex < 0) {
9912 Log.w(TAG, "Binding with unknown activity: " + token);
9913 return 0;
9914 }
9915 activity = (HistoryRecord)mHistory.get(aindex);
9916 }
9917
9918 ServiceLookupResult res =
9919 retrieveServiceLocked(service, resolvedType,
9920 Binder.getCallingPid(), Binder.getCallingUid());
9921 if (res == null) {
9922 return 0;
9923 }
9924 if (res.record == null) {
9925 return -1;
9926 }
9927 ServiceRecord s = res.record;
9928
9929 final long origId = Binder.clearCallingIdentity();
9930
9931 if (unscheduleServiceRestartLocked(s)) {
9932 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
9933 + s.shortName);
9934 }
9935
9936 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
9937 ConnectionRecord c = new ConnectionRecord(b, activity,
9938 connection, flags);
9939
9940 IBinder binder = connection.asBinder();
9941 s.connections.put(binder, c);
9942 b.connections.add(c);
9943 if (activity != null) {
9944 if (activity.connections == null) {
9945 activity.connections = new HashSet<ConnectionRecord>();
9946 }
9947 activity.connections.add(c);
9948 }
9949 b.client.connections.add(c);
9950 mServiceConnections.put(binder, c);
9951
9952 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
9953 s.lastActivity = SystemClock.uptimeMillis();
9954 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
9955 return 0;
9956 }
9957 }
9958
9959 if (s.app != null) {
9960 // This could have made the service more important.
9961 updateOomAdjLocked(s.app);
9962 }
9963
9964 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
9965 + ": received=" + b.intent.received
9966 + " apps=" + b.intent.apps.size()
9967 + " doRebind=" + b.intent.doRebind);
9968
9969 if (s.app != null && b.intent.received) {
9970 // Service is already running, so we can immediately
9971 // publish the connection.
9972 try {
9973 c.conn.connected(s.name, b.intent.binder);
9974 } catch (Exception e) {
9975 Log.w(TAG, "Failure sending service " + s.shortName
9976 + " to connection " + c.conn.asBinder()
9977 + " (in " + c.binding.client.processName + ")", e);
9978 }
9979
9980 // If this is the first app connected back to this binding,
9981 // and the service had previously asked to be told when
9982 // rebound, then do so.
9983 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
9984 requestServiceBindingLocked(s, b.intent, true);
9985 }
9986 } else if (!b.intent.requested) {
9987 requestServiceBindingLocked(s, b.intent, false);
9988 }
9989
9990 Binder.restoreCallingIdentity(origId);
9991 }
9992
9993 return 1;
9994 }
9995
9996 private void removeConnectionLocked(
9997 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
9998 IBinder binder = c.conn.asBinder();
9999 AppBindRecord b = c.binding;
10000 ServiceRecord s = b.service;
10001 s.connections.remove(binder);
10002 b.connections.remove(c);
10003 if (c.activity != null && c.activity != skipAct) {
10004 if (c.activity.connections != null) {
10005 c.activity.connections.remove(c);
10006 }
10007 }
10008 if (b.client != skipApp) {
10009 b.client.connections.remove(c);
10010 }
10011 mServiceConnections.remove(binder);
10012
10013 if (b.connections.size() == 0) {
10014 b.intent.apps.remove(b.client);
10015 }
10016
10017 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10018 + ": shouldUnbind=" + b.intent.hasBound);
10019 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10020 && b.intent.hasBound) {
10021 try {
10022 bumpServiceExecutingLocked(s);
10023 updateOomAdjLocked(s.app);
10024 b.intent.hasBound = false;
10025 // Assume the client doesn't want to know about a rebind;
10026 // we will deal with that later if it asks for one.
10027 b.intent.doRebind = false;
10028 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10029 } catch (Exception e) {
10030 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10031 serviceDoneExecutingLocked(s, true);
10032 }
10033 }
10034
10035 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10036 bringDownServiceLocked(s, false);
10037 }
10038 }
10039
10040 public boolean unbindService(IServiceConnection connection) {
10041 synchronized (this) {
10042 IBinder binder = connection.asBinder();
10043 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10044 ConnectionRecord r = mServiceConnections.get(binder);
10045 if (r == null) {
10046 Log.w(TAG, "Unbind failed: could not find connection for "
10047 + connection.asBinder());
10048 return false;
10049 }
10050
10051 final long origId = Binder.clearCallingIdentity();
10052
10053 removeConnectionLocked(r, null, null);
10054
10055 if (r.binding.service.app != null) {
10056 // This could have made the service less important.
10057 updateOomAdjLocked(r.binding.service.app);
10058 }
10059
10060 Binder.restoreCallingIdentity(origId);
10061 }
10062
10063 return true;
10064 }
10065
10066 public void publishService(IBinder token, Intent intent, IBinder service) {
10067 // Refuse possible leaked file descriptors
10068 if (intent != null && intent.hasFileDescriptors() == true) {
10069 throw new IllegalArgumentException("File descriptors passed in Intent");
10070 }
10071
10072 synchronized(this) {
10073 if (!(token instanceof ServiceRecord)) {
10074 throw new IllegalArgumentException("Invalid service token");
10075 }
10076 ServiceRecord r = (ServiceRecord)token;
10077
10078 final long origId = Binder.clearCallingIdentity();
10079
10080 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10081 + " " + intent + ": " + service);
10082 if (r != null) {
10083 Intent.FilterComparison filter
10084 = new Intent.FilterComparison(intent);
10085 IntentBindRecord b = r.bindings.get(filter);
10086 if (b != null && !b.received) {
10087 b.binder = service;
10088 b.requested = true;
10089 b.received = true;
10090 if (r.connections.size() > 0) {
10091 Iterator<ConnectionRecord> it
10092 = r.connections.values().iterator();
10093 while (it.hasNext()) {
10094 ConnectionRecord c = it.next();
10095 if (!filter.equals(c.binding.intent.intent)) {
10096 if (DEBUG_SERVICE) Log.v(
10097 TAG, "Not publishing to: " + c);
10098 if (DEBUG_SERVICE) Log.v(
10099 TAG, "Bound intent: " + c.binding.intent.intent);
10100 if (DEBUG_SERVICE) Log.v(
10101 TAG, "Published intent: " + intent);
10102 continue;
10103 }
10104 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10105 try {
10106 c.conn.connected(r.name, service);
10107 } catch (Exception e) {
10108 Log.w(TAG, "Failure sending service " + r.name +
10109 " to connection " + c.conn.asBinder() +
10110 " (in " + c.binding.client.processName + ")", e);
10111 }
10112 }
10113 }
10114 }
10115
10116 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10117
10118 Binder.restoreCallingIdentity(origId);
10119 }
10120 }
10121 }
10122
10123 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10124 // Refuse possible leaked file descriptors
10125 if (intent != null && intent.hasFileDescriptors() == true) {
10126 throw new IllegalArgumentException("File descriptors passed in Intent");
10127 }
10128
10129 synchronized(this) {
10130 if (!(token instanceof ServiceRecord)) {
10131 throw new IllegalArgumentException("Invalid service token");
10132 }
10133 ServiceRecord r = (ServiceRecord)token;
10134
10135 final long origId = Binder.clearCallingIdentity();
10136
10137 if (r != null) {
10138 Intent.FilterComparison filter
10139 = new Intent.FilterComparison(intent);
10140 IntentBindRecord b = r.bindings.get(filter);
10141 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10142 + " at " + b + ": apps="
10143 + (b != null ? b.apps.size() : 0));
10144 if (b != null) {
10145 if (b.apps.size() > 0) {
10146 // Applications have already bound since the last
10147 // unbind, so just rebind right here.
10148 requestServiceBindingLocked(r, b, true);
10149 } else {
10150 // Note to tell the service the next time there is
10151 // a new client.
10152 b.doRebind = true;
10153 }
10154 }
10155
10156 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10157
10158 Binder.restoreCallingIdentity(origId);
10159 }
10160 }
10161 }
10162
10163 public void serviceDoneExecuting(IBinder token) {
10164 synchronized(this) {
10165 if (!(token instanceof ServiceRecord)) {
10166 throw new IllegalArgumentException("Invalid service token");
10167 }
10168 ServiceRecord r = (ServiceRecord)token;
10169 boolean inStopping = mStoppingServices.contains(token);
10170 if (r != null) {
10171 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10172 + ": nesting=" + r.executeNesting
10173 + ", inStopping=" + inStopping);
10174 if (r != token) {
10175 Log.w(TAG, "Done executing service " + r.name
10176 + " with incorrect token: given " + token
10177 + ", expected " + r);
10178 return;
10179 }
10180
10181 final long origId = Binder.clearCallingIdentity();
10182 serviceDoneExecutingLocked(r, inStopping);
10183 Binder.restoreCallingIdentity(origId);
10184 } else {
10185 Log.w(TAG, "Done executing unknown service " + r.name
10186 + " with token " + token);
10187 }
10188 }
10189 }
10190
10191 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10192 r.executeNesting--;
10193 if (r.executeNesting <= 0 && r.app != null) {
10194 r.app.executingServices.remove(r);
10195 if (r.app.executingServices.size() == 0) {
10196 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10197 }
10198 if (inStopping) {
10199 mStoppingServices.remove(r);
10200 }
10201 updateOomAdjLocked(r.app);
10202 }
10203 }
10204
10205 void serviceTimeout(ProcessRecord proc) {
10206 synchronized(this) {
10207 if (proc.executingServices.size() == 0 || proc.thread == null) {
10208 return;
10209 }
10210 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10211 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10212 ServiceRecord timeout = null;
10213 long nextTime = 0;
10214 while (it.hasNext()) {
10215 ServiceRecord sr = it.next();
10216 if (sr.executingStart < maxTime) {
10217 timeout = sr;
10218 break;
10219 }
10220 if (sr.executingStart > nextTime) {
10221 nextTime = sr.executingStart;
10222 }
10223 }
10224 if (timeout != null && mLRUProcesses.contains(proc)) {
10225 Log.w(TAG, "Timeout executing service: " + timeout);
10226 appNotRespondingLocked(proc, null, "Executing service "
10227 + timeout.name);
10228 } else {
10229 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10230 msg.obj = proc;
10231 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10232 }
10233 }
10234 }
10235
10236 // =========================================================
10237 // BROADCASTS
10238 // =========================================================
10239
10240 private final List getStickies(String action, IntentFilter filter,
10241 List cur) {
10242 final ContentResolver resolver = mContext.getContentResolver();
10243 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10244 if (list == null) {
10245 return cur;
10246 }
10247 int N = list.size();
10248 for (int i=0; i<N; i++) {
10249 Intent intent = list.get(i);
10250 if (filter.match(resolver, intent, true, TAG) >= 0) {
10251 if (cur == null) {
10252 cur = new ArrayList<Intent>();
10253 }
10254 cur.add(intent);
10255 }
10256 }
10257 return cur;
10258 }
10259
10260 private final void scheduleBroadcastsLocked() {
10261 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10262 + mBroadcastsScheduled);
10263
10264 if (mBroadcastsScheduled) {
10265 return;
10266 }
10267 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10268 mBroadcastsScheduled = true;
10269 }
10270
10271 public Intent registerReceiver(IApplicationThread caller,
10272 IIntentReceiver receiver, IntentFilter filter, String permission) {
10273 synchronized(this) {
10274 ProcessRecord callerApp = null;
10275 if (caller != null) {
10276 callerApp = getRecordForAppLocked(caller);
10277 if (callerApp == null) {
10278 throw new SecurityException(
10279 "Unable to find app for caller " + caller
10280 + " (pid=" + Binder.getCallingPid()
10281 + ") when registering receiver " + receiver);
10282 }
10283 }
10284
10285 List allSticky = null;
10286
10287 // Look for any matching sticky broadcasts...
10288 Iterator actions = filter.actionsIterator();
10289 if (actions != null) {
10290 while (actions.hasNext()) {
10291 String action = (String)actions.next();
10292 allSticky = getStickies(action, filter, allSticky);
10293 }
10294 } else {
10295 allSticky = getStickies(null, filter, allSticky);
10296 }
10297
10298 // The first sticky in the list is returned directly back to
10299 // the client.
10300 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10301
10302 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10303 + ": " + sticky);
10304
10305 if (receiver == null) {
10306 return sticky;
10307 }
10308
10309 ReceiverList rl
10310 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10311 if (rl == null) {
10312 rl = new ReceiverList(this, callerApp,
10313 Binder.getCallingPid(),
10314 Binder.getCallingUid(), receiver);
10315 if (rl.app != null) {
10316 rl.app.receivers.add(rl);
10317 } else {
10318 try {
10319 receiver.asBinder().linkToDeath(rl, 0);
10320 } catch (RemoteException e) {
10321 return sticky;
10322 }
10323 rl.linkedToDeath = true;
10324 }
10325 mRegisteredReceivers.put(receiver.asBinder(), rl);
10326 }
10327 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10328 rl.add(bf);
10329 if (!bf.debugCheck()) {
10330 Log.w(TAG, "==> For Dynamic broadast");
10331 }
10332 mReceiverResolver.addFilter(bf);
10333
10334 // Enqueue broadcasts for all existing stickies that match
10335 // this filter.
10336 if (allSticky != null) {
10337 ArrayList receivers = new ArrayList();
10338 receivers.add(bf);
10339
10340 int N = allSticky.size();
10341 for (int i=0; i<N; i++) {
10342 Intent intent = (Intent)allSticky.get(i);
10343 BroadcastRecord r = new BroadcastRecord(intent, null,
10344 null, -1, -1, null, receivers, null, 0, null, null,
10345 false);
10346 if (mParallelBroadcasts.size() == 0) {
10347 scheduleBroadcastsLocked();
10348 }
10349 mParallelBroadcasts.add(r);
10350 }
10351 }
10352
10353 return sticky;
10354 }
10355 }
10356
10357 public void unregisterReceiver(IIntentReceiver receiver) {
10358 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10359
10360 boolean doNext = false;
10361
10362 synchronized(this) {
10363 ReceiverList rl
10364 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10365 if (rl != null) {
10366 if (rl.curBroadcast != null) {
10367 BroadcastRecord r = rl.curBroadcast;
10368 doNext = finishReceiverLocked(
10369 receiver.asBinder(), r.resultCode, r.resultData,
10370 r.resultExtras, r.resultAbort, true);
10371 }
10372
10373 if (rl.app != null) {
10374 rl.app.receivers.remove(rl);
10375 }
10376 removeReceiverLocked(rl);
10377 if (rl.linkedToDeath) {
10378 rl.linkedToDeath = false;
10379 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10380 }
10381 }
10382 }
10383
10384 if (!doNext) {
10385 return;
10386 }
10387
10388 final long origId = Binder.clearCallingIdentity();
10389 processNextBroadcast(false);
10390 trimApplications();
10391 Binder.restoreCallingIdentity(origId);
10392 }
10393
10394 void removeReceiverLocked(ReceiverList rl) {
10395 mRegisteredReceivers.remove(rl.receiver.asBinder());
10396 int N = rl.size();
10397 for (int i=0; i<N; i++) {
10398 mReceiverResolver.removeFilter(rl.get(i));
10399 }
10400 }
10401
10402 private final int broadcastIntentLocked(ProcessRecord callerApp,
10403 String callerPackage, Intent intent, String resolvedType,
10404 IIntentReceiver resultTo, int resultCode, String resultData,
10405 Bundle map, String requiredPermission,
10406 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10407 intent = new Intent(intent);
10408
10409 if (DEBUG_BROADCAST) Log.v(
10410 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10411 + " ordered=" + ordered);
10412 if ((resultTo != null) && !ordered) {
10413 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10414 }
10415
10416 // Handle special intents: if this broadcast is from the package
10417 // manager about a package being removed, we need to remove all of
10418 // its activities from the history stack.
10419 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10420 intent.getAction());
10421 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10422 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10423 || uidRemoved) {
10424 if (checkComponentPermission(
10425 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10426 callingPid, callingUid, -1)
10427 == PackageManager.PERMISSION_GRANTED) {
10428 if (uidRemoved) {
10429 final Bundle intentExtras = intent.getExtras();
10430 final int uid = intentExtras != null
10431 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10432 if (uid >= 0) {
10433 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10434 synchronized (bs) {
10435 bs.removeUidStatsLocked(uid);
10436 }
10437 }
10438 } else {
10439 Uri data = intent.getData();
10440 String ssp;
10441 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10442 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10443 uninstallPackageLocked(ssp,
10444 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10445 }
10446 }
10447 }
10448 } else {
10449 String msg = "Permission Denial: " + intent.getAction()
10450 + " broadcast from " + callerPackage + " (pid=" + callingPid
10451 + ", uid=" + callingUid + ")"
10452 + " requires "
10453 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10454 Log.w(TAG, msg);
10455 throw new SecurityException(msg);
10456 }
10457 }
10458
10459 /*
10460 * If this is the time zone changed action, queue up a message that will reset the timezone
10461 * of all currently running processes. This message will get queued up before the broadcast
10462 * happens.
10463 */
10464 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10465 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10466 }
10467
10468 // Add to the sticky list if requested.
10469 if (sticky) {
10470 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10471 callingPid, callingUid)
10472 != PackageManager.PERMISSION_GRANTED) {
10473 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10474 + callingPid + ", uid=" + callingUid
10475 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10476 Log.w(TAG, msg);
10477 throw new SecurityException(msg);
10478 }
10479 if (requiredPermission != null) {
10480 Log.w(TAG, "Can't broadcast sticky intent " + intent
10481 + " and enforce permission " + requiredPermission);
10482 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10483 }
10484 if (intent.getComponent() != null) {
10485 throw new SecurityException(
10486 "Sticky broadcasts can't target a specific component");
10487 }
10488 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10489 if (list == null) {
10490 list = new ArrayList<Intent>();
10491 mStickyBroadcasts.put(intent.getAction(), list);
10492 }
10493 int N = list.size();
10494 int i;
10495 for (i=0; i<N; i++) {
10496 if (intent.filterEquals(list.get(i))) {
10497 // This sticky already exists, replace it.
10498 list.set(i, new Intent(intent));
10499 break;
10500 }
10501 }
10502 if (i >= N) {
10503 list.add(new Intent(intent));
10504 }
10505 }
10506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010507 // Figure out who all will receive this broadcast.
10508 List receivers = null;
10509 List<BroadcastFilter> registeredReceivers = null;
10510 try {
10511 if (intent.getComponent() != null) {
10512 // Broadcast is going to one specific receiver class...
10513 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010514 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010515 if (ai != null) {
10516 receivers = new ArrayList();
10517 ResolveInfo ri = new ResolveInfo();
10518 ri.activityInfo = ai;
10519 receivers.add(ri);
10520 }
10521 } else {
10522 // Need to resolve the intent to interested receivers...
10523 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10524 == 0) {
10525 receivers =
10526 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010527 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010528 }
Mihai Preda074edef2009-05-18 17:13:31 +020010529 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010530 }
10531 } catch (RemoteException ex) {
10532 // pm is in same process, this will never happen.
10533 }
10534
10535 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10536 if (!ordered && NR > 0) {
10537 // If we are not serializing this broadcast, then send the
10538 // registered receivers separately so they don't wait for the
10539 // components to be launched.
10540 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10541 callerPackage, callingPid, callingUid, requiredPermission,
10542 registeredReceivers, resultTo, resultCode, resultData, map,
10543 ordered);
10544 if (DEBUG_BROADCAST) Log.v(
10545 TAG, "Enqueueing parallel broadcast " + r
10546 + ": prev had " + mParallelBroadcasts.size());
10547 mParallelBroadcasts.add(r);
10548 scheduleBroadcastsLocked();
10549 registeredReceivers = null;
10550 NR = 0;
10551 }
10552
10553 // Merge into one list.
10554 int ir = 0;
10555 if (receivers != null) {
10556 // A special case for PACKAGE_ADDED: do not allow the package
10557 // being added to see this broadcast. This prevents them from
10558 // using this as a back door to get run as soon as they are
10559 // installed. Maybe in the future we want to have a special install
10560 // broadcast or such for apps, but we'd like to deliberately make
10561 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010562 boolean skip = false;
10563 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010564 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010565 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10566 skip = true;
10567 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10568 skip = true;
10569 }
10570 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 ? intent.getData().getSchemeSpecificPart()
10572 : null;
10573 if (skipPackage != null && receivers != null) {
10574 int NT = receivers.size();
10575 for (int it=0; it<NT; it++) {
10576 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10577 if (curt.activityInfo.packageName.equals(skipPackage)) {
10578 receivers.remove(it);
10579 it--;
10580 NT--;
10581 }
10582 }
10583 }
10584
10585 int NT = receivers != null ? receivers.size() : 0;
10586 int it = 0;
10587 ResolveInfo curt = null;
10588 BroadcastFilter curr = null;
10589 while (it < NT && ir < NR) {
10590 if (curt == null) {
10591 curt = (ResolveInfo)receivers.get(it);
10592 }
10593 if (curr == null) {
10594 curr = registeredReceivers.get(ir);
10595 }
10596 if (curr.getPriority() >= curt.priority) {
10597 // Insert this broadcast record into the final list.
10598 receivers.add(it, curr);
10599 ir++;
10600 curr = null;
10601 it++;
10602 NT++;
10603 } else {
10604 // Skip to the next ResolveInfo in the final list.
10605 it++;
10606 curt = null;
10607 }
10608 }
10609 }
10610 while (ir < NR) {
10611 if (receivers == null) {
10612 receivers = new ArrayList();
10613 }
10614 receivers.add(registeredReceivers.get(ir));
10615 ir++;
10616 }
10617
10618 if ((receivers != null && receivers.size() > 0)
10619 || resultTo != null) {
10620 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10621 callerPackage, callingPid, callingUid, requiredPermission,
10622 receivers, resultTo, resultCode, resultData, map, ordered);
10623 if (DEBUG_BROADCAST) Log.v(
10624 TAG, "Enqueueing ordered broadcast " + r
10625 + ": prev had " + mOrderedBroadcasts.size());
10626 if (DEBUG_BROADCAST) {
10627 int seq = r.intent.getIntExtra("seq", -1);
10628 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10629 }
10630 mOrderedBroadcasts.add(r);
10631 scheduleBroadcastsLocked();
10632 }
10633
10634 return BROADCAST_SUCCESS;
10635 }
10636
10637 public final int broadcastIntent(IApplicationThread caller,
10638 Intent intent, String resolvedType, IIntentReceiver resultTo,
10639 int resultCode, String resultData, Bundle map,
10640 String requiredPermission, boolean serialized, boolean sticky) {
10641 // Refuse possible leaked file descriptors
10642 if (intent != null && intent.hasFileDescriptors() == true) {
10643 throw new IllegalArgumentException("File descriptors passed in Intent");
10644 }
10645
10646 synchronized(this) {
10647 if (!mSystemReady) {
10648 // if the caller really truly claims to know what they're doing, go
10649 // ahead and allow the broadcast without launching any receivers
10650 int flags = intent.getFlags();
10651 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10652 intent = new Intent(intent);
10653 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10654 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10655 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10656 + " before boot completion");
10657 throw new IllegalStateException("Cannot broadcast before boot completed");
10658 }
10659 }
10660
10661 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10662 final int callingPid = Binder.getCallingPid();
10663 final int callingUid = Binder.getCallingUid();
10664 final long origId = Binder.clearCallingIdentity();
10665 int res = broadcastIntentLocked(callerApp,
10666 callerApp != null ? callerApp.info.packageName : null,
10667 intent, resolvedType, resultTo,
10668 resultCode, resultData, map, requiredPermission, serialized,
10669 sticky, callingPid, callingUid);
10670 Binder.restoreCallingIdentity(origId);
10671 return res;
10672 }
10673 }
10674
10675 int broadcastIntentInPackage(String packageName, int uid,
10676 Intent intent, String resolvedType, IIntentReceiver resultTo,
10677 int resultCode, String resultData, Bundle map,
10678 String requiredPermission, boolean serialized, boolean sticky) {
10679 synchronized(this) {
10680 final long origId = Binder.clearCallingIdentity();
10681 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10682 resultTo, resultCode, resultData, map, requiredPermission,
10683 serialized, sticky, -1, uid);
10684 Binder.restoreCallingIdentity(origId);
10685 return res;
10686 }
10687 }
10688
10689 public final void unbroadcastIntent(IApplicationThread caller,
10690 Intent intent) {
10691 // Refuse possible leaked file descriptors
10692 if (intent != null && intent.hasFileDescriptors() == true) {
10693 throw new IllegalArgumentException("File descriptors passed in Intent");
10694 }
10695
10696 synchronized(this) {
10697 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10698 != PackageManager.PERMISSION_GRANTED) {
10699 String msg = "Permission Denial: unbroadcastIntent() from pid="
10700 + Binder.getCallingPid()
10701 + ", uid=" + Binder.getCallingUid()
10702 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10703 Log.w(TAG, msg);
10704 throw new SecurityException(msg);
10705 }
10706 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10707 if (list != null) {
10708 int N = list.size();
10709 int i;
10710 for (i=0; i<N; i++) {
10711 if (intent.filterEquals(list.get(i))) {
10712 list.remove(i);
10713 break;
10714 }
10715 }
10716 }
10717 }
10718 }
10719
10720 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10721 String resultData, Bundle resultExtras, boolean resultAbort,
10722 boolean explicit) {
10723 if (mOrderedBroadcasts.size() == 0) {
10724 if (explicit) {
10725 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10726 }
10727 return false;
10728 }
10729 BroadcastRecord r = mOrderedBroadcasts.get(0);
10730 if (r.receiver == null) {
10731 if (explicit) {
10732 Log.w(TAG, "finishReceiver called but none active");
10733 }
10734 return false;
10735 }
10736 if (r.receiver != receiver) {
10737 Log.w(TAG, "finishReceiver called but active receiver is different");
10738 return false;
10739 }
10740 int state = r.state;
10741 r.state = r.IDLE;
10742 if (state == r.IDLE) {
10743 if (explicit) {
10744 Log.w(TAG, "finishReceiver called but state is IDLE");
10745 }
10746 }
10747 r.receiver = null;
10748 r.intent.setComponent(null);
10749 if (r.curApp != null) {
10750 r.curApp.curReceiver = null;
10751 }
10752 if (r.curFilter != null) {
10753 r.curFilter.receiverList.curBroadcast = null;
10754 }
10755 r.curFilter = null;
10756 r.curApp = null;
10757 r.curComponent = null;
10758 r.curReceiver = null;
10759 mPendingBroadcast = null;
10760
10761 r.resultCode = resultCode;
10762 r.resultData = resultData;
10763 r.resultExtras = resultExtras;
10764 r.resultAbort = resultAbort;
10765
10766 // We will process the next receiver right now if this is finishing
10767 // an app receiver (which is always asynchronous) or after we have
10768 // come back from calling a receiver.
10769 return state == BroadcastRecord.APP_RECEIVE
10770 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10771 }
10772
10773 public void finishReceiver(IBinder who, int resultCode, String resultData,
10774 Bundle resultExtras, boolean resultAbort) {
10775 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10776
10777 // Refuse possible leaked file descriptors
10778 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10779 throw new IllegalArgumentException("File descriptors passed in Bundle");
10780 }
10781
10782 boolean doNext;
10783
10784 final long origId = Binder.clearCallingIdentity();
10785
10786 synchronized(this) {
10787 doNext = finishReceiverLocked(
10788 who, resultCode, resultData, resultExtras, resultAbort, true);
10789 }
10790
10791 if (doNext) {
10792 processNextBroadcast(false);
10793 }
10794 trimApplications();
10795
10796 Binder.restoreCallingIdentity(origId);
10797 }
10798
10799 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10800 if (r.nextReceiver > 0) {
10801 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10802 if (curReceiver instanceof BroadcastFilter) {
10803 BroadcastFilter bf = (BroadcastFilter) curReceiver;
10804 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
10805 System.identityHashCode(r),
10806 r.intent.getAction(),
10807 r.nextReceiver - 1,
10808 System.identityHashCode(bf));
10809 } else {
10810 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10811 System.identityHashCode(r),
10812 r.intent.getAction(),
10813 r.nextReceiver - 1,
10814 ((ResolveInfo)curReceiver).toString());
10815 }
10816 } else {
10817 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
10818 + r);
10819 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10820 System.identityHashCode(r),
10821 r.intent.getAction(),
10822 r.nextReceiver,
10823 "NONE");
10824 }
10825 }
10826
10827 private final void broadcastTimeout() {
10828 synchronized (this) {
10829 if (mOrderedBroadcasts.size() == 0) {
10830 return;
10831 }
10832 long now = SystemClock.uptimeMillis();
10833 BroadcastRecord r = mOrderedBroadcasts.get(0);
10834 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
10835 if (DEBUG_BROADCAST) Log.v(TAG,
10836 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
10837 + (r.startTime + BROADCAST_TIMEOUT));
10838 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
10839 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
10840 return;
10841 }
10842
10843 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
10844 r.startTime = now;
10845 r.anrCount++;
10846
10847 // Current receiver has passed its expiration date.
10848 if (r.nextReceiver <= 0) {
10849 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
10850 return;
10851 }
10852
10853 ProcessRecord app = null;
10854
10855 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10856 Log.w(TAG, "Receiver during timeout: " + curReceiver);
10857 logBroadcastReceiverDiscard(r);
10858 if (curReceiver instanceof BroadcastFilter) {
10859 BroadcastFilter bf = (BroadcastFilter)curReceiver;
10860 if (bf.receiverList.pid != 0
10861 && bf.receiverList.pid != MY_PID) {
10862 synchronized (this.mPidsSelfLocked) {
10863 app = this.mPidsSelfLocked.get(
10864 bf.receiverList.pid);
10865 }
10866 }
10867 } else {
10868 app = r.curApp;
10869 }
10870
10871 if (app != null) {
10872 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
10873 }
10874
10875 if (mPendingBroadcast == r) {
10876 mPendingBroadcast = null;
10877 }
10878
10879 // Move on to the next receiver.
10880 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
10881 r.resultExtras, r.resultAbort, true);
10882 scheduleBroadcastsLocked();
10883 }
10884 }
10885
10886 private final void processCurBroadcastLocked(BroadcastRecord r,
10887 ProcessRecord app) throws RemoteException {
10888 if (app.thread == null) {
10889 throw new RemoteException();
10890 }
10891 r.receiver = app.thread.asBinder();
10892 r.curApp = app;
10893 app.curReceiver = r;
10894 updateLRUListLocked(app, true);
10895
10896 // Tell the application to launch this receiver.
10897 r.intent.setComponent(r.curComponent);
10898
10899 boolean started = false;
10900 try {
10901 if (DEBUG_BROADCAST) Log.v(TAG,
10902 "Delivering to component " + r.curComponent
10903 + ": " + r);
10904 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
10905 r.resultCode, r.resultData, r.resultExtras, r.ordered);
10906 started = true;
10907 } finally {
10908 if (!started) {
10909 r.receiver = null;
10910 r.curApp = null;
10911 app.curReceiver = null;
10912 }
10913 }
10914
10915 }
10916
10917 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
10918 Intent intent, int resultCode, String data,
10919 Bundle extras, boolean ordered) throws RemoteException {
10920 if (app != null && app.thread != null) {
10921 // If we have an app thread, do the call through that so it is
10922 // correctly ordered with other one-way calls.
10923 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
10924 data, extras, ordered);
10925 } else {
10926 receiver.performReceive(intent, resultCode, data, extras, ordered);
10927 }
10928 }
10929
10930 private final void deliverToRegisteredReceiver(BroadcastRecord r,
10931 BroadcastFilter filter, boolean ordered) {
10932 boolean skip = false;
10933 if (filter.requiredPermission != null) {
10934 int perm = checkComponentPermission(filter.requiredPermission,
10935 r.callingPid, r.callingUid, -1);
10936 if (perm != PackageManager.PERMISSION_GRANTED) {
10937 Log.w(TAG, "Permission Denial: broadcasting "
10938 + r.intent.toString()
10939 + " from " + r.callerPackage + " (pid="
10940 + r.callingPid + ", uid=" + r.callingUid + ")"
10941 + " requires " + filter.requiredPermission
10942 + " due to registered receiver " + filter);
10943 skip = true;
10944 }
10945 }
10946 if (r.requiredPermission != null) {
10947 int perm = checkComponentPermission(r.requiredPermission,
10948 filter.receiverList.pid, filter.receiverList.uid, -1);
10949 if (perm != PackageManager.PERMISSION_GRANTED) {
10950 Log.w(TAG, "Permission Denial: receiving "
10951 + r.intent.toString()
10952 + " to " + filter.receiverList.app
10953 + " (pid=" + filter.receiverList.pid
10954 + ", uid=" + filter.receiverList.uid + ")"
10955 + " requires " + r.requiredPermission
10956 + " due to sender " + r.callerPackage
10957 + " (uid " + r.callingUid + ")");
10958 skip = true;
10959 }
10960 }
10961
10962 if (!skip) {
10963 // If this is not being sent as an ordered broadcast, then we
10964 // don't want to touch the fields that keep track of the current
10965 // state of ordered broadcasts.
10966 if (ordered) {
10967 r.receiver = filter.receiverList.receiver.asBinder();
10968 r.curFilter = filter;
10969 filter.receiverList.curBroadcast = r;
10970 r.state = BroadcastRecord.CALL_IN_RECEIVE;
10971 }
10972 try {
10973 if (DEBUG_BROADCAST) {
10974 int seq = r.intent.getIntExtra("seq", -1);
10975 Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
10976 + " app=" + filter.receiverList.app);
10977 }
10978 performReceive(filter.receiverList.app, filter.receiverList.receiver,
10979 new Intent(r.intent), r.resultCode,
10980 r.resultData, r.resultExtras, r.ordered);
10981 if (ordered) {
10982 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
10983 }
10984 } catch (RemoteException e) {
10985 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
10986 if (ordered) {
10987 r.receiver = null;
10988 r.curFilter = null;
10989 filter.receiverList.curBroadcast = null;
10990 }
10991 }
10992 }
10993 }
10994
10995 private final void processNextBroadcast(boolean fromMsg) {
10996 synchronized(this) {
10997 BroadcastRecord r;
10998
10999 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11000 + mParallelBroadcasts.size() + " broadcasts, "
11001 + mOrderedBroadcasts.size() + " serialized broadcasts");
11002
11003 updateCpuStats();
11004
11005 if (fromMsg) {
11006 mBroadcastsScheduled = false;
11007 }
11008
11009 // First, deliver any non-serialized broadcasts right away.
11010 while (mParallelBroadcasts.size() > 0) {
11011 r = mParallelBroadcasts.remove(0);
11012 final int N = r.receivers.size();
11013 for (int i=0; i<N; i++) {
11014 Object target = r.receivers.get(i);
11015 if (DEBUG_BROADCAST) Log.v(TAG,
11016 "Delivering non-serialized to registered "
11017 + target + ": " + r);
11018 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11019 }
11020 }
11021
11022 // Now take care of the next serialized one...
11023
11024 // If we are waiting for a process to come up to handle the next
11025 // broadcast, then do nothing at this point. Just in case, we
11026 // check that the process we're waiting for still exists.
11027 if (mPendingBroadcast != null) {
11028 Log.i(TAG, "processNextBroadcast: waiting for "
11029 + mPendingBroadcast.curApp);
11030
11031 boolean isDead;
11032 synchronized (mPidsSelfLocked) {
11033 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11034 }
11035 if (!isDead) {
11036 // It's still alive, so keep waiting
11037 return;
11038 } else {
11039 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11040 + " died before responding to broadcast");
11041 mPendingBroadcast = null;
11042 }
11043 }
11044
11045 do {
11046 if (mOrderedBroadcasts.size() == 0) {
11047 // No more broadcasts pending, so all done!
11048 scheduleAppGcsLocked();
11049 return;
11050 }
11051 r = mOrderedBroadcasts.get(0);
11052 boolean forceReceive = false;
11053
11054 // Ensure that even if something goes awry with the timeout
11055 // detection, we catch "hung" broadcasts here, discard them,
11056 // and continue to make progress.
11057 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11058 long now = SystemClock.uptimeMillis();
11059 if (r.dispatchTime > 0) {
11060 if ((numReceivers > 0) &&
11061 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11062 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11063 + " now=" + now
11064 + " dispatchTime=" + r.dispatchTime
11065 + " startTime=" + r.startTime
11066 + " intent=" + r.intent
11067 + " numReceivers=" + numReceivers
11068 + " nextReceiver=" + r.nextReceiver
11069 + " state=" + r.state);
11070 broadcastTimeout(); // forcibly finish this broadcast
11071 forceReceive = true;
11072 r.state = BroadcastRecord.IDLE;
11073 }
11074 }
11075
11076 if (r.state != BroadcastRecord.IDLE) {
11077 if (DEBUG_BROADCAST) Log.d(TAG,
11078 "processNextBroadcast() called when not idle (state="
11079 + r.state + ")");
11080 return;
11081 }
11082
11083 if (r.receivers == null || r.nextReceiver >= numReceivers
11084 || r.resultAbort || forceReceive) {
11085 // No more receivers for this broadcast! Send the final
11086 // result if requested...
11087 if (r.resultTo != null) {
11088 try {
11089 if (DEBUG_BROADCAST) {
11090 int seq = r.intent.getIntExtra("seq", -1);
11091 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11092 + " seq=" + seq + " app=" + r.callerApp);
11093 }
11094 performReceive(r.callerApp, r.resultTo,
11095 new Intent(r.intent), r.resultCode,
11096 r.resultData, r.resultExtras, false);
11097 } catch (RemoteException e) {
11098 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11099 }
11100 }
11101
11102 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11103 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11104
11105 // ... and on to the next...
11106 mOrderedBroadcasts.remove(0);
11107 r = null;
11108 continue;
11109 }
11110 } while (r == null);
11111
11112 // Get the next receiver...
11113 int recIdx = r.nextReceiver++;
11114
11115 // Keep track of when this receiver started, and make sure there
11116 // is a timeout message pending to kill it if need be.
11117 r.startTime = SystemClock.uptimeMillis();
11118 if (recIdx == 0) {
11119 r.dispatchTime = r.startTime;
11120
11121 if (DEBUG_BROADCAST) Log.v(TAG,
11122 "Submitting BROADCAST_TIMEOUT_MSG for "
11123 + (r.startTime + BROADCAST_TIMEOUT));
11124 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11125 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11126 }
11127
11128 Object nextReceiver = r.receivers.get(recIdx);
11129 if (nextReceiver instanceof BroadcastFilter) {
11130 // Simple case: this is a registered receiver who gets
11131 // a direct call.
11132 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11133 if (DEBUG_BROADCAST) Log.v(TAG,
11134 "Delivering serialized to registered "
11135 + filter + ": " + r);
11136 deliverToRegisteredReceiver(r, filter, r.ordered);
11137 if (r.receiver == null || !r.ordered) {
11138 // The receiver has already finished, so schedule to
11139 // process the next one.
11140 r.state = BroadcastRecord.IDLE;
11141 scheduleBroadcastsLocked();
11142 }
11143 return;
11144 }
11145
11146 // Hard case: need to instantiate the receiver, possibly
11147 // starting its application process to host it.
11148
11149 ResolveInfo info =
11150 (ResolveInfo)nextReceiver;
11151
11152 boolean skip = false;
11153 int perm = checkComponentPermission(info.activityInfo.permission,
11154 r.callingPid, r.callingUid,
11155 info.activityInfo.exported
11156 ? -1 : info.activityInfo.applicationInfo.uid);
11157 if (perm != PackageManager.PERMISSION_GRANTED) {
11158 Log.w(TAG, "Permission Denial: broadcasting "
11159 + r.intent.toString()
11160 + " from " + r.callerPackage + " (pid=" + r.callingPid
11161 + ", uid=" + r.callingUid + ")"
11162 + " requires " + info.activityInfo.permission
11163 + " due to receiver " + info.activityInfo.packageName
11164 + "/" + info.activityInfo.name);
11165 skip = true;
11166 }
11167 if (r.callingUid != Process.SYSTEM_UID &&
11168 r.requiredPermission != null) {
11169 try {
11170 perm = ActivityThread.getPackageManager().
11171 checkPermission(r.requiredPermission,
11172 info.activityInfo.applicationInfo.packageName);
11173 } catch (RemoteException e) {
11174 perm = PackageManager.PERMISSION_DENIED;
11175 }
11176 if (perm != PackageManager.PERMISSION_GRANTED) {
11177 Log.w(TAG, "Permission Denial: receiving "
11178 + r.intent + " to "
11179 + info.activityInfo.applicationInfo.packageName
11180 + " requires " + r.requiredPermission
11181 + " due to sender " + r.callerPackage
11182 + " (uid " + r.callingUid + ")");
11183 skip = true;
11184 }
11185 }
11186 if (r.curApp != null && r.curApp.crashing) {
11187 // If the target process is crashing, just skip it.
11188 skip = true;
11189 }
11190
11191 if (skip) {
11192 r.receiver = null;
11193 r.curFilter = null;
11194 r.state = BroadcastRecord.IDLE;
11195 scheduleBroadcastsLocked();
11196 return;
11197 }
11198
11199 r.state = BroadcastRecord.APP_RECEIVE;
11200 String targetProcess = info.activityInfo.processName;
11201 r.curComponent = new ComponentName(
11202 info.activityInfo.applicationInfo.packageName,
11203 info.activityInfo.name);
11204 r.curReceiver = info.activityInfo;
11205
11206 // Is this receiver's application already running?
11207 ProcessRecord app = getProcessRecordLocked(targetProcess,
11208 info.activityInfo.applicationInfo.uid);
11209 if (app != null && app.thread != null) {
11210 try {
11211 processCurBroadcastLocked(r, app);
11212 return;
11213 } catch (RemoteException e) {
11214 Log.w(TAG, "Exception when sending broadcast to "
11215 + r.curComponent, e);
11216 }
11217
11218 // If a dead object exception was thrown -- fall through to
11219 // restart the application.
11220 }
11221
11222 // Not running -- get it started, and enqueue this history record
11223 // to be executed when the app comes up.
11224 if ((r.curApp=startProcessLocked(targetProcess,
11225 info.activityInfo.applicationInfo, true,
11226 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11227 "broadcast", r.curComponent)) == null) {
11228 // Ah, this recipient is unavailable. Finish it if necessary,
11229 // and mark the broadcast record as ready for the next.
11230 Log.w(TAG, "Unable to launch app "
11231 + info.activityInfo.applicationInfo.packageName + "/"
11232 + info.activityInfo.applicationInfo.uid + " for broadcast "
11233 + r.intent + ": process is bad");
11234 logBroadcastReceiverDiscard(r);
11235 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11236 r.resultExtras, r.resultAbort, true);
11237 scheduleBroadcastsLocked();
11238 r.state = BroadcastRecord.IDLE;
11239 return;
11240 }
11241
11242 mPendingBroadcast = r;
11243 }
11244 }
11245
11246 // =========================================================
11247 // INSTRUMENTATION
11248 // =========================================================
11249
11250 public boolean startInstrumentation(ComponentName className,
11251 String profileFile, int flags, Bundle arguments,
11252 IInstrumentationWatcher watcher) {
11253 // Refuse possible leaked file descriptors
11254 if (arguments != null && arguments.hasFileDescriptors()) {
11255 throw new IllegalArgumentException("File descriptors passed in Bundle");
11256 }
11257
11258 synchronized(this) {
11259 InstrumentationInfo ii = null;
11260 ApplicationInfo ai = null;
11261 try {
11262 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011263 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011264 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011265 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011266 } catch (PackageManager.NameNotFoundException e) {
11267 }
11268 if (ii == null) {
11269 reportStartInstrumentationFailure(watcher, className,
11270 "Unable to find instrumentation info for: " + className);
11271 return false;
11272 }
11273 if (ai == null) {
11274 reportStartInstrumentationFailure(watcher, className,
11275 "Unable to find instrumentation target package: " + ii.targetPackage);
11276 return false;
11277 }
11278
11279 int match = mContext.getPackageManager().checkSignatures(
11280 ii.targetPackage, ii.packageName);
11281 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11282 String msg = "Permission Denial: starting instrumentation "
11283 + className + " from pid="
11284 + Binder.getCallingPid()
11285 + ", uid=" + Binder.getCallingPid()
11286 + " not allowed because package " + ii.packageName
11287 + " does not have a signature matching the target "
11288 + ii.targetPackage;
11289 reportStartInstrumentationFailure(watcher, className, msg);
11290 throw new SecurityException(msg);
11291 }
11292
11293 final long origId = Binder.clearCallingIdentity();
11294 uninstallPackageLocked(ii.targetPackage, -1, true);
11295 ProcessRecord app = addAppLocked(ai);
11296 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011297 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011298 app.instrumentationProfileFile = profileFile;
11299 app.instrumentationArguments = arguments;
11300 app.instrumentationWatcher = watcher;
11301 app.instrumentationResultClass = className;
11302 Binder.restoreCallingIdentity(origId);
11303 }
11304
11305 return true;
11306 }
11307
11308 /**
11309 * Report errors that occur while attempting to start Instrumentation. Always writes the
11310 * error to the logs, but if somebody is watching, send the report there too. This enables
11311 * the "am" command to report errors with more information.
11312 *
11313 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11314 * @param cn The component name of the instrumentation.
11315 * @param report The error report.
11316 */
11317 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11318 ComponentName cn, String report) {
11319 Log.w(TAG, report);
11320 try {
11321 if (watcher != null) {
11322 Bundle results = new Bundle();
11323 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11324 results.putString("Error", report);
11325 watcher.instrumentationStatus(cn, -1, results);
11326 }
11327 } catch (RemoteException e) {
11328 Log.w(TAG, e);
11329 }
11330 }
11331
11332 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11333 if (app.instrumentationWatcher != null) {
11334 try {
11335 // NOTE: IInstrumentationWatcher *must* be oneway here
11336 app.instrumentationWatcher.instrumentationFinished(
11337 app.instrumentationClass,
11338 resultCode,
11339 results);
11340 } catch (RemoteException e) {
11341 }
11342 }
11343 app.instrumentationWatcher = null;
11344 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011345 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011346 app.instrumentationProfileFile = null;
11347 app.instrumentationArguments = null;
11348
11349 uninstallPackageLocked(app.processName, -1, false);
11350 }
11351
11352 public void finishInstrumentation(IApplicationThread target,
11353 int resultCode, Bundle results) {
11354 // Refuse possible leaked file descriptors
11355 if (results != null && results.hasFileDescriptors()) {
11356 throw new IllegalArgumentException("File descriptors passed in Intent");
11357 }
11358
11359 synchronized(this) {
11360 ProcessRecord app = getRecordForAppLocked(target);
11361 if (app == null) {
11362 Log.w(TAG, "finishInstrumentation: no app for " + target);
11363 return;
11364 }
11365 final long origId = Binder.clearCallingIdentity();
11366 finishInstrumentationLocked(app, resultCode, results);
11367 Binder.restoreCallingIdentity(origId);
11368 }
11369 }
11370
11371 // =========================================================
11372 // CONFIGURATION
11373 // =========================================================
11374
11375 public ConfigurationInfo getDeviceConfigurationInfo() {
11376 ConfigurationInfo config = new ConfigurationInfo();
11377 synchronized (this) {
11378 config.reqTouchScreen = mConfiguration.touchscreen;
11379 config.reqKeyboardType = mConfiguration.keyboard;
11380 config.reqNavigation = mConfiguration.navigation;
11381 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11382 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11383 }
11384 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11385 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11386 }
11387 }
11388 return config;
11389 }
11390
11391 public Configuration getConfiguration() {
11392 Configuration ci;
11393 synchronized(this) {
11394 ci = new Configuration(mConfiguration);
11395 }
11396 return ci;
11397 }
11398
11399 public void updateConfiguration(Configuration values) {
11400 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11401 "updateConfiguration()");
11402
11403 synchronized(this) {
11404 if (values == null && mWindowManager != null) {
11405 // sentinel: fetch the current configuration from the window manager
11406 values = mWindowManager.computeNewConfiguration();
11407 }
11408
11409 final long origId = Binder.clearCallingIdentity();
11410 updateConfigurationLocked(values, null);
11411 Binder.restoreCallingIdentity(origId);
11412 }
11413 }
11414
11415 /**
11416 * Do either or both things: (1) change the current configuration, and (2)
11417 * make sure the given activity is running with the (now) current
11418 * configuration. Returns true if the activity has been left running, or
11419 * false if <var>starting</var> is being destroyed to match the new
11420 * configuration.
11421 */
11422 public boolean updateConfigurationLocked(Configuration values,
11423 HistoryRecord starting) {
11424 int changes = 0;
11425
11426 boolean kept = true;
11427
11428 if (values != null) {
11429 Configuration newConfig = new Configuration(mConfiguration);
11430 changes = newConfig.updateFrom(values);
11431 if (changes != 0) {
11432 if (DEBUG_SWITCH) {
11433 Log.i(TAG, "Updating configuration to: " + values);
11434 }
11435
11436 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11437
11438 if (values.locale != null) {
11439 saveLocaleLocked(values.locale,
11440 !values.locale.equals(mConfiguration.locale),
11441 values.userSetLocale);
11442 }
11443
11444 mConfiguration = newConfig;
11445
11446 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11447 msg.obj = new Configuration(mConfiguration);
11448 mHandler.sendMessage(msg);
11449
11450 final int N = mLRUProcesses.size();
11451 for (int i=0; i<N; i++) {
11452 ProcessRecord app = mLRUProcesses.get(i);
11453 try {
11454 if (app.thread != null) {
11455 app.thread.scheduleConfigurationChanged(mConfiguration);
11456 }
11457 } catch (Exception e) {
11458 }
11459 }
11460 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11461 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11462 null, false, false, MY_PID, Process.SYSTEM_UID);
11463 }
11464 }
11465
11466 if (changes != 0 && starting == null) {
11467 // If the configuration changed, and the caller is not already
11468 // in the process of starting an activity, then find the top
11469 // activity to check if its configuration needs to change.
11470 starting = topRunningActivityLocked(null);
11471 }
11472
11473 if (starting != null) {
11474 kept = ensureActivityConfigurationLocked(starting, changes);
11475 if (kept) {
11476 // If this didn't result in the starting activity being
11477 // destroyed, then we need to make sure at this point that all
11478 // other activities are made visible.
11479 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11480 + ", ensuring others are correct.");
11481 ensureActivitiesVisibleLocked(starting, changes);
11482 }
11483 }
11484
11485 return kept;
11486 }
11487
11488 private final boolean relaunchActivityLocked(HistoryRecord r,
11489 int changes, boolean andResume) {
11490 List<ResultInfo> results = null;
11491 List<Intent> newIntents = null;
11492 if (andResume) {
11493 results = r.results;
11494 newIntents = r.newIntents;
11495 }
11496 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11497 + " with results=" + results + " newIntents=" + newIntents
11498 + " andResume=" + andResume);
11499 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11500 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11501 r.task.taskId, r.shortComponentName);
11502
11503 r.startFreezingScreenLocked(r.app, 0);
11504
11505 try {
11506 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11507 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11508 changes, !andResume);
11509 // Note: don't need to call pauseIfSleepingLocked() here, because
11510 // the caller will only pass in 'andResume' if this activity is
11511 // currently resumed, which implies we aren't sleeping.
11512 } catch (RemoteException e) {
11513 return false;
11514 }
11515
11516 if (andResume) {
11517 r.results = null;
11518 r.newIntents = null;
11519 }
11520
11521 return true;
11522 }
11523
11524 /**
11525 * Make sure the given activity matches the current configuration. Returns
11526 * false if the activity had to be destroyed. Returns true if the
11527 * configuration is the same, or the activity will remain running as-is
11528 * for whatever reason. Ensures the HistoryRecord is updated with the
11529 * correct configuration and all other bookkeeping is handled.
11530 */
11531 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11532 int globalChanges) {
11533 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11534
11535 // Short circuit: if the two configurations are the exact same
11536 // object (the common case), then there is nothing to do.
11537 Configuration newConfig = mConfiguration;
11538 if (r.configuration == newConfig) {
11539 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11540 return true;
11541 }
11542
11543 // We don't worry about activities that are finishing.
11544 if (r.finishing) {
11545 if (DEBUG_SWITCH) Log.i(TAG,
11546 "Configuration doesn't matter in finishing " + r);
11547 r.stopFreezingScreenLocked(false);
11548 return true;
11549 }
11550
11551 // Okay we now are going to make this activity have the new config.
11552 // But then we need to figure out how it needs to deal with that.
11553 Configuration oldConfig = r.configuration;
11554 r.configuration = newConfig;
11555
11556 // If the activity isn't currently running, just leave the new
11557 // configuration and it will pick that up next time it starts.
11558 if (r.app == null || r.app.thread == null) {
11559 if (DEBUG_SWITCH) Log.i(TAG,
11560 "Configuration doesn't matter not running " + r);
11561 r.stopFreezingScreenLocked(false);
11562 return true;
11563 }
11564
11565 // If the activity isn't persistent, there is a chance we will
11566 // need to restart it.
11567 if (!r.persistent) {
11568
11569 // Figure out what has changed between the two configurations.
11570 int changes = oldConfig.diff(newConfig);
11571 if (DEBUG_SWITCH) {
11572 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11573 + Integer.toHexString(changes) + ", handles=0x"
11574 + Integer.toHexString(r.info.configChanges));
11575 }
11576 if ((changes&(~r.info.configChanges)) != 0) {
11577 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11578 r.configChangeFlags |= changes;
11579 r.startFreezingScreenLocked(r.app, globalChanges);
11580 if (r.app == null || r.app.thread == null) {
11581 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11582 destroyActivityLocked(r, true);
11583 } else if (r.state == ActivityState.PAUSING) {
11584 // A little annoying: we are waiting for this activity to
11585 // finish pausing. Let's not do anything now, but just
11586 // flag that it needs to be restarted when done pausing.
11587 r.configDestroy = true;
11588 return true;
11589 } else if (r.state == ActivityState.RESUMED) {
11590 // Try to optimize this case: the configuration is changing
11591 // and we need to restart the top, resumed activity.
11592 // Instead of doing the normal handshaking, just say
11593 // "restart!".
11594 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11595 relaunchActivityLocked(r, r.configChangeFlags, true);
11596 r.configChangeFlags = 0;
11597 } else {
11598 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11599 relaunchActivityLocked(r, r.configChangeFlags, false);
11600 r.configChangeFlags = 0;
11601 }
11602
11603 // All done... tell the caller we weren't able to keep this
11604 // activity around.
11605 return false;
11606 }
11607 }
11608
11609 // Default case: the activity can handle this new configuration, so
11610 // hand it over. Note that we don't need to give it the new
11611 // configuration, since we always send configuration changes to all
11612 // process when they happen so it can just use whatever configuration
11613 // it last got.
11614 if (r.app != null && r.app.thread != null) {
11615 try {
11616 r.app.thread.scheduleActivityConfigurationChanged(r);
11617 } catch (RemoteException e) {
11618 // If process died, whatever.
11619 }
11620 }
11621 r.stopFreezingScreenLocked(false);
11622
11623 return true;
11624 }
11625
11626 /**
11627 * Save the locale. You must be inside a synchronized (this) block.
11628 */
11629 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11630 if(isDiff) {
11631 SystemProperties.set("user.language", l.getLanguage());
11632 SystemProperties.set("user.region", l.getCountry());
11633 }
11634
11635 if(isPersist) {
11636 SystemProperties.set("persist.sys.language", l.getLanguage());
11637 SystemProperties.set("persist.sys.country", l.getCountry());
11638 SystemProperties.set("persist.sys.localevar", l.getVariant());
11639 }
11640 }
11641
11642 // =========================================================
11643 // LIFETIME MANAGEMENT
11644 // =========================================================
11645
11646 private final int computeOomAdjLocked(
11647 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11648 if (mAdjSeq == app.adjSeq) {
11649 // This adjustment has already been computed.
11650 return app.curAdj;
11651 }
11652
11653 if (app.thread == null) {
11654 app.adjSeq = mAdjSeq;
11655 return (app.curAdj=EMPTY_APP_ADJ);
11656 }
11657
11658 app.isForeground = false;
11659
The Android Open Source Project4df24232009-03-05 14:34:35 -080011660 // Determine the importance of the process, starting with most
11661 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011662 int adj;
11663 int N;
11664 if (app == TOP_APP || app.instrumentationClass != null
11665 || app.persistentActivities > 0) {
11666 // The last app on the list is the foreground app.
11667 adj = FOREGROUND_APP_ADJ;
11668 app.isForeground = true;
11669 } else if (app.curReceiver != null ||
11670 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11671 // An app that is currently receiving a broadcast also
11672 // counts as being in the foreground.
11673 adj = FOREGROUND_APP_ADJ;
11674 } else if (app.executingServices.size() > 0) {
11675 // An app that is currently executing a service callback also
11676 // counts as being in the foreground.
11677 adj = FOREGROUND_APP_ADJ;
11678 } else if (app.foregroundServices || app.forcingToForeground != null) {
11679 // The user is aware of this app, so make it visible.
11680 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011681 } else if (app == mHomeProcess) {
11682 // This process is hosting what we currently consider to be the
11683 // home app, so we don't want to let it go into the background.
11684 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011685 } else if ((N=app.activities.size()) != 0) {
11686 // This app is in the background with paused activities.
11687 adj = hiddenAdj;
11688 for (int j=0; j<N; j++) {
11689 if (((HistoryRecord)app.activities.get(j)).visible) {
11690 // This app has a visible activity!
11691 adj = VISIBLE_APP_ADJ;
11692 break;
11693 }
11694 }
11695 } else {
11696 // A very not-needed process.
11697 adj = EMPTY_APP_ADJ;
11698 }
11699
The Android Open Source Project4df24232009-03-05 14:34:35 -080011700 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011701 // there are applications dependent on our services or providers, but
11702 // this gives us a baseline and makes sure we don't get into an
11703 // infinite recursion.
11704 app.adjSeq = mAdjSeq;
11705 app.curRawAdj = adj;
11706 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11707
11708 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11709 // If this process has active services running in it, we would
11710 // like to avoid killing it unless it would prevent the current
11711 // application from running.
11712 if (adj > hiddenAdj) {
11713 adj = hiddenAdj;
11714 }
11715 final long now = SystemClock.uptimeMillis();
11716 // This process is more important if the top activity is
11717 // bound to the service.
11718 Iterator jt = app.services.iterator();
11719 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11720 ServiceRecord s = (ServiceRecord)jt.next();
11721 if (s.startRequested) {
11722 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11723 // This service has seen some activity within
11724 // recent memory, so we will keep its process ahead
11725 // of the background processes.
11726 if (adj > SECONDARY_SERVER_ADJ) {
11727 adj = SECONDARY_SERVER_ADJ;
11728 }
11729 } else {
11730 // This service has been inactive for too long, just
11731 // put it with the rest of the background processes.
11732 if (adj > hiddenAdj) {
11733 adj = hiddenAdj;
11734 }
11735 }
11736 }
11737 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11738 Iterator<ConnectionRecord> kt
11739 = s.connections.values().iterator();
11740 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11741 // XXX should compute this based on the max of
11742 // all connected clients.
11743 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011744 if (cr.binding.client == app) {
11745 // Binding to ourself is not interesting.
11746 continue;
11747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011748 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11749 ProcessRecord client = cr.binding.client;
11750 int myHiddenAdj = hiddenAdj;
11751 if (myHiddenAdj > client.hiddenAdj) {
11752 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11753 myHiddenAdj = client.hiddenAdj;
11754 } else {
11755 myHiddenAdj = VISIBLE_APP_ADJ;
11756 }
11757 }
11758 int clientAdj = computeOomAdjLocked(
11759 client, myHiddenAdj, TOP_APP);
11760 if (adj > clientAdj) {
11761 adj = clientAdj > VISIBLE_APP_ADJ
11762 ? clientAdj : VISIBLE_APP_ADJ;
11763 }
11764 }
11765 HistoryRecord a = cr.activity;
11766 //if (a != null) {
11767 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11768 //}
11769 if (a != null && adj > FOREGROUND_APP_ADJ &&
11770 (a.state == ActivityState.RESUMED
11771 || a.state == ActivityState.PAUSING)) {
11772 adj = FOREGROUND_APP_ADJ;
11773 }
11774 }
11775 }
11776 }
11777 }
11778
11779 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11780 // If this process has published any content providers, then
11781 // its adjustment makes it at least as important as any of the
11782 // processes using those providers, and no less important than
11783 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
11784 if (adj > CONTENT_PROVIDER_ADJ) {
11785 adj = CONTENT_PROVIDER_ADJ;
11786 }
11787 Iterator jt = app.pubProviders.values().iterator();
11788 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11789 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
11790 if (cpr.clients.size() != 0) {
11791 Iterator<ProcessRecord> kt = cpr.clients.iterator();
11792 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11793 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011794 if (client == app) {
11795 // Being our own client is not interesting.
11796 continue;
11797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011798 int myHiddenAdj = hiddenAdj;
11799 if (myHiddenAdj > client.hiddenAdj) {
11800 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
11801 myHiddenAdj = client.hiddenAdj;
11802 } else {
11803 myHiddenAdj = FOREGROUND_APP_ADJ;
11804 }
11805 }
11806 int clientAdj = computeOomAdjLocked(
11807 client, myHiddenAdj, TOP_APP);
11808 if (adj > clientAdj) {
11809 adj = clientAdj > FOREGROUND_APP_ADJ
11810 ? clientAdj : FOREGROUND_APP_ADJ;
11811 }
11812 }
11813 }
11814 // If the provider has external (non-framework) process
11815 // dependencies, ensure that its adjustment is at least
11816 // FOREGROUND_APP_ADJ.
11817 if (cpr.externals != 0) {
11818 if (adj > FOREGROUND_APP_ADJ) {
11819 adj = FOREGROUND_APP_ADJ;
11820 }
11821 }
11822 }
11823 }
11824
11825 app.curRawAdj = adj;
11826
11827 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
11828 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
11829 if (adj > app.maxAdj) {
11830 adj = app.maxAdj;
11831 }
11832
11833 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070011834 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
11835 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
11836 : Process.THREAD_GROUP_DEFAULT;
11837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011838 return adj;
11839 }
11840
11841 /**
11842 * Ask a given process to GC right now.
11843 */
11844 final void performAppGcLocked(ProcessRecord app) {
11845 try {
11846 app.lastRequestedGc = SystemClock.uptimeMillis();
11847 if (app.thread != null) {
11848 app.thread.processInBackground();
11849 }
11850 } catch (Exception e) {
11851 // whatever.
11852 }
11853 }
11854
11855 /**
11856 * Returns true if things are idle enough to perform GCs.
11857 */
11858 private final boolean canGcNow() {
11859 return mParallelBroadcasts.size() == 0
11860 && mOrderedBroadcasts.size() == 0
11861 && (mSleeping || (mResumedActivity != null &&
11862 mResumedActivity.idle));
11863 }
11864
11865 /**
11866 * Perform GCs on all processes that are waiting for it, but only
11867 * if things are idle.
11868 */
11869 final void performAppGcsLocked() {
11870 final int N = mProcessesToGc.size();
11871 if (N <= 0) {
11872 return;
11873 }
11874 if (canGcNow()) {
11875 while (mProcessesToGc.size() > 0) {
11876 ProcessRecord proc = mProcessesToGc.remove(0);
11877 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
11878 // To avoid spamming the system, we will GC processes one
11879 // at a time, waiting a few seconds between each.
11880 performAppGcLocked(proc);
11881 scheduleAppGcsLocked();
11882 return;
11883 }
11884 }
11885 }
11886 }
11887
11888 /**
11889 * If all looks good, perform GCs on all processes waiting for them.
11890 */
11891 final void performAppGcsIfAppropriateLocked() {
11892 if (canGcNow()) {
11893 performAppGcsLocked();
11894 return;
11895 }
11896 // Still not idle, wait some more.
11897 scheduleAppGcsLocked();
11898 }
11899
11900 /**
11901 * Schedule the execution of all pending app GCs.
11902 */
11903 final void scheduleAppGcsLocked() {
11904 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
11905 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
11906 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
11907 }
11908
11909 /**
11910 * Set up to ask a process to GC itself. This will either do it
11911 * immediately, or put it on the list of processes to gc the next
11912 * time things are idle.
11913 */
11914 final void scheduleAppGcLocked(ProcessRecord app) {
11915 long now = SystemClock.uptimeMillis();
11916 if ((app.lastRequestedGc+5000) > now) {
11917 return;
11918 }
11919 if (!mProcessesToGc.contains(app)) {
11920 mProcessesToGc.add(app);
11921 scheduleAppGcsLocked();
11922 }
11923 }
11924
11925 private final boolean updateOomAdjLocked(
11926 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11927 app.hiddenAdj = hiddenAdj;
11928
11929 if (app.thread == null) {
11930 return true;
11931 }
11932
11933 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
11934
11935 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
11936 //Thread priority adjustment is disabled out to see
11937 //how the kernel scheduler performs.
11938 if (false) {
11939 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
11940 app.setIsForeground = app.isForeground;
11941 if (app.pid != MY_PID) {
11942 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
11943 + " to " + (app.isForeground
11944 ? Process.THREAD_PRIORITY_FOREGROUND
11945 : Process.THREAD_PRIORITY_DEFAULT));
11946 try {
11947 Process.setThreadPriority(app.pid, app.isForeground
11948 ? Process.THREAD_PRIORITY_FOREGROUND
11949 : Process.THREAD_PRIORITY_DEFAULT);
11950 } catch (RuntimeException e) {
11951 Log.w(TAG, "Exception trying to set priority of application thread "
11952 + app.pid, e);
11953 }
11954 }
11955 }
11956 }
11957 if (app.pid != 0 && app.pid != MY_PID) {
11958 if (app.curRawAdj != app.setRawAdj) {
11959 if (app.curRawAdj > FOREGROUND_APP_ADJ
11960 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
11961 // If this app is transitioning from foreground to
11962 // non-foreground, have it do a gc.
11963 scheduleAppGcLocked(app);
11964 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
11965 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
11966 // Likewise do a gc when an app is moving in to the
11967 // background (such as a service stopping).
11968 scheduleAppGcLocked(app);
11969 }
11970 app.setRawAdj = app.curRawAdj;
11971 }
11972 if (adj != app.setAdj) {
11973 if (Process.setOomAdj(app.pid, adj)) {
11974 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
11975 TAG, "Set app " + app.processName +
11976 " oom adj to " + adj);
11977 app.setAdj = adj;
11978 } else {
11979 return false;
11980 }
11981 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070011982 if (app.setSchedGroup != app.curSchedGroup) {
11983 app.setSchedGroup = app.curSchedGroup;
11984 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
11985 "Setting process group of " + app.processName
11986 + " to " + app.curSchedGroup);
11987 if (true) {
11988 try {
11989 Process.setProcessGroup(app.pid, app.curSchedGroup);
11990 } catch (Exception e) {
11991 Log.w(TAG, "Failed setting process group of " + app.pid
11992 + " to " + app.curSchedGroup);
11993 }
11994 }
11995 if (false) {
11996 if (app.thread != null) {
11997 try {
11998 app.thread.setSchedulingGroup(app.curSchedGroup);
11999 } catch (RemoteException e) {
12000 }
12001 }
12002 }
12003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012004 }
12005
12006 return true;
12007 }
12008
12009 private final HistoryRecord resumedAppLocked() {
12010 HistoryRecord resumedActivity = mResumedActivity;
12011 if (resumedActivity == null || resumedActivity.app == null) {
12012 resumedActivity = mPausingActivity;
12013 if (resumedActivity == null || resumedActivity.app == null) {
12014 resumedActivity = topRunningActivityLocked(null);
12015 }
12016 }
12017 return resumedActivity;
12018 }
12019
12020 private final boolean updateOomAdjLocked(ProcessRecord app) {
12021 final HistoryRecord TOP_ACT = resumedAppLocked();
12022 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12023 int curAdj = app.curAdj;
12024 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12025 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12026
12027 mAdjSeq++;
12028
12029 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12030 if (res) {
12031 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12032 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12033 if (nowHidden != wasHidden) {
12034 // Changed to/from hidden state, so apps after it in the LRU
12035 // list may also be changed.
12036 updateOomAdjLocked();
12037 }
12038 }
12039 return res;
12040 }
12041
12042 private final boolean updateOomAdjLocked() {
12043 boolean didOomAdj = true;
12044 final HistoryRecord TOP_ACT = resumedAppLocked();
12045 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12046
12047 if (false) {
12048 RuntimeException e = new RuntimeException();
12049 e.fillInStackTrace();
12050 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12051 }
12052
12053 mAdjSeq++;
12054
12055 // First try updating the OOM adjustment for each of the
12056 // application processes based on their current state.
12057 int i = mLRUProcesses.size();
12058 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12059 while (i > 0) {
12060 i--;
12061 ProcessRecord app = mLRUProcesses.get(i);
12062 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12063 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12064 && app.curAdj == curHiddenAdj) {
12065 curHiddenAdj++;
12066 }
12067 } else {
12068 didOomAdj = false;
12069 }
12070 }
12071
12072 // todo: for now pretend like OOM ADJ didn't work, because things
12073 // aren't behaving as expected on Linux -- it's not killing processes.
12074 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12075 }
12076
12077 private final void trimApplications() {
12078 synchronized (this) {
12079 int i;
12080
12081 // First remove any unused application processes whose package
12082 // has been removed.
12083 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12084 final ProcessRecord app = mRemovedProcesses.get(i);
12085 if (app.activities.size() == 0
12086 && app.curReceiver == null && app.services.size() == 0) {
12087 Log.i(
12088 TAG, "Exiting empty application process "
12089 + app.processName + " ("
12090 + (app.thread != null ? app.thread.asBinder() : null)
12091 + ")\n");
12092 if (app.pid > 0 && app.pid != MY_PID) {
12093 Process.killProcess(app.pid);
12094 } else {
12095 try {
12096 app.thread.scheduleExit();
12097 } catch (Exception e) {
12098 // Ignore exceptions.
12099 }
12100 }
12101 cleanUpApplicationRecordLocked(app, false, -1);
12102 mRemovedProcesses.remove(i);
12103
12104 if (app.persistent) {
12105 if (app.persistent) {
12106 addAppLocked(app.info);
12107 }
12108 }
12109 }
12110 }
12111
12112 // Now try updating the OOM adjustment for each of the
12113 // application processes based on their current state.
12114 // If the setOomAdj() API is not supported, then go with our
12115 // back-up plan...
12116 if (!updateOomAdjLocked()) {
12117
12118 // Count how many processes are running services.
12119 int numServiceProcs = 0;
12120 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12121 final ProcessRecord app = mLRUProcesses.get(i);
12122
12123 if (app.persistent || app.services.size() != 0
12124 || app.curReceiver != null
12125 || app.persistentActivities > 0) {
12126 // Don't count processes holding services against our
12127 // maximum process count.
12128 if (localLOGV) Log.v(
12129 TAG, "Not trimming app " + app + " with services: "
12130 + app.services);
12131 numServiceProcs++;
12132 }
12133 }
12134
12135 int curMaxProcs = mProcessLimit;
12136 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12137 if (mAlwaysFinishActivities) {
12138 curMaxProcs = 1;
12139 }
12140 curMaxProcs += numServiceProcs;
12141
12142 // Quit as many processes as we can to get down to the desired
12143 // process count. First remove any processes that no longer
12144 // have activites running in them.
12145 for ( i=0;
12146 i<mLRUProcesses.size()
12147 && mLRUProcesses.size() > curMaxProcs;
12148 i++) {
12149 final ProcessRecord app = mLRUProcesses.get(i);
12150 // Quit an application only if it is not currently
12151 // running any activities.
12152 if (!app.persistent && app.activities.size() == 0
12153 && app.curReceiver == null && app.services.size() == 0) {
12154 Log.i(
12155 TAG, "Exiting empty application process "
12156 + app.processName + " ("
12157 + (app.thread != null ? app.thread.asBinder() : null)
12158 + ")\n");
12159 if (app.pid > 0 && app.pid != MY_PID) {
12160 Process.killProcess(app.pid);
12161 } else {
12162 try {
12163 app.thread.scheduleExit();
12164 } catch (Exception e) {
12165 // Ignore exceptions.
12166 }
12167 }
12168 // todo: For now we assume the application is not buggy
12169 // or evil, and will quit as a result of our request.
12170 // Eventually we need to drive this off of the death
12171 // notification, and kill the process if it takes too long.
12172 cleanUpApplicationRecordLocked(app, false, i);
12173 i--;
12174 }
12175 }
12176
12177 // If we still have too many processes, now from the least
12178 // recently used process we start finishing activities.
12179 if (Config.LOGV) Log.v(
12180 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12181 " of " + curMaxProcs + " processes");
12182 for ( i=0;
12183 i<mLRUProcesses.size()
12184 && mLRUProcesses.size() > curMaxProcs;
12185 i++) {
12186 final ProcessRecord app = mLRUProcesses.get(i);
12187 // Quit the application only if we have a state saved for
12188 // all of its activities.
12189 boolean canQuit = !app.persistent && app.curReceiver == null
12190 && app.services.size() == 0
12191 && app.persistentActivities == 0;
12192 int NUMA = app.activities.size();
12193 int j;
12194 if (Config.LOGV) Log.v(
12195 TAG, "Looking to quit " + app.processName);
12196 for (j=0; j<NUMA && canQuit; j++) {
12197 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12198 if (Config.LOGV) Log.v(
12199 TAG, " " + r.intent.getComponent().flattenToShortString()
12200 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12201 canQuit = (r.haveState || !r.stateNotNeeded)
12202 && !r.visible && r.stopped;
12203 }
12204 if (canQuit) {
12205 // Finish all of the activities, and then the app itself.
12206 for (j=0; j<NUMA; j++) {
12207 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12208 if (!r.finishing) {
12209 destroyActivityLocked(r, false);
12210 }
12211 r.resultTo = null;
12212 }
12213 Log.i(TAG, "Exiting application process "
12214 + app.processName + " ("
12215 + (app.thread != null ? app.thread.asBinder() : null)
12216 + ")\n");
12217 if (app.pid > 0 && app.pid != MY_PID) {
12218 Process.killProcess(app.pid);
12219 } else {
12220 try {
12221 app.thread.scheduleExit();
12222 } catch (Exception e) {
12223 // Ignore exceptions.
12224 }
12225 }
12226 // todo: For now we assume the application is not buggy
12227 // or evil, and will quit as a result of our request.
12228 // Eventually we need to drive this off of the death
12229 // notification, and kill the process if it takes too long.
12230 cleanUpApplicationRecordLocked(app, false, i);
12231 i--;
12232 //dump();
12233 }
12234 }
12235
12236 }
12237
12238 int curMaxActivities = MAX_ACTIVITIES;
12239 if (mAlwaysFinishActivities) {
12240 curMaxActivities = 1;
12241 }
12242
12243 // Finally, if there are too many activities now running, try to
12244 // finish as many as we can to get back down to the limit.
12245 for ( i=0;
12246 i<mLRUActivities.size()
12247 && mLRUActivities.size() > curMaxActivities;
12248 i++) {
12249 final HistoryRecord r
12250 = (HistoryRecord)mLRUActivities.get(i);
12251
12252 // We can finish this one if we have its icicle saved and
12253 // it is not persistent.
12254 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12255 && r.stopped && !r.persistent && !r.finishing) {
12256 final int origSize = mLRUActivities.size();
12257 destroyActivityLocked(r, true);
12258
12259 // This will remove it from the LRU list, so keep
12260 // our index at the same value. Note that this check to
12261 // see if the size changes is just paranoia -- if
12262 // something unexpected happens, we don't want to end up
12263 // in an infinite loop.
12264 if (origSize > mLRUActivities.size()) {
12265 i--;
12266 }
12267 }
12268 }
12269 }
12270 }
12271
12272 /** This method sends the specified signal to each of the persistent apps */
12273 public void signalPersistentProcesses(int sig) throws RemoteException {
12274 if (sig != Process.SIGNAL_USR1) {
12275 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12276 }
12277
12278 synchronized (this) {
12279 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12280 != PackageManager.PERMISSION_GRANTED) {
12281 throw new SecurityException("Requires permission "
12282 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12283 }
12284
12285 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12286 ProcessRecord r = mLRUProcesses.get(i);
12287 if (r.thread != null && r.persistent) {
12288 Process.sendSignal(r.pid, sig);
12289 }
12290 }
12291 }
12292 }
12293
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012294 public boolean profileControl(String process, boolean start,
12295 String path) throws RemoteException {
12296
12297 synchronized (this) {
12298 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12299 // its own permission.
12300 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12301 != PackageManager.PERMISSION_GRANTED) {
12302 throw new SecurityException("Requires permission "
12303 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12304 }
12305
12306 ProcessRecord proc = null;
12307 try {
12308 int pid = Integer.parseInt(process);
12309 synchronized (mPidsSelfLocked) {
12310 proc = mPidsSelfLocked.get(pid);
12311 }
12312 } catch (NumberFormatException e) {
12313 }
12314
12315 if (proc == null) {
12316 HashMap<String, SparseArray<ProcessRecord>> all
12317 = mProcessNames.getMap();
12318 SparseArray<ProcessRecord> procs = all.get(process);
12319 if (procs != null && procs.size() > 0) {
12320 proc = procs.valueAt(0);
12321 }
12322 }
12323
12324 if (proc == null || proc.thread == null) {
12325 throw new IllegalArgumentException("Unknown process: " + process);
12326 }
12327
12328 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12329 if (isSecure) {
12330 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12331 throw new SecurityException("Process not debuggable: " + proc);
12332 }
12333 }
12334
12335 try {
12336 proc.thread.profilerControl(start, path);
12337 return true;
12338 } catch (RemoteException e) {
12339 throw new IllegalStateException("Process disappeared");
12340 }
12341 }
12342 }
12343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012344 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12345 public void monitor() {
12346 synchronized (this) { }
12347 }
12348}