blob: d9c40ec602f6b98bb3cbf478723722eed58f90be [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;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import 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;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070044import android.backup.IBackupManager;
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;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070051import android.content.IIntentReceiver;
52import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.pm.ActivityInfo;
54import android.content.pm.ApplicationInfo;
55import android.content.pm.ConfigurationInfo;
56import android.content.pm.IPackageDataObserver;
57import android.content.pm.IPackageManager;
58import android.content.pm.InstrumentationInfo;
59import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070060import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.content.pm.ProviderInfo;
62import android.content.pm.ResolveInfo;
63import android.content.pm.ServiceInfo;
64import android.content.res.Configuration;
65import android.graphics.Bitmap;
66import android.net.Uri;
67import android.os.Binder;
68import android.os.Bundle;
69import android.os.Environment;
70import android.os.FileUtils;
71import android.os.Handler;
72import android.os.IBinder;
73import android.os.IPermissionController;
74import android.os.Looper;
75import android.os.Message;
76import android.os.Parcel;
77import android.os.ParcelFileDescriptor;
78import android.os.PowerManager;
79import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070080import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.RemoteException;
82import android.os.ServiceManager;
83import android.os.SystemClock;
84import android.os.SystemProperties;
85import android.provider.Checkin;
86import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020087import android.server.data.CrashData;
88import android.server.data.StackTraceElementData;
89import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.text.TextUtils;
91import android.util.Config;
92import android.util.EventLog;
93import android.util.Log;
94import android.util.PrintWriterPrinter;
95import android.util.SparseArray;
96import android.view.Gravity;
97import android.view.LayoutInflater;
98import android.view.View;
99import android.view.WindowManager;
100import android.view.WindowManagerPolicy;
101
102import dalvik.system.Zygote;
103
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200104import java.io.ByteArrayInputStream;
105import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import java.io.File;
107import java.io.FileDescriptor;
108import java.io.FileInputStream;
109import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200110import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.PrintWriter;
112import java.lang.IllegalStateException;
113import java.lang.ref.WeakReference;
114import java.util.ArrayList;
115import java.util.HashMap;
116import java.util.HashSet;
117import java.util.Iterator;
118import java.util.List;
119import java.util.Locale;
120import java.util.Map;
121
122public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
123 static final String TAG = "ActivityManager";
124 static final boolean DEBUG = false;
125 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
126 static final boolean DEBUG_SWITCH = localLOGV || false;
127 static final boolean DEBUG_TASKS = localLOGV || false;
128 static final boolean DEBUG_PAUSE = localLOGV || false;
129 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
130 static final boolean DEBUG_TRANSITION = localLOGV || false;
131 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700132 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 static final boolean DEBUG_SERVICE = localLOGV || false;
134 static final boolean DEBUG_VISBILITY = localLOGV || false;
135 static final boolean DEBUG_PROCESSES = localLOGV || false;
136 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700138 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean VALIDATE_TOKENS = false;
140 static final boolean SHOW_ACTIVITY_START_TIME = true;
141
142 // Control over CPU and battery monitoring.
143 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
144 static final boolean MONITOR_CPU_USAGE = true;
145 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
146 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
147 static final boolean MONITOR_THREAD_CPU_USAGE = false;
148
149 // Event log tags
150 static final int LOG_CONFIGURATION_CHANGED = 2719;
151 static final int LOG_CPU = 2721;
152 static final int LOG_AM_FINISH_ACTIVITY = 30001;
153 static final int LOG_TASK_TO_FRONT = 30002;
154 static final int LOG_AM_NEW_INTENT = 30003;
155 static final int LOG_AM_CREATE_TASK = 30004;
156 static final int LOG_AM_CREATE_ACTIVITY = 30005;
157 static final int LOG_AM_RESTART_ACTIVITY = 30006;
158 static final int LOG_AM_RESUME_ACTIVITY = 30007;
159 static final int LOG_ANR = 30008;
160 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
161 static final int LOG_AM_PROCESS_BOUND = 30010;
162 static final int LOG_AM_PROCESS_DIED = 30011;
163 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
164 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
165 static final int LOG_AM_PROCESS_START = 30014;
166 static final int LOG_AM_PROCESS_BAD = 30015;
167 static final int LOG_AM_PROCESS_GOOD = 30016;
168 static final int LOG_AM_LOW_MEMORY = 30017;
169 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
170 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
171 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
172 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
173 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
174 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
175 static final int LOG_AM_CREATE_SERVICE = 30030;
176 static final int LOG_AM_DESTROY_SERVICE = 30031;
177 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
178 static final int LOG_AM_DROP_PROCESS = 30033;
179 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
180 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
181 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
182
183 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
184 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
185
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186 // The flags that are set for all calls we make to the package manager.
187 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700188 | PackageManager.GET_SUPPORTS_DENSITIES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 private static final String SYSTEM_SECURE = "ro.secure";
191
192 // This is the maximum number of application processes we would like
193 // to have running. Due to the asynchronous nature of things, we can
194 // temporarily go beyond this limit.
195 static final int MAX_PROCESSES = 2;
196
197 // Set to false to leave processes running indefinitely, relying on
198 // the kernel killing them as resources are required.
199 static final boolean ENFORCE_PROCESS_LIMIT = false;
200
201 // This is the maximum number of activities that we would like to have
202 // running at a given time.
203 static final int MAX_ACTIVITIES = 20;
204
205 // Maximum number of recent tasks that we can remember.
206 static final int MAX_RECENT_TASKS = 20;
207
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700208 // Amount of time after a call to stopAppSwitches() during which we will
209 // prevent further untrusted switches from happening.
210 static final long APP_SWITCH_DELAY_TIME = 5*1000;
211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 // How long until we reset a task when the user returns to it. Currently
213 // 30 minutes.
214 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
215
216 // Set to true to disable the icon that is shown while a new activity
217 // is being started.
218 static final boolean SHOW_APP_STARTING_ICON = true;
219
220 // How long we wait until giving up on the last activity to pause. This
221 // is short because it directly impacts the responsiveness of starting the
222 // next activity.
223 static final int PAUSE_TIMEOUT = 500;
224
225 /**
226 * How long we can hold the launch wake lock before giving up.
227 */
228 static final int LAUNCH_TIMEOUT = 10*1000;
229
230 // How long we wait for a launched process to attach to the activity manager
231 // before we decide it's never going to come up for real.
232 static final int PROC_START_TIMEOUT = 10*1000;
233
234 // How long we wait until giving up on the last activity telling us it
235 // is idle.
236 static final int IDLE_TIMEOUT = 10*1000;
237
238 // How long to wait after going idle before forcing apps to GC.
239 static final int GC_TIMEOUT = 5*1000;
240
241 // How long we wait until giving up on an activity telling us it has
242 // finished destroying itself.
243 static final int DESTROY_TIMEOUT = 10*1000;
244
245 // How long we allow a receiver to run before giving up on it.
246 static final int BROADCAST_TIMEOUT = 10*1000;
247
248 // How long we wait for a service to finish executing.
249 static final int SERVICE_TIMEOUT = 20*1000;
250
251 // How long a service needs to be running until restarting its process
252 // is no longer considered to be a relaunch of the service.
253 static final int SERVICE_RESTART_DURATION = 5*1000;
254
255 // Maximum amount of time for there to be no activity on a service before
256 // we consider it non-essential and allow its process to go on the
257 // LRU background list.
258 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
259
260 // How long we wait until we timeout on key dispatching.
261 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
262
263 // The minimum time we allow between crashes, for us to consider this
264 // application to be bad and stop and its services and reject broadcasts.
265 static final int MIN_CRASH_INTERVAL = 60*1000;
266
267 // How long we wait until we timeout on key dispatching during instrumentation.
268 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
269
270 // OOM adjustments for processes in various states:
271
272 // This is a process without anything currently running in it. Definitely
273 // the first to go! Value set in system/rootdir/init.rc on startup.
274 // This value is initalized in the constructor, careful when refering to
275 // this static variable externally.
276 static int EMPTY_APP_ADJ;
277
278 // This is a process with a content provider that does not have any clients
279 // attached to it. If it did have any clients, its adjustment would be the
280 // one for the highest-priority of those processes.
281 static int CONTENT_PROVIDER_ADJ;
282
283 // This is a process only hosting activities that are not visible,
284 // so it can be killed without any disruption. Value set in
285 // system/rootdir/init.rc on startup.
286 final int HIDDEN_APP_MAX_ADJ;
287 static int HIDDEN_APP_MIN_ADJ;
288
The Android Open Source Project4df24232009-03-05 14:34:35 -0800289 // This is a process holding the home application -- we want to try
290 // avoiding killing it, even if it would normally be in the background,
291 // because the user interacts with it so much.
292 final int HOME_APP_ADJ;
293
Christopher Tate6fa95972009-06-05 18:43:55 -0700294 // This is a process currently hosting a backup operation. Killing it
295 // is not entirely fatal but is generally a bad idea.
296 final int BACKUP_APP_ADJ;
297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 // This is a process holding a secondary server -- killing it will not
299 // have much of an impact as far as the user is concerned. Value set in
300 // system/rootdir/init.rc on startup.
301 final int SECONDARY_SERVER_ADJ;
302
303 // This is a process only hosting activities that are visible to the
304 // user, so we'd prefer they don't disappear. Value set in
305 // system/rootdir/init.rc on startup.
306 final int VISIBLE_APP_ADJ;
307
308 // This is the process running the current foreground app. We'd really
309 // rather not kill it! Value set in system/rootdir/init.rc on startup.
310 final int FOREGROUND_APP_ADJ;
311
312 // This is a process running a core server, such as telephony. Definitely
313 // don't want to kill it, but doing so is not completely fatal.
314 static final int CORE_SERVER_ADJ = -12;
315
316 // The system process runs at the default adjustment.
317 static final int SYSTEM_ADJ = -16;
318
319 // Memory pages are 4K.
320 static final int PAGE_SIZE = 4*1024;
321
322 // Corresponding memory levels for above adjustments.
323 final int EMPTY_APP_MEM;
324 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800325 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700326 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 final int SECONDARY_SERVER_MEM;
328 final int VISIBLE_APP_MEM;
329 final int FOREGROUND_APP_MEM;
330
331 final int MY_PID;
332
333 static final String[] EMPTY_STRING_ARRAY = new String[0];
334
335 enum ActivityState {
336 INITIALIZING,
337 RESUMED,
338 PAUSING,
339 PAUSED,
340 STOPPING,
341 STOPPED,
342 FINISHING,
343 DESTROYING,
344 DESTROYED
345 }
346
347 /**
348 * The back history of all previous (and possibly still
349 * running) activities. It contains HistoryRecord objects.
350 */
351 final ArrayList mHistory = new ArrayList();
352
353 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700354 * Description of a request to start a new activity, which has been held
355 * due to app switches being disabled.
356 */
357 class PendingActivityLaunch {
358 HistoryRecord r;
359 HistoryRecord sourceRecord;
360 Uri[] grantedUriPermissions;
361 int grantedMode;
362 boolean onlyIfNeeded;
363 }
364
365 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
366 = new ArrayList<PendingActivityLaunch>();
367
368 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 * List of all active broadcasts that are to be executed immediately
370 * (without waiting for another broadcast to finish). Currently this only
371 * contains broadcasts to registered receivers, to avoid spinning up
372 * a bunch of processes to execute IntentReceiver components.
373 */
374 final ArrayList<BroadcastRecord> mParallelBroadcasts
375 = new ArrayList<BroadcastRecord>();
376
377 /**
378 * List of all active broadcasts that are to be executed one at a time.
379 * The object at the top of the list is the currently activity broadcasts;
380 * those after it are waiting for the top to finish..
381 */
382 final ArrayList<BroadcastRecord> mOrderedBroadcasts
383 = new ArrayList<BroadcastRecord>();
384
385 /**
386 * Set when we current have a BROADCAST_INTENT_MSG in flight.
387 */
388 boolean mBroadcastsScheduled = false;
389
390 /**
391 * Set to indicate whether to issue an onUserLeaving callback when a
392 * newly launched activity is being brought in front of us.
393 */
394 boolean mUserLeaving = false;
395
396 /**
397 * When we are in the process of pausing an activity, before starting the
398 * next one, this variable holds the activity that is currently being paused.
399 */
400 HistoryRecord mPausingActivity = null;
401
402 /**
403 * Current activity that is resumed, or null if there is none.
404 */
405 HistoryRecord mResumedActivity = null;
406
407 /**
408 * Activity we have told the window manager to have key focus.
409 */
410 HistoryRecord mFocusedActivity = null;
411
412 /**
413 * This is the last activity that we put into the paused state. This is
414 * used to determine if we need to do an activity transition while sleeping,
415 * when we normally hold the top activity paused.
416 */
417 HistoryRecord mLastPausedActivity = null;
418
419 /**
420 * List of activities that are waiting for a new activity
421 * to become visible before completing whatever operation they are
422 * supposed to do.
423 */
424 final ArrayList mWaitingVisibleActivities = new ArrayList();
425
426 /**
427 * List of activities that are ready to be stopped, but waiting
428 * for the next activity to settle down before doing so. It contains
429 * HistoryRecord objects.
430 */
431 final ArrayList<HistoryRecord> mStoppingActivities
432 = new ArrayList<HistoryRecord>();
433
434 /**
435 * List of intents that were used to start the most recent tasks.
436 */
437 final ArrayList<TaskRecord> mRecentTasks
438 = new ArrayList<TaskRecord>();
439
440 /**
441 * List of activities that are ready to be finished, but waiting
442 * for the previous activity to settle down before doing so. It contains
443 * HistoryRecord objects.
444 */
445 final ArrayList mFinishingActivities = new ArrayList();
446
447 /**
448 * All of the applications we currently have running organized by name.
449 * The keys are strings of the application package name (as
450 * returned by the package manager), and the keys are ApplicationRecord
451 * objects.
452 */
453 final ProcessMap<ProcessRecord> mProcessNames
454 = new ProcessMap<ProcessRecord>();
455
456 /**
457 * The last time that various processes have crashed.
458 */
459 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
460
461 /**
462 * Set of applications that we consider to be bad, and will reject
463 * incoming broadcasts from (which the user has no control over).
464 * Processes are added to this set when they have crashed twice within
465 * a minimum amount of time; they are removed from it when they are
466 * later restarted (hopefully due to some user action). The value is the
467 * time it was added to the list.
468 */
469 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
470
471 /**
472 * All of the processes we currently have running organized by pid.
473 * The keys are the pid running the application.
474 *
475 * <p>NOTE: This object is protected by its own lock, NOT the global
476 * activity manager lock!
477 */
478 final SparseArray<ProcessRecord> mPidsSelfLocked
479 = new SparseArray<ProcessRecord>();
480
481 /**
482 * All of the processes that have been forced to be foreground. The key
483 * is the pid of the caller who requested it (we hold a death
484 * link on it).
485 */
486 abstract class ForegroundToken implements IBinder.DeathRecipient {
487 int pid;
488 IBinder token;
489 }
490 final SparseArray<ForegroundToken> mForegroundProcesses
491 = new SparseArray<ForegroundToken>();
492
493 /**
494 * List of records for processes that someone had tried to start before the
495 * system was ready. We don't start them at that point, but ensure they
496 * are started by the time booting is complete.
497 */
498 final ArrayList<ProcessRecord> mProcessesOnHold
499 = new ArrayList<ProcessRecord>();
500
501 /**
502 * List of records for processes that we have started and are waiting
503 * for them to call back. This is really only needed when running in
504 * single processes mode, in which case we do not have a unique pid for
505 * each process.
506 */
507 final ArrayList<ProcessRecord> mStartingProcesses
508 = new ArrayList<ProcessRecord>();
509
510 /**
511 * List of persistent applications that are in the process
512 * of being started.
513 */
514 final ArrayList<ProcessRecord> mPersistentStartingProcesses
515 = new ArrayList<ProcessRecord>();
516
517 /**
518 * Processes that are being forcibly torn down.
519 */
520 final ArrayList<ProcessRecord> mRemovedProcesses
521 = new ArrayList<ProcessRecord>();
522
523 /**
524 * List of running applications, sorted by recent usage.
525 * The first entry in the list is the least recently used.
526 * It contains ApplicationRecord objects. This list does NOT include
527 * any persistent application records (since we never want to exit them).
528 */
529 final ArrayList<ProcessRecord> mLRUProcesses
530 = new ArrayList<ProcessRecord>();
531
532 /**
533 * List of processes that should gc as soon as things are idle.
534 */
535 final ArrayList<ProcessRecord> mProcessesToGc
536 = new ArrayList<ProcessRecord>();
537
538 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800539 * This is the process holding what we currently consider to be
540 * the "home" activity.
541 */
542 private ProcessRecord mHomeProcess;
543
544 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 * List of running activities, sorted by recent usage.
546 * The first entry in the list is the least recently used.
547 * It contains HistoryRecord objects.
548 */
549 private final ArrayList mLRUActivities = new ArrayList();
550
551 /**
552 * Set of PendingResultRecord objects that are currently active.
553 */
554 final HashSet mPendingResultRecords = new HashSet();
555
556 /**
557 * Set of IntentSenderRecord objects that are currently active.
558 */
559 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
560 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
561
562 /**
563 * Intent broadcast that we have tried to start, but are
564 * waiting for its application's process to be created. We only
565 * need one (instead of a list) because we always process broadcasts
566 * one at a time, so no others can be started while waiting for this
567 * one.
568 */
569 BroadcastRecord mPendingBroadcast = null;
570
571 /**
572 * Keeps track of all IIntentReceivers that have been registered for
573 * broadcasts. Hash keys are the receiver IBinder, hash value is
574 * a ReceiverList.
575 */
576 final HashMap mRegisteredReceivers = new HashMap();
577
578 /**
579 * Resolver for broadcast intents to registered receivers.
580 * Holds BroadcastFilter (subclass of IntentFilter).
581 */
582 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
583 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
584 @Override
585 protected boolean allowFilterResult(
586 BroadcastFilter filter, List<BroadcastFilter> dest) {
587 IBinder target = filter.receiverList.receiver.asBinder();
588 for (int i=dest.size()-1; i>=0; i--) {
589 if (dest.get(i).receiverList.receiver.asBinder() == target) {
590 return false;
591 }
592 }
593 return true;
594 }
595 };
596
597 /**
598 * State of all active sticky broadcasts. Keys are the action of the
599 * sticky Intent, values are an ArrayList of all broadcasted intents with
600 * that action (which should usually be one).
601 */
602 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
603 new HashMap<String, ArrayList<Intent>>();
604
605 /**
606 * All currently running services.
607 */
608 final HashMap<ComponentName, ServiceRecord> mServices =
609 new HashMap<ComponentName, ServiceRecord>();
610
611 /**
612 * All currently running services indexed by the Intent used to start them.
613 */
614 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
615 new HashMap<Intent.FilterComparison, ServiceRecord>();
616
617 /**
618 * All currently bound service connections. Keys are the IBinder of
619 * the client's IServiceConnection.
620 */
621 final HashMap<IBinder, ConnectionRecord> mServiceConnections
622 = new HashMap<IBinder, ConnectionRecord>();
623
624 /**
625 * List of services that we have been asked to start,
626 * but haven't yet been able to. It is used to hold start requests
627 * while waiting for their corresponding application thread to get
628 * going.
629 */
630 final ArrayList<ServiceRecord> mPendingServices
631 = new ArrayList<ServiceRecord>();
632
633 /**
634 * List of services that are scheduled to restart following a crash.
635 */
636 final ArrayList<ServiceRecord> mRestartingServices
637 = new ArrayList<ServiceRecord>();
638
639 /**
640 * List of services that are in the process of being stopped.
641 */
642 final ArrayList<ServiceRecord> mStoppingServices
643 = new ArrayList<ServiceRecord>();
644
645 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700646 * Backup/restore process management
647 */
648 String mBackupAppName = null;
649 BackupRecord mBackupTarget = null;
650
651 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 * List of PendingThumbnailsRecord objects of clients who are still
653 * waiting to receive all of the thumbnails for a task.
654 */
655 final ArrayList mPendingThumbnails = new ArrayList();
656
657 /**
658 * List of HistoryRecord objects that have been finished and must
659 * still report back to a pending thumbnail receiver.
660 */
661 final ArrayList mCancelledThumbnails = new ArrayList();
662
663 /**
664 * All of the currently running global content providers. Keys are a
665 * string containing the provider name and values are a
666 * ContentProviderRecord object containing the data about it. Note
667 * that a single provider may be published under multiple names, so
668 * there may be multiple entries here for a single one in mProvidersByClass.
669 */
670 final HashMap mProvidersByName = new HashMap();
671
672 /**
673 * All of the currently running global content providers. Keys are a
674 * string containing the provider's implementation class and values are a
675 * ContentProviderRecord object containing the data about it.
676 */
677 final HashMap mProvidersByClass = new HashMap();
678
679 /**
680 * List of content providers who have clients waiting for them. The
681 * application is currently being launched and the provider will be
682 * removed from this list once it is published.
683 */
684 final ArrayList mLaunchingProviders = new ArrayList();
685
686 /**
687 * Global set of specific Uri permissions that have been granted.
688 */
689 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
690 = new SparseArray<HashMap<Uri, UriPermission>>();
691
692 /**
693 * Thread-local storage used to carry caller permissions over through
694 * indirect content-provider access.
695 * @see #ActivityManagerService.openContentUri()
696 */
697 private class Identity {
698 public int pid;
699 public int uid;
700
701 Identity(int _pid, int _uid) {
702 pid = _pid;
703 uid = _uid;
704 }
705 }
706 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
707
708 /**
709 * All information we have collected about the runtime performance of
710 * any user id that can impact battery performance.
711 */
712 final BatteryStatsService mBatteryStatsService;
713
714 /**
715 * information about component usage
716 */
717 final UsageStatsService mUsageStatsService;
718
719 /**
720 * Current configuration information. HistoryRecord objects are given
721 * a reference to this object to indicate which configuration they are
722 * currently running in, so this object must be kept immutable.
723 */
724 Configuration mConfiguration = new Configuration();
725
726 /**
727 * List of initialization arguments to pass to all processes when binding applications to them.
728 * For example, references to the commonly used services.
729 */
730 HashMap<String, IBinder> mAppBindArgs;
731
732 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700733 * Temporary to avoid allocations. Protected by main lock.
734 */
735 final StringBuilder mStringBuilder = new StringBuilder(256);
736
737 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 * Used to control how we initialize the service.
739 */
740 boolean mStartRunning = false;
741 ComponentName mTopComponent;
742 String mTopAction;
743 String mTopData;
744 boolean mSystemReady = false;
745 boolean mBooting = false;
746
747 Context mContext;
748
749 int mFactoryTest;
750
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700751 boolean mCheckedForSetup;
752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700754 * The time at which we will allow normal application switches again,
755 * after a call to {@link #stopAppSwitches()}.
756 */
757 long mAppSwitchesAllowedTime;
758
759 /**
760 * This is set to true after the first switch after mAppSwitchesAllowedTime
761 * is set; any switches after that will clear the time.
762 */
763 boolean mDidAppSwitch;
764
765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 * Set while we are wanting to sleep, to prevent any
767 * activities from being started/resumed.
768 */
769 boolean mSleeping = false;
770
771 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700772 * Set if we are shutting down the system, similar to sleeping.
773 */
774 boolean mShuttingDown = false;
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Set when the system is going to sleep, until we have
778 * successfully paused the current activity and released our wake lock.
779 * At that point the system is allowed to actually sleep.
780 */
781 PowerManager.WakeLock mGoingToSleep;
782
783 /**
784 * We don't want to allow the device to go to sleep while in the process
785 * of launching an activity. This is primarily to allow alarm intent
786 * receivers to launch an activity and get that to run before the device
787 * goes back to sleep.
788 */
789 PowerManager.WakeLock mLaunchingActivity;
790
791 /**
792 * Task identifier that activities are currently being started
793 * in. Incremented each time a new task is created.
794 * todo: Replace this with a TokenSpace class that generates non-repeating
795 * integers that won't wrap.
796 */
797 int mCurTask = 1;
798
799 /**
800 * Current sequence id for oom_adj computation traversal.
801 */
802 int mAdjSeq = 0;
803
804 /**
805 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
806 * is set, indicating the user wants processes started in such a way
807 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
808 * running in each process (thus no pre-initialized process, etc).
809 */
810 boolean mSimpleProcessManagement = false;
811
812 /**
813 * System monitoring: number of processes that died since the last
814 * N procs were started.
815 */
816 int[] mProcDeaths = new int[20];
817
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700818 /**
819 * This is set if we had to do a delayed dexopt of an app before launching
820 * it, to increasing the ANR timeouts in that case.
821 */
822 boolean mDidDexOpt;
823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 String mDebugApp = null;
825 boolean mWaitForDebugger = false;
826 boolean mDebugTransient = false;
827 String mOrigDebugApp = null;
828 boolean mOrigWaitForDebugger = false;
829 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700830 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700832 final RemoteCallbackList<IActivityWatcher> mWatchers
833 = new RemoteCallbackList<IActivityWatcher>();
834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 /**
836 * Callback of last caller to {@link #requestPss}.
837 */
838 Runnable mRequestPssCallback;
839
840 /**
841 * Remaining processes for which we are waiting results from the last
842 * call to {@link #requestPss}.
843 */
844 final ArrayList<ProcessRecord> mRequestPssList
845 = new ArrayList<ProcessRecord>();
846
847 /**
848 * Runtime statistics collection thread. This object's lock is used to
849 * protect all related state.
850 */
851 final Thread mProcessStatsThread;
852
853 /**
854 * Used to collect process stats when showing not responding dialog.
855 * Protected by mProcessStatsThread.
856 */
857 final ProcessStats mProcessStats = new ProcessStats(
858 MONITOR_THREAD_CPU_USAGE);
859 long mLastCpuTime = 0;
860 long mLastWriteTime = 0;
861
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700862 long mInitialStartTime = 0;
863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 /**
865 * Set to true after the system has finished booting.
866 */
867 boolean mBooted = false;
868
869 int mProcessLimit = 0;
870
871 WindowManagerService mWindowManager;
872
873 static ActivityManagerService mSelf;
874 static ActivityThread mSystemThread;
875
876 private final class AppDeathRecipient implements IBinder.DeathRecipient {
877 final ProcessRecord mApp;
878 final int mPid;
879 final IApplicationThread mAppThread;
880
881 AppDeathRecipient(ProcessRecord app, int pid,
882 IApplicationThread thread) {
883 if (localLOGV) Log.v(
884 TAG, "New death recipient " + this
885 + " for thread " + thread.asBinder());
886 mApp = app;
887 mPid = pid;
888 mAppThread = thread;
889 }
890
891 public void binderDied() {
892 if (localLOGV) Log.v(
893 TAG, "Death received in " + this
894 + " for thread " + mAppThread.asBinder());
895 removeRequestedPss(mApp);
896 synchronized(ActivityManagerService.this) {
897 appDiedLocked(mApp, mPid, mAppThread);
898 }
899 }
900 }
901
902 static final int SHOW_ERROR_MSG = 1;
903 static final int SHOW_NOT_RESPONDING_MSG = 2;
904 static final int SHOW_FACTORY_ERROR_MSG = 3;
905 static final int UPDATE_CONFIGURATION_MSG = 4;
906 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
907 static final int WAIT_FOR_DEBUGGER_MSG = 6;
908 static final int BROADCAST_INTENT_MSG = 7;
909 static final int BROADCAST_TIMEOUT_MSG = 8;
910 static final int PAUSE_TIMEOUT_MSG = 9;
911 static final int IDLE_TIMEOUT_MSG = 10;
912 static final int IDLE_NOW_MSG = 11;
913 static final int SERVICE_TIMEOUT_MSG = 12;
914 static final int UPDATE_TIME_ZONE = 13;
915 static final int SHOW_UID_ERROR_MSG = 14;
916 static final int IM_FEELING_LUCKY_MSG = 15;
917 static final int LAUNCH_TIMEOUT_MSG = 16;
918 static final int DESTROY_TIMEOUT_MSG = 17;
919 static final int SERVICE_ERROR_MSG = 18;
920 static final int RESUME_TOP_ACTIVITY_MSG = 19;
921 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700922 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923
924 AlertDialog mUidAlert;
925
926 final Handler mHandler = new Handler() {
927 //public Handler() {
928 // if (localLOGV) Log.v(TAG, "Handler started!");
929 //}
930
931 public void handleMessage(Message msg) {
932 switch (msg.what) {
933 case SHOW_ERROR_MSG: {
934 HashMap data = (HashMap) msg.obj;
935 byte[] crashData = (byte[])data.get("crashData");
936 if (crashData != null) {
937 // This needs to be *un*synchronized to avoid deadlock.
938 ContentResolver resolver = mContext.getContentResolver();
939 Checkin.reportCrash(resolver, crashData);
940 }
941 synchronized (ActivityManagerService.this) {
942 ProcessRecord proc = (ProcessRecord)data.get("app");
943 if (proc != null && proc.crashDialog != null) {
944 Log.e(TAG, "App already has crash dialog: " + proc);
945 return;
946 }
947 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700948 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 Dialog d = new AppErrorDialog(
950 mContext, res, proc,
951 (Integer)data.get("flags"),
952 (String)data.get("shortMsg"),
953 (String)data.get("longMsg"));
954 d.show();
955 proc.crashDialog = d;
956 } else {
957 // The device is asleep, so just pretend that the user
958 // saw a crash dialog and hit "force quit".
959 res.set(0);
960 }
961 }
962 } break;
963 case SHOW_NOT_RESPONDING_MSG: {
964 synchronized (ActivityManagerService.this) {
965 HashMap data = (HashMap) msg.obj;
966 ProcessRecord proc = (ProcessRecord)data.get("app");
967 if (proc != null && proc.anrDialog != null) {
968 Log.e(TAG, "App already has anr dialog: " + proc);
969 return;
970 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800971
972 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
973 null, null, 0, null, null, null,
974 false, false, MY_PID, Process.SYSTEM_UID);
975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
977 mContext, proc, (HistoryRecord)data.get("activity"));
978 d.show();
979 proc.anrDialog = d;
980 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700981
982 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 } break;
984 case SHOW_FACTORY_ERROR_MSG: {
985 Dialog d = new FactoryErrorDialog(
986 mContext, msg.getData().getCharSequence("msg"));
987 d.show();
988 enableScreenAfterBoot();
989 } break;
990 case UPDATE_CONFIGURATION_MSG: {
991 final ContentResolver resolver = mContext.getContentResolver();
992 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
993 } break;
994 case GC_BACKGROUND_PROCESSES_MSG: {
995 synchronized (ActivityManagerService.this) {
996 performAppGcsIfAppropriateLocked();
997 }
998 } break;
999 case WAIT_FOR_DEBUGGER_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 ProcessRecord app = (ProcessRecord)msg.obj;
1002 if (msg.arg1 != 0) {
1003 if (!app.waitedForDebugger) {
1004 Dialog d = new AppWaitingForDebuggerDialog(
1005 ActivityManagerService.this,
1006 mContext, app);
1007 app.waitDialog = d;
1008 app.waitedForDebugger = true;
1009 d.show();
1010 }
1011 } else {
1012 if (app.waitDialog != null) {
1013 app.waitDialog.dismiss();
1014 app.waitDialog = null;
1015 }
1016 }
1017 }
1018 } break;
1019 case BROADCAST_INTENT_MSG: {
1020 if (DEBUG_BROADCAST) Log.v(
1021 TAG, "Received BROADCAST_INTENT_MSG");
1022 processNextBroadcast(true);
1023 } break;
1024 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001025 if (mDidDexOpt) {
1026 mDidDexOpt = false;
1027 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1028 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1029 return;
1030 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 broadcastTimeout();
1032 } break;
1033 case PAUSE_TIMEOUT_MSG: {
1034 IBinder token = (IBinder)msg.obj;
1035 // We don't at this point know if the activity is fullscreen,
1036 // so we need to be conservative and assume it isn't.
1037 Log.w(TAG, "Activity pause timeout for " + token);
1038 activityPaused(token, null, true);
1039 } break;
1040 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001041 if (mDidDexOpt) {
1042 mDidDexOpt = false;
1043 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1044 nmsg.obj = msg.obj;
1045 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1046 return;
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 // We don't at this point know if the activity is fullscreen,
1049 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001050 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 Log.w(TAG, "Activity idle timeout for " + token);
1052 activityIdleInternal(token, true);
1053 } break;
1054 case DESTROY_TIMEOUT_MSG: {
1055 IBinder token = (IBinder)msg.obj;
1056 // We don't at this point know if the activity is fullscreen,
1057 // so we need to be conservative and assume it isn't.
1058 Log.w(TAG, "Activity destroy timeout for " + token);
1059 activityDestroyed(token);
1060 } break;
1061 case IDLE_NOW_MSG: {
1062 IBinder token = (IBinder)msg.obj;
1063 activityIdle(token);
1064 } break;
1065 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001066 if (mDidDexOpt) {
1067 mDidDexOpt = false;
1068 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1069 nmsg.obj = msg.obj;
1070 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1071 return;
1072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 serviceTimeout((ProcessRecord)msg.obj);
1074 } break;
1075 case UPDATE_TIME_ZONE: {
1076 synchronized (ActivityManagerService.this) {
1077 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1078 ProcessRecord r = mLRUProcesses.get(i);
1079 if (r.thread != null) {
1080 try {
1081 r.thread.updateTimeZone();
1082 } catch (RemoteException ex) {
1083 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1084 }
1085 }
1086 }
1087 }
1088 break;
1089 }
1090 case SHOW_UID_ERROR_MSG: {
1091 // XXX This is a temporary dialog, no need to localize.
1092 AlertDialog d = new BaseErrorDialog(mContext);
1093 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1094 d.setCancelable(false);
1095 d.setTitle("System UIDs Inconsistent");
1096 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1097 d.setButton("I'm Feeling Lucky",
1098 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1099 mUidAlert = d;
1100 d.show();
1101 } break;
1102 case IM_FEELING_LUCKY_MSG: {
1103 if (mUidAlert != null) {
1104 mUidAlert.dismiss();
1105 mUidAlert = null;
1106 }
1107 } break;
1108 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1112 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1113 return;
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 synchronized (ActivityManagerService.this) {
1116 if (mLaunchingActivity.isHeld()) {
1117 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1118 mLaunchingActivity.release();
1119 }
1120 }
1121 } break;
1122 case SERVICE_ERROR_MSG: {
1123 ServiceRecord srv = (ServiceRecord)msg.obj;
1124 // This needs to be *un*synchronized to avoid deadlock.
1125 Checkin.logEvent(mContext.getContentResolver(),
1126 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1127 srv.name.toShortString());
1128 } break;
1129 case RESUME_TOP_ACTIVITY_MSG: {
1130 synchronized (ActivityManagerService.this) {
1131 resumeTopActivityLocked(null);
1132 }
1133 }
1134 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001135 if (mDidDexOpt) {
1136 mDidDexOpt = false;
1137 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1138 nmsg.obj = msg.obj;
1139 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1140 return;
1141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 ProcessRecord app = (ProcessRecord)msg.obj;
1143 synchronized (ActivityManagerService.this) {
1144 processStartTimedOutLocked(app);
1145 }
1146 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001147 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1148 synchronized (ActivityManagerService.this) {
1149 doPendingActivityLaunchesLocked(true);
1150 }
1151 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 }
1153 }
1154 };
1155
1156 public static void setSystemProcess() {
1157 try {
1158 ActivityManagerService m = mSelf;
1159
1160 ServiceManager.addService("activity", m);
1161 ServiceManager.addService("meminfo", new MemBinder(m));
1162 if (MONITOR_CPU_USAGE) {
1163 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1164 }
1165 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1166 ServiceManager.addService("activity.services", new ServicesBinder(m));
1167 ServiceManager.addService("activity.senders", new SendersBinder(m));
1168 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1169 ServiceManager.addService("permission", new PermissionController(m));
1170
1171 ApplicationInfo info =
1172 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001173 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 synchronized (mSelf) {
1175 ProcessRecord app = mSelf.newProcessRecordLocked(
1176 mSystemThread.getApplicationThread(), info,
1177 info.processName);
1178 app.persistent = true;
1179 app.pid = Process.myPid();
1180 app.maxAdj = SYSTEM_ADJ;
1181 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1182 synchronized (mSelf.mPidsSelfLocked) {
1183 mSelf.mPidsSelfLocked.put(app.pid, app);
1184 }
1185 mSelf.updateLRUListLocked(app, true);
1186 }
1187 } catch (PackageManager.NameNotFoundException e) {
1188 throw new RuntimeException(
1189 "Unable to find android system package", e);
1190 }
1191 }
1192
1193 public void setWindowManager(WindowManagerService wm) {
1194 mWindowManager = wm;
1195 }
1196
1197 public static final Context main(int factoryTest) {
1198 AThread thr = new AThread();
1199 thr.start();
1200
1201 synchronized (thr) {
1202 while (thr.mService == null) {
1203 try {
1204 thr.wait();
1205 } catch (InterruptedException e) {
1206 }
1207 }
1208 }
1209
1210 ActivityManagerService m = thr.mService;
1211 mSelf = m;
1212 ActivityThread at = ActivityThread.systemMain();
1213 mSystemThread = at;
1214 Context context = at.getSystemContext();
1215 m.mContext = context;
1216 m.mFactoryTest = factoryTest;
1217 PowerManager pm =
1218 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1219 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1220 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1221 m.mLaunchingActivity.setReferenceCounted(false);
1222
1223 m.mBatteryStatsService.publish(context);
1224 m.mUsageStatsService.publish(context);
1225
1226 synchronized (thr) {
1227 thr.mReady = true;
1228 thr.notifyAll();
1229 }
1230
1231 m.startRunning(null, null, null, null);
1232
1233 return context;
1234 }
1235
1236 public static ActivityManagerService self() {
1237 return mSelf;
1238 }
1239
1240 static class AThread extends Thread {
1241 ActivityManagerService mService;
1242 boolean mReady = false;
1243
1244 public AThread() {
1245 super("ActivityManager");
1246 }
1247
1248 public void run() {
1249 Looper.prepare();
1250
1251 android.os.Process.setThreadPriority(
1252 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1253
1254 ActivityManagerService m = new ActivityManagerService();
1255
1256 synchronized (this) {
1257 mService = m;
1258 notifyAll();
1259 }
1260
1261 synchronized (this) {
1262 while (!mReady) {
1263 try {
1264 wait();
1265 } catch (InterruptedException e) {
1266 }
1267 }
1268 }
1269
1270 Looper.loop();
1271 }
1272 }
1273
1274 static class BroadcastsBinder extends Binder {
1275 ActivityManagerService mActivityManagerService;
1276 BroadcastsBinder(ActivityManagerService activityManagerService) {
1277 mActivityManagerService = activityManagerService;
1278 }
1279
1280 @Override
1281 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1282 mActivityManagerService.dumpBroadcasts(pw);
1283 }
1284 }
1285
1286 static class ServicesBinder extends Binder {
1287 ActivityManagerService mActivityManagerService;
1288 ServicesBinder(ActivityManagerService activityManagerService) {
1289 mActivityManagerService = activityManagerService;
1290 }
1291
1292 @Override
1293 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1294 mActivityManagerService.dumpServices(pw);
1295 }
1296 }
1297
1298 static class SendersBinder extends Binder {
1299 ActivityManagerService mActivityManagerService;
1300 SendersBinder(ActivityManagerService activityManagerService) {
1301 mActivityManagerService = activityManagerService;
1302 }
1303
1304 @Override
1305 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1306 mActivityManagerService.dumpSenders(pw);
1307 }
1308 }
1309
1310 static class ProvidersBinder extends Binder {
1311 ActivityManagerService mActivityManagerService;
1312 ProvidersBinder(ActivityManagerService activityManagerService) {
1313 mActivityManagerService = activityManagerService;
1314 }
1315
1316 @Override
1317 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1318 mActivityManagerService.dumpProviders(pw);
1319 }
1320 }
1321
1322 static class MemBinder extends Binder {
1323 ActivityManagerService mActivityManagerService;
1324 MemBinder(ActivityManagerService activityManagerService) {
1325 mActivityManagerService = activityManagerService;
1326 }
1327
1328 @Override
1329 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1330 ActivityManagerService service = mActivityManagerService;
1331 ArrayList<ProcessRecord> procs;
1332 synchronized (mActivityManagerService) {
1333 if (args != null && args.length > 0
1334 && args[0].charAt(0) != '-') {
1335 procs = new ArrayList<ProcessRecord>();
1336 int pid = -1;
1337 try {
1338 pid = Integer.parseInt(args[0]);
1339 } catch (NumberFormatException e) {
1340
1341 }
1342 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1343 ProcessRecord proc = service.mLRUProcesses.get(i);
1344 if (proc.pid == pid) {
1345 procs.add(proc);
1346 } else if (proc.processName.equals(args[0])) {
1347 procs.add(proc);
1348 }
1349 }
1350 if (procs.size() <= 0) {
1351 pw.println("No process found for: " + args[0]);
1352 return;
1353 }
1354 } else {
1355 procs = service.mLRUProcesses;
1356 }
1357 }
1358 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1359 }
1360 }
1361
1362 static class CpuBinder extends Binder {
1363 ActivityManagerService mActivityManagerService;
1364 CpuBinder(ActivityManagerService activityManagerService) {
1365 mActivityManagerService = activityManagerService;
1366 }
1367
1368 @Override
1369 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370 synchronized (mActivityManagerService.mProcessStatsThread) {
1371 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1372 }
1373 }
1374 }
1375
1376 private ActivityManagerService() {
1377 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1378 if (v != null && Integer.getInteger(v) != 0) {
1379 mSimpleProcessManagement = true;
1380 }
1381 v = System.getenv("ANDROID_DEBUG_APP");
1382 if (v != null) {
1383 mSimpleProcessManagement = true;
1384 }
1385
1386 MY_PID = Process.myPid();
1387
1388 File dataDir = Environment.getDataDirectory();
1389 File systemDir = new File(dataDir, "system");
1390 systemDir.mkdirs();
1391 mBatteryStatsService = new BatteryStatsService(new File(
1392 systemDir, "batterystats.bin").toString());
1393 mBatteryStatsService.getActiveStatistics().readLocked();
1394 mBatteryStatsService.getActiveStatistics().writeLocked();
1395
1396 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001397 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
1399 mConfiguration.makeDefault();
1400 mProcessStats.init();
1401
1402 // Add ourself to the Watchdog monitors.
1403 Watchdog.getInstance().addMonitor(this);
1404
1405 // These values are set in system/rootdir/init.rc on startup.
1406 FOREGROUND_APP_ADJ =
1407 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1408 VISIBLE_APP_ADJ =
1409 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1410 SECONDARY_SERVER_ADJ =
1411 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001412 BACKUP_APP_ADJ =
1413 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001414 HOME_APP_ADJ =
1415 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 HIDDEN_APP_MIN_ADJ =
1417 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1418 CONTENT_PROVIDER_ADJ =
1419 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1420 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1421 EMPTY_APP_ADJ =
1422 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1423 FOREGROUND_APP_MEM =
1424 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1425 VISIBLE_APP_MEM =
1426 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1427 SECONDARY_SERVER_MEM =
1428 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001429 BACKUP_APP_MEM =
1430 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001431 HOME_APP_MEM =
1432 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 HIDDEN_APP_MEM =
1434 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1435 EMPTY_APP_MEM =
1436 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1437
1438 mProcessStatsThread = new Thread("ProcessStats") {
1439 public void run() {
1440 while (true) {
1441 try {
1442 try {
1443 synchronized(this) {
1444 final long now = SystemClock.uptimeMillis();
1445 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1446 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1447 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1448 // + ", write delay=" + nextWriteDelay);
1449 if (nextWriteDelay < nextCpuDelay) {
1450 nextCpuDelay = nextWriteDelay;
1451 }
1452 if (nextCpuDelay > 0) {
1453 this.wait(nextCpuDelay);
1454 }
1455 }
1456 } catch (InterruptedException e) {
1457 }
1458
1459 updateCpuStatsNow();
1460 } catch (Exception e) {
1461 Log.e(TAG, "Unexpected exception collecting process stats", e);
1462 }
1463 }
1464 }
1465 };
1466 mProcessStatsThread.start();
1467 }
1468
1469 @Override
1470 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1471 throws RemoteException {
1472 try {
1473 return super.onTransact(code, data, reply, flags);
1474 } catch (RuntimeException e) {
1475 // The activity manager only throws security exceptions, so let's
1476 // log all others.
1477 if (!(e instanceof SecurityException)) {
1478 Log.e(TAG, "Activity Manager Crash", e);
1479 }
1480 throw e;
1481 }
1482 }
1483
1484 void updateCpuStats() {
1485 synchronized (mProcessStatsThread) {
1486 final long now = SystemClock.uptimeMillis();
1487 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1488 mProcessStatsThread.notify();
1489 }
1490 }
1491 }
1492
1493 void updateCpuStatsNow() {
1494 synchronized (mProcessStatsThread) {
1495 final long now = SystemClock.uptimeMillis();
1496 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 if (MONITOR_CPU_USAGE &&
1499 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1500 mLastCpuTime = now;
1501 haveNewCpuStats = true;
1502 mProcessStats.update();
1503 //Log.i(TAG, mProcessStats.printCurrentState());
1504 //Log.i(TAG, "Total CPU usage: "
1505 // + mProcessStats.getTotalCpuPercent() + "%");
1506
1507 // Log the cpu usage if the property is set.
1508 if ("true".equals(SystemProperties.get("events.cpu"))) {
1509 int user = mProcessStats.getLastUserTime();
1510 int system = mProcessStats.getLastSystemTime();
1511 int iowait = mProcessStats.getLastIoWaitTime();
1512 int irq = mProcessStats.getLastIrqTime();
1513 int softIrq = mProcessStats.getLastSoftIrqTime();
1514 int idle = mProcessStats.getLastIdleTime();
1515
1516 int total = user + system + iowait + irq + softIrq + idle;
1517 if (total == 0) total = 1;
1518
1519 EventLog.writeEvent(LOG_CPU,
1520 ((user+system+iowait+irq+softIrq) * 100) / total,
1521 (user * 100) / total,
1522 (system * 100) / total,
1523 (iowait * 100) / total,
1524 (irq * 100) / total,
1525 (softIrq * 100) / total);
1526 }
1527 }
1528
Amith Yamasani819f9282009-06-24 23:18:15 -07001529 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001530 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 synchronized(mPidsSelfLocked) {
1532 if (haveNewCpuStats) {
1533 if (mBatteryStatsService.isOnBattery()) {
1534 final int N = mProcessStats.countWorkingStats();
1535 for (int i=0; i<N; i++) {
1536 ProcessStats.Stats st
1537 = mProcessStats.getWorkingStats(i);
1538 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1539 if (pr != null) {
1540 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1541 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001542 } else {
1543 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001544 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001545 if (ps != null) {
1546 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 }
1549 }
1550 }
1551 }
1552 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1555 mLastWriteTime = now;
1556 mBatteryStatsService.getActiveStatistics().writeLocked();
1557 }
1558 }
1559 }
1560 }
1561
1562 /**
1563 * Initialize the application bind args. These are passed to each
1564 * process when the bindApplication() IPC is sent to the process. They're
1565 * lazily setup to make sure the services are running when they're asked for.
1566 */
1567 private HashMap<String, IBinder> getCommonServicesLocked() {
1568 if (mAppBindArgs == null) {
1569 mAppBindArgs = new HashMap<String, IBinder>();
1570
1571 // Setup the application init args
1572 mAppBindArgs.put("package", ServiceManager.getService("package"));
1573 mAppBindArgs.put("window", ServiceManager.getService("window"));
1574 mAppBindArgs.put(Context.ALARM_SERVICE,
1575 ServiceManager.getService(Context.ALARM_SERVICE));
1576 }
1577 return mAppBindArgs;
1578 }
1579
1580 private final void setFocusedActivityLocked(HistoryRecord r) {
1581 if (mFocusedActivity != r) {
1582 mFocusedActivity = r;
1583 mWindowManager.setFocusedApp(r, true);
1584 }
1585 }
1586
1587 private final void updateLRUListLocked(ProcessRecord app,
1588 boolean oomAdj) {
1589 // put it on the LRU to keep track of when it should be exited.
1590 int lrui = mLRUProcesses.indexOf(app);
1591 if (lrui >= 0) mLRUProcesses.remove(lrui);
1592 mLRUProcesses.add(app);
1593 //Log.i(TAG, "Putting proc to front: " + app.processName);
1594 if (oomAdj) {
1595 updateOomAdjLocked();
1596 }
1597 }
1598
1599 private final boolean updateLRUListLocked(HistoryRecord r) {
1600 final boolean hadit = mLRUActivities.remove(r);
1601 mLRUActivities.add(r);
1602 return hadit;
1603 }
1604
1605 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1606 int i = mHistory.size()-1;
1607 while (i >= 0) {
1608 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1609 if (!r.finishing && r != notTop) {
1610 return r;
1611 }
1612 i--;
1613 }
1614 return null;
1615 }
1616
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001617 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1618 int i = mHistory.size()-1;
1619 while (i >= 0) {
1620 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1621 if (!r.finishing && !r.delayedResume && r != notTop) {
1622 return r;
1623 }
1624 i--;
1625 }
1626 return null;
1627 }
1628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 /**
1630 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001631 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 *
1633 * @param token If non-null, any history records matching this token will be skipped.
1634 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1635 *
1636 * @return Returns the HistoryRecord of the next activity on the stack.
1637 */
1638 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1639 int i = mHistory.size()-1;
1640 while (i >= 0) {
1641 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1642 // Note: the taskId check depends on real taskId fields being non-zero
1643 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1644 return r;
1645 }
1646 i--;
1647 }
1648 return null;
1649 }
1650
1651 private final ProcessRecord getProcessRecordLocked(
1652 String processName, int uid) {
1653 if (uid == Process.SYSTEM_UID) {
1654 // The system gets to run in any process. If there are multiple
1655 // processes with the same uid, just pick the first (this
1656 // should never happen).
1657 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1658 processName);
1659 return procs != null ? procs.valueAt(0) : null;
1660 }
1661 ProcessRecord proc = mProcessNames.get(processName, uid);
1662 return proc;
1663 }
1664
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001665 private void ensurePackageDexOpt(String packageName) {
1666 IPackageManager pm = ActivityThread.getPackageManager();
1667 try {
1668 if (pm.performDexOpt(packageName)) {
1669 mDidDexOpt = true;
1670 }
1671 } catch (RemoteException e) {
1672 }
1673 }
1674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 private boolean isNextTransitionForward() {
1676 int transit = mWindowManager.getPendingAppTransition();
1677 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1678 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1679 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1680 }
1681
1682 private final boolean realStartActivityLocked(HistoryRecord r,
1683 ProcessRecord app, boolean andResume, boolean checkConfig)
1684 throws RemoteException {
1685
1686 r.startFreezingScreenLocked(app, 0);
1687 mWindowManager.setAppVisibility(r, true);
1688
1689 // Have the window manager re-evaluate the orientation of
1690 // the screen based on the new activity order. Note that
1691 // as a result of this, it can call back into the activity
1692 // manager with a new orientation. We don't care about that,
1693 // because the activity is not currently running so we are
1694 // just restarting it anyway.
1695 if (checkConfig) {
1696 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001697 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 r.mayFreezeScreenLocked(app) ? r : null);
1699 updateConfigurationLocked(config, r);
1700 }
1701
1702 r.app = app;
1703
1704 if (localLOGV) Log.v(TAG, "Launching: " + r);
1705
1706 int idx = app.activities.indexOf(r);
1707 if (idx < 0) {
1708 app.activities.add(r);
1709 }
1710 updateLRUListLocked(app, true);
1711
1712 try {
1713 if (app.thread == null) {
1714 throw new RemoteException();
1715 }
1716 List<ResultInfo> results = null;
1717 List<Intent> newIntents = null;
1718 if (andResume) {
1719 results = r.results;
1720 newIntents = r.newIntents;
1721 }
1722 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1723 + " icicle=" + r.icicle
1724 + " with results=" + results + " newIntents=" + newIntents
1725 + " andResume=" + andResume);
1726 if (andResume) {
1727 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1728 System.identityHashCode(r),
1729 r.task.taskId, r.shortComponentName);
1730 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001731 if (r.isHomeActivity) {
1732 mHomeProcess = app;
1733 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001734 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001736 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 r.info, r.icicle, results, newIntents, !andResume,
1738 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 } catch (RemoteException e) {
1740 if (r.launchFailed) {
1741 // This is the second time we failed -- finish activity
1742 // and give up.
1743 Log.e(TAG, "Second failure launching "
1744 + r.intent.getComponent().flattenToShortString()
1745 + ", giving up", e);
1746 appDiedLocked(app, app.pid, app.thread);
1747 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1748 "2nd-crash");
1749 return false;
1750 }
1751
1752 // This is the first time we failed -- restart process and
1753 // retry.
1754 app.activities.remove(r);
1755 throw e;
1756 }
1757
1758 r.launchFailed = false;
1759 if (updateLRUListLocked(r)) {
1760 Log.w(TAG, "Activity " + r
1761 + " being launched, but already in LRU list");
1762 }
1763
1764 if (andResume) {
1765 // As part of the process of launching, ActivityThread also performs
1766 // a resume.
1767 r.state = ActivityState.RESUMED;
1768 r.icicle = null;
1769 r.haveState = false;
1770 r.stopped = false;
1771 mResumedActivity = r;
1772 r.task.touchActiveTime();
1773 completeResumeLocked(r);
1774 pauseIfSleepingLocked();
1775 } else {
1776 // This activity is not starting in the resumed state... which
1777 // should look like we asked it to pause+stop (but remain visible),
1778 // and it has done so and reported back the current icicle and
1779 // other state.
1780 r.state = ActivityState.STOPPED;
1781 r.stopped = true;
1782 }
1783
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001784 // Launch the new version setup screen if needed. We do this -after-
1785 // launching the initial activity (that is, home), so that it can have
1786 // a chance to initialize itself while in the background, making the
1787 // switch back to it faster and look better.
1788 startSetupActivityLocked();
1789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 return true;
1791 }
1792
1793 private final void startSpecificActivityLocked(HistoryRecord r,
1794 boolean andResume, boolean checkConfig) {
1795 // Is this activity's application already running?
1796 ProcessRecord app = getProcessRecordLocked(r.processName,
1797 r.info.applicationInfo.uid);
1798
1799 if (r.startTime == 0) {
1800 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001801 if (mInitialStartTime == 0) {
1802 mInitialStartTime = r.startTime;
1803 }
1804 } else if (mInitialStartTime == 0) {
1805 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807
1808 if (app != null && app.thread != null) {
1809 try {
1810 realStartActivityLocked(r, app, andResume, checkConfig);
1811 return;
1812 } catch (RemoteException e) {
1813 Log.w(TAG, "Exception when starting activity "
1814 + r.intent.getComponent().flattenToShortString(), e);
1815 }
1816
1817 // If a dead object exception was thrown -- fall through to
1818 // restart the application.
1819 }
1820
1821 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1822 "activity", r.intent.getComponent());
1823 }
1824
1825 private final ProcessRecord startProcessLocked(String processName,
1826 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1827 String hostingType, ComponentName hostingName) {
1828 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1829 // We don't have to do anything more if:
1830 // (1) There is an existing application record; and
1831 // (2) The caller doesn't think it is dead, OR there is no thread
1832 // object attached to it so we know it couldn't have crashed; and
1833 // (3) There is a pid assigned to it, so it is either starting or
1834 // already running.
1835 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1836 + " app=" + app + " knownToBeDead=" + knownToBeDead
1837 + " thread=" + (app != null ? app.thread : null)
1838 + " pid=" + (app != null ? app.pid : -1));
1839 if (app != null &&
1840 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1841 return app;
1842 }
1843
1844 String hostingNameStr = hostingName != null
1845 ? hostingName.flattenToShortString() : null;
1846
1847 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1848 // If we are in the background, then check to see if this process
1849 // is bad. If so, we will just silently fail.
1850 if (mBadProcesses.get(info.processName, info.uid) != null) {
1851 return null;
1852 }
1853 } else {
1854 // When the user is explicitly starting a process, then clear its
1855 // crash count so that we won't make it bad until they see at
1856 // least one crash dialog again, and make the process good again
1857 // if it had been bad.
1858 mProcessCrashTimes.remove(info.processName, info.uid);
1859 if (mBadProcesses.get(info.processName, info.uid) != null) {
1860 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1861 info.processName);
1862 mBadProcesses.remove(info.processName, info.uid);
1863 if (app != null) {
1864 app.bad = false;
1865 }
1866 }
1867 }
1868
1869 if (app == null) {
1870 app = newProcessRecordLocked(null, info, processName);
1871 mProcessNames.put(processName, info.uid, app);
1872 } else {
1873 // If this is a new package in the process, add the package to the list
1874 app.addPackage(info.packageName);
1875 }
1876
1877 // If the system is not ready yet, then hold off on starting this
1878 // process until it is.
1879 if (!mSystemReady
1880 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1881 if (!mProcessesOnHold.contains(app)) {
1882 mProcessesOnHold.add(app);
1883 }
1884 return app;
1885 }
1886
1887 startProcessLocked(app, hostingType, hostingNameStr);
1888 return (app.pid != 0) ? app : null;
1889 }
1890
1891 private final void startProcessLocked(ProcessRecord app,
1892 String hostingType, String hostingNameStr) {
1893 if (app.pid > 0 && app.pid != MY_PID) {
1894 synchronized (mPidsSelfLocked) {
1895 mPidsSelfLocked.remove(app.pid);
1896 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1897 }
1898 app.pid = 0;
1899 }
1900
1901 mProcessesOnHold.remove(app);
1902
1903 updateCpuStats();
1904
1905 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1906 mProcDeaths[0] = 0;
1907
1908 try {
1909 int uid = app.info.uid;
1910 int[] gids = null;
1911 try {
1912 gids = mContext.getPackageManager().getPackageGids(
1913 app.info.packageName);
1914 } catch (PackageManager.NameNotFoundException e) {
1915 Log.w(TAG, "Unable to retrieve gids", e);
1916 }
1917 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1918 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1919 && mTopComponent != null
1920 && app.processName.equals(mTopComponent.getPackageName())) {
1921 uid = 0;
1922 }
1923 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1924 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1925 uid = 0;
1926 }
1927 }
1928 int debugFlags = 0;
1929 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1930 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1931 }
1932 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1933 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1934 }
1935 if ("1".equals(SystemProperties.get("debug.assert"))) {
1936 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1937 }
1938 int pid = Process.start("android.app.ActivityThread",
1939 mSimpleProcessManagement ? app.processName : null, uid, uid,
1940 gids, debugFlags, null);
1941 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1942 synchronized (bs) {
1943 if (bs.isOnBattery()) {
1944 app.batteryStats.incStartsLocked();
1945 }
1946 }
1947
1948 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1949 app.processName, hostingType,
1950 hostingNameStr != null ? hostingNameStr : "");
1951
1952 if (app.persistent) {
1953 Watchdog.getInstance().processStarted(app, app.processName, pid);
1954 }
1955
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001956 StringBuilder buf = mStringBuilder;
1957 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 buf.append("Start proc ");
1959 buf.append(app.processName);
1960 buf.append(" for ");
1961 buf.append(hostingType);
1962 if (hostingNameStr != null) {
1963 buf.append(" ");
1964 buf.append(hostingNameStr);
1965 }
1966 buf.append(": pid=");
1967 buf.append(pid);
1968 buf.append(" uid=");
1969 buf.append(uid);
1970 buf.append(" gids={");
1971 if (gids != null) {
1972 for (int gi=0; gi<gids.length; gi++) {
1973 if (gi != 0) buf.append(", ");
1974 buf.append(gids[gi]);
1975
1976 }
1977 }
1978 buf.append("}");
1979 Log.i(TAG, buf.toString());
1980 if (pid == 0 || pid == MY_PID) {
1981 // Processes are being emulated with threads.
1982 app.pid = MY_PID;
1983 app.removed = false;
1984 mStartingProcesses.add(app);
1985 } else if (pid > 0) {
1986 app.pid = pid;
1987 app.removed = false;
1988 synchronized (mPidsSelfLocked) {
1989 this.mPidsSelfLocked.put(pid, app);
1990 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1991 msg.obj = app;
1992 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1993 }
1994 } else {
1995 app.pid = 0;
1996 RuntimeException e = new RuntimeException(
1997 "Failure starting process " + app.processName
1998 + ": returned pid=" + pid);
1999 Log.e(TAG, e.getMessage(), e);
2000 }
2001 } catch (RuntimeException e) {
2002 // XXX do better error recovery.
2003 app.pid = 0;
2004 Log.e(TAG, "Failure starting process " + app.processName, e);
2005 }
2006 }
2007
2008 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2009 if (mPausingActivity != null) {
2010 RuntimeException e = new RuntimeException();
2011 Log.e(TAG, "Trying to pause when pause is already pending for "
2012 + mPausingActivity, e);
2013 }
2014 HistoryRecord prev = mResumedActivity;
2015 if (prev == null) {
2016 RuntimeException e = new RuntimeException();
2017 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2018 resumeTopActivityLocked(null);
2019 return;
2020 }
2021 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2022 mResumedActivity = null;
2023 mPausingActivity = prev;
2024 mLastPausedActivity = prev;
2025 prev.state = ActivityState.PAUSING;
2026 prev.task.touchActiveTime();
2027
2028 updateCpuStats();
2029
2030 if (prev.app != null && prev.app.thread != null) {
2031 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2032 try {
2033 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2034 System.identityHashCode(prev),
2035 prev.shortComponentName);
2036 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2037 prev.configChangeFlags);
2038 updateUsageStats(prev, false);
2039 } catch (Exception e) {
2040 // Ignore exception, if process died other code will cleanup.
2041 Log.w(TAG, "Exception thrown during pause", e);
2042 mPausingActivity = null;
2043 mLastPausedActivity = null;
2044 }
2045 } else {
2046 mPausingActivity = null;
2047 mLastPausedActivity = null;
2048 }
2049
2050 // If we are not going to sleep, we want to ensure the device is
2051 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002052 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 mLaunchingActivity.acquire();
2054 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2055 // To be safe, don't allow the wake lock to be held for too long.
2056 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2057 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2058 }
2059 }
2060
2061
2062 if (mPausingActivity != null) {
2063 // Have the window manager pause its key dispatching until the new
2064 // activity has started. If we're pausing the activity just because
2065 // the screen is being turned off and the UI is sleeping, don't interrupt
2066 // key dispatch; the same activity will pick it up again on wakeup.
2067 if (!uiSleeping) {
2068 prev.pauseKeyDispatchingLocked();
2069 } else {
2070 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2071 }
2072
2073 // Schedule a pause timeout in case the app doesn't respond.
2074 // We don't give it much time because this directly impacts the
2075 // responsiveness seen by the user.
2076 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2077 msg.obj = prev;
2078 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2079 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2080 } else {
2081 // This activity failed to schedule the
2082 // pause, so just treat it as being paused now.
2083 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2084 resumeTopActivityLocked(null);
2085 }
2086 }
2087
2088 private final void completePauseLocked() {
2089 HistoryRecord prev = mPausingActivity;
2090 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2091
2092 if (prev != null) {
2093 if (prev.finishing) {
2094 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2095 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2096 } else if (prev.app != null) {
2097 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2098 if (prev.waitingVisible) {
2099 prev.waitingVisible = false;
2100 mWaitingVisibleActivities.remove(prev);
2101 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2102 TAG, "Complete pause, no longer waiting: " + prev);
2103 }
2104 if (prev.configDestroy) {
2105 // The previous is being paused because the configuration
2106 // is changing, which means it is actually stopping...
2107 // To juggle the fact that we are also starting a new
2108 // instance right now, we need to first completely stop
2109 // the current instance before starting the new one.
2110 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2111 destroyActivityLocked(prev, true);
2112 } else {
2113 mStoppingActivities.add(prev);
2114 if (mStoppingActivities.size() > 3) {
2115 // If we already have a few activities waiting to stop,
2116 // then give up on things going idle and start clearing
2117 // them out.
2118 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2119 Message msg = Message.obtain();
2120 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2121 mHandler.sendMessage(msg);
2122 }
2123 }
2124 } else {
2125 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2126 prev = null;
2127 }
2128 mPausingActivity = null;
2129 }
2130
Dianne Hackborn55280a92009-05-07 15:53:46 -07002131 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 resumeTopActivityLocked(prev);
2133 } else {
2134 if (mGoingToSleep.isHeld()) {
2135 mGoingToSleep.release();
2136 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002137 if (mShuttingDown) {
2138 notifyAll();
2139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140 }
2141
2142 if (prev != null) {
2143 prev.resumeKeyDispatchingLocked();
2144 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002145
2146 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2147 long diff = 0;
2148 synchronized (mProcessStatsThread) {
2149 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2150 }
2151 if (diff > 0) {
2152 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2153 synchronized (bsi) {
2154 BatteryStatsImpl.Uid.Proc ps =
2155 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2156 prev.info.packageName);
2157 if (ps != null) {
2158 ps.addForegroundTimeLocked(diff);
2159 }
2160 }
2161 }
2162 }
2163 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
2165
2166 /**
2167 * Once we know that we have asked an application to put an activity in
2168 * the resumed state (either by launching it or explicitly telling it),
2169 * this function updates the rest of our state to match that fact.
2170 */
2171 private final void completeResumeLocked(HistoryRecord next) {
2172 next.idle = false;
2173 next.results = null;
2174 next.newIntents = null;
2175
2176 // schedule an idle timeout in case the app doesn't do it for us.
2177 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2178 msg.obj = next;
2179 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2180
2181 if (false) {
2182 // The activity was never told to pause, so just keep
2183 // things going as-is. To maintain our own state,
2184 // we need to emulate it coming back and saying it is
2185 // idle.
2186 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2187 msg.obj = next;
2188 mHandler.sendMessage(msg);
2189 }
2190
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002191 reportResumedActivity(next);
2192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 next.thumbnail = null;
2194 setFocusedActivityLocked(next);
2195 next.resumeKeyDispatchingLocked();
2196 ensureActivitiesVisibleLocked(null, 0);
2197 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002198
2199 // Mark the point when the activity is resuming
2200 // TODO: To be more accurate, the mark should be before the onCreate,
2201 // not after the onResume. But for subsequent starts, onResume is fine.
2202 if (next.app != null) {
2203 synchronized (mProcessStatsThread) {
2204 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2205 }
2206 } else {
2207 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 }
2210
2211 /**
2212 * Make sure that all activities that need to be visible (that is, they
2213 * currently can be seen by the user) actually are.
2214 */
2215 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2216 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2217 if (DEBUG_VISBILITY) Log.v(
2218 TAG, "ensureActivitiesVisible behind " + top
2219 + " configChanges=0x" + Integer.toHexString(configChanges));
2220
2221 // If the top activity is not fullscreen, then we need to
2222 // make sure any activities under it are now visible.
2223 final int count = mHistory.size();
2224 int i = count-1;
2225 while (mHistory.get(i) != top) {
2226 i--;
2227 }
2228 HistoryRecord r;
2229 boolean behindFullscreen = false;
2230 for (; i>=0; i--) {
2231 r = (HistoryRecord)mHistory.get(i);
2232 if (DEBUG_VISBILITY) Log.v(
2233 TAG, "Make visible? " + r + " finishing=" + r.finishing
2234 + " state=" + r.state);
2235 if (r.finishing) {
2236 continue;
2237 }
2238
2239 final boolean doThisProcess = onlyThisProcess == null
2240 || onlyThisProcess.equals(r.processName);
2241
2242 // First: if this is not the current activity being started, make
2243 // sure it matches the current configuration.
2244 if (r != starting && doThisProcess) {
2245 ensureActivityConfigurationLocked(r, 0);
2246 }
2247
2248 if (r.app == null || r.app.thread == null) {
2249 if (onlyThisProcess == null
2250 || onlyThisProcess.equals(r.processName)) {
2251 // This activity needs to be visible, but isn't even
2252 // running... get it started, but don't resume it
2253 // at this point.
2254 if (DEBUG_VISBILITY) Log.v(
2255 TAG, "Start and freeze screen for " + r);
2256 if (r != starting) {
2257 r.startFreezingScreenLocked(r.app, configChanges);
2258 }
2259 if (!r.visible) {
2260 if (DEBUG_VISBILITY) Log.v(
2261 TAG, "Starting and making visible: " + r);
2262 mWindowManager.setAppVisibility(r, true);
2263 }
2264 if (r != starting) {
2265 startSpecificActivityLocked(r, false, false);
2266 }
2267 }
2268
2269 } else if (r.visible) {
2270 // If this activity is already visible, then there is nothing
2271 // else to do here.
2272 if (DEBUG_VISBILITY) Log.v(
2273 TAG, "Skipping: already visible at " + r);
2274 r.stopFreezingScreenLocked(false);
2275
2276 } else if (onlyThisProcess == null) {
2277 // This activity is not currently visible, but is running.
2278 // Tell it to become visible.
2279 r.visible = true;
2280 if (r.state != ActivityState.RESUMED && r != starting) {
2281 // If this activity is paused, tell it
2282 // to now show its window.
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Making visible and scheduling visibility: " + r);
2285 try {
2286 mWindowManager.setAppVisibility(r, true);
2287 r.app.thread.scheduleWindowVisibility(r, true);
2288 r.stopFreezingScreenLocked(false);
2289 } catch (Exception e) {
2290 // Just skip on any failure; we'll make it
2291 // visible when it next restarts.
2292 Log.w(TAG, "Exception thrown making visibile: "
2293 + r.intent.getComponent(), e);
2294 }
2295 }
2296 }
2297
2298 // Aggregate current change flags.
2299 configChanges |= r.configChangeFlags;
2300
2301 if (r.fullscreen) {
2302 // At this point, nothing else needs to be shown
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Stopping: fullscreen at " + r);
2305 behindFullscreen = true;
2306 i--;
2307 break;
2308 }
2309 }
2310
2311 // Now for any activities that aren't visible to the user, make
2312 // sure they no longer are keeping the screen frozen.
2313 while (i >= 0) {
2314 r = (HistoryRecord)mHistory.get(i);
2315 if (DEBUG_VISBILITY) Log.v(
2316 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2317 + " state=" + r.state
2318 + " behindFullscreen=" + behindFullscreen);
2319 if (!r.finishing) {
2320 if (behindFullscreen) {
2321 if (r.visible) {
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Making invisible: " + r);
2324 r.visible = false;
2325 try {
2326 mWindowManager.setAppVisibility(r, false);
2327 if ((r.state == ActivityState.STOPPING
2328 || r.state == ActivityState.STOPPED)
2329 && r.app != null && r.app.thread != null) {
2330 if (DEBUG_VISBILITY) Log.v(
2331 TAG, "Scheduling invisibility: " + r);
2332 r.app.thread.scheduleWindowVisibility(r, false);
2333 }
2334 } catch (Exception e) {
2335 // Just skip on any failure; we'll make it
2336 // visible when it next restarts.
2337 Log.w(TAG, "Exception thrown making hidden: "
2338 + r.intent.getComponent(), e);
2339 }
2340 } else {
2341 if (DEBUG_VISBILITY) Log.v(
2342 TAG, "Already invisible: " + r);
2343 }
2344 } else if (r.fullscreen) {
2345 if (DEBUG_VISBILITY) Log.v(
2346 TAG, "Now behindFullscreen: " + r);
2347 behindFullscreen = true;
2348 }
2349 }
2350 i--;
2351 }
2352 }
2353
2354 /**
2355 * Version of ensureActivitiesVisible that can easily be called anywhere.
2356 */
2357 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2358 int configChanges) {
2359 HistoryRecord r = topRunningActivityLocked(null);
2360 if (r != null) {
2361 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2362 }
2363 }
2364
2365 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2366 if (resumed) {
2367 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2368 } else {
2369 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2370 }
2371 }
2372
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002373 private boolean startHomeActivityLocked() {
2374 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2375 && mTopAction == null) {
2376 // We are running in factory test mode, but unable to find
2377 // the factory test app, so just sit around displaying the
2378 // error message and don't try to start anything.
2379 return false;
2380 }
2381 Intent intent = new Intent(
2382 mTopAction,
2383 mTopData != null ? Uri.parse(mTopData) : null);
2384 intent.setComponent(mTopComponent);
2385 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2386 intent.addCategory(Intent.CATEGORY_HOME);
2387 }
2388 ActivityInfo aInfo =
2389 intent.resolveActivityInfo(mContext.getPackageManager(),
2390 STOCK_PM_FLAGS);
2391 if (aInfo != null) {
2392 intent.setComponent(new ComponentName(
2393 aInfo.applicationInfo.packageName, aInfo.name));
2394 // Don't do this if the home app is currently being
2395 // instrumented.
2396 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2397 aInfo.applicationInfo.uid);
2398 if (app == null || app.instrumentationClass == null) {
2399 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2400 startActivityLocked(null, intent, null, null, 0, aInfo,
2401 null, null, 0, 0, 0, false, false);
2402 }
2403 }
2404
2405
2406 return true;
2407 }
2408
2409 /**
2410 * Starts the "new version setup screen" if appropriate.
2411 */
2412 private void startSetupActivityLocked() {
2413 // Only do this once per boot.
2414 if (mCheckedForSetup) {
2415 return;
2416 }
2417
2418 // We will show this screen if the current one is a different
2419 // version than the last one shown, and we are not running in
2420 // low-level factory test mode.
2421 final ContentResolver resolver = mContext.getContentResolver();
2422 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2423 Settings.Secure.getInt(resolver,
2424 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2425 mCheckedForSetup = true;
2426
2427 // See if we should be showing the platform update setup UI.
2428 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2429 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2430 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2431
2432 // We don't allow third party apps to replace this.
2433 ResolveInfo ri = null;
2434 for (int i=0; ris != null && i<ris.size(); i++) {
2435 if ((ris.get(i).activityInfo.applicationInfo.flags
2436 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2437 ri = ris.get(i);
2438 break;
2439 }
2440 }
2441
2442 if (ri != null) {
2443 String vers = ri.activityInfo.metaData != null
2444 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2445 : null;
2446 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2447 vers = ri.activityInfo.applicationInfo.metaData.getString(
2448 Intent.METADATA_SETUP_VERSION);
2449 }
2450 String lastVers = Settings.Secure.getString(
2451 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2452 if (vers != null && !vers.equals(lastVers)) {
2453 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2454 intent.setComponent(new ComponentName(
2455 ri.activityInfo.packageName, ri.activityInfo.name));
2456 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2457 null, null, 0, 0, 0, false, false);
2458 }
2459 }
2460 }
2461 }
2462
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002463 private void reportResumedActivity(HistoryRecord r) {
2464 //Log.i(TAG, "**** REPORT RESUME: " + r);
2465
2466 final int identHash = System.identityHashCode(r);
2467 updateUsageStats(r, true);
2468
2469 int i = mWatchers.beginBroadcast();
2470 while (i > 0) {
2471 i--;
2472 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2473 if (w != null) {
2474 try {
2475 w.activityResuming(identHash);
2476 } catch (RemoteException e) {
2477 }
2478 }
2479 }
2480 mWatchers.finishBroadcast();
2481 }
2482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 /**
2484 * Ensure that the top activity in the stack is resumed.
2485 *
2486 * @param prev The previously resumed activity, for when in the process
2487 * of pausing; can be null to call from elsewhere.
2488 *
2489 * @return Returns true if something is being resumed, or false if
2490 * nothing happened.
2491 */
2492 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2493 // Find the first activity that is not finishing.
2494 HistoryRecord next = topRunningActivityLocked(null);
2495
2496 // Remember how we'll process this pause/resume situation, and ensure
2497 // that the state is reset however we wind up proceeding.
2498 final boolean userLeaving = mUserLeaving;
2499 mUserLeaving = false;
2500
2501 if (next == null) {
2502 // There are no more activities! Let's just start up the
2503 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002504 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002505 }
2506
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002507 next.delayedResume = false;
2508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002509 // If the top activity is the resumed one, nothing to do.
2510 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2511 // Make sure we have executed any pending transitions, since there
2512 // should be nothing left to do at this point.
2513 mWindowManager.executeAppTransition();
2514 return false;
2515 }
2516
2517 // If we are sleeping, and there is no resumed activity, and the top
2518 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002519 if ((mSleeping || mShuttingDown)
2520 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 // Make sure we have executed any pending transitions, since there
2522 // should be nothing left to do at this point.
2523 mWindowManager.executeAppTransition();
2524 return false;
2525 }
2526
2527 // The activity may be waiting for stop, but that is no longer
2528 // appropriate for it.
2529 mStoppingActivities.remove(next);
2530 mWaitingVisibleActivities.remove(next);
2531
2532 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2533
2534 // If we are currently pausing an activity, then don't do anything
2535 // until that is done.
2536 if (mPausingActivity != null) {
2537 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2538 return false;
2539 }
2540
2541 // We need to start pausing the current activity so the top one
2542 // can be resumed...
2543 if (mResumedActivity != null) {
2544 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2545 startPausingLocked(userLeaving, false);
2546 return true;
2547 }
2548
2549 if (prev != null && prev != next) {
2550 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2551 prev.waitingVisible = true;
2552 mWaitingVisibleActivities.add(prev);
2553 if (DEBUG_SWITCH) Log.v(
2554 TAG, "Resuming top, waiting visible to hide: " + prev);
2555 } else {
2556 // The next activity is already visible, so hide the previous
2557 // activity's windows right now so we can show the new one ASAP.
2558 // We only do this if the previous is finishing, which should mean
2559 // it is on top of the one being resumed so hiding it quickly
2560 // is good. Otherwise, we want to do the normal route of allowing
2561 // the resumed activity to be shown so we can decide if the
2562 // previous should actually be hidden depending on whether the
2563 // new one is found to be full-screen or not.
2564 if (prev.finishing) {
2565 mWindowManager.setAppVisibility(prev, false);
2566 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2567 + prev + ", waitingVisible="
2568 + (prev != null ? prev.waitingVisible : null)
2569 + ", nowVisible=" + next.nowVisible);
2570 } else {
2571 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2572 + prev + ", waitingVisible="
2573 + (prev != null ? prev.waitingVisible : null)
2574 + ", nowVisible=" + next.nowVisible);
2575 }
2576 }
2577 }
2578
2579 // We are starting up the next activity, so tell the window manager
2580 // that the previous one will be hidden soon. This way it can know
2581 // to ignore it when computing the desired screen orientation.
2582 if (prev != null) {
2583 if (prev.finishing) {
2584 if (DEBUG_TRANSITION) Log.v(TAG,
2585 "Prepare close transition: prev=" + prev);
2586 mWindowManager.prepareAppTransition(prev.task == next.task
2587 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2588 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2589 mWindowManager.setAppWillBeHidden(prev);
2590 mWindowManager.setAppVisibility(prev, false);
2591 } else {
2592 if (DEBUG_TRANSITION) Log.v(TAG,
2593 "Prepare open transition: prev=" + prev);
2594 mWindowManager.prepareAppTransition(prev.task == next.task
2595 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2596 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2597 }
2598 if (false) {
2599 mWindowManager.setAppWillBeHidden(prev);
2600 mWindowManager.setAppVisibility(prev, false);
2601 }
2602 } else if (mHistory.size() > 1) {
2603 if (DEBUG_TRANSITION) Log.v(TAG,
2604 "Prepare open transition: no previous");
2605 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2606 }
2607
2608 if (next.app != null && next.app.thread != null) {
2609 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2610
2611 // This activity is now becoming visible.
2612 mWindowManager.setAppVisibility(next, true);
2613
2614 HistoryRecord lastResumedActivity = mResumedActivity;
2615 ActivityState lastState = next.state;
2616
2617 updateCpuStats();
2618
2619 next.state = ActivityState.RESUMED;
2620 mResumedActivity = next;
2621 next.task.touchActiveTime();
2622 updateLRUListLocked(next.app, true);
2623 updateLRUListLocked(next);
2624
2625 // Have the window manager re-evaluate the orientation of
2626 // the screen based on the new activity order.
2627 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002628 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 next.mayFreezeScreenLocked(next.app) ? next : null);
2630 if (config != null) {
2631 next.frozenBeforeDestroy = true;
2632 }
2633 if (!updateConfigurationLocked(config, next)) {
2634 // The configuration update wasn't able to keep the existing
2635 // instance of the activity, and instead started a new one.
2636 // We should be all done, but let's just make sure our activity
2637 // is still at the top and schedule another run if something
2638 // weird happened.
2639 HistoryRecord nextNext = topRunningActivityLocked(null);
2640 if (DEBUG_SWITCH) Log.i(TAG,
2641 "Activity config changed during resume: " + next
2642 + ", new next: " + nextNext);
2643 if (nextNext != next) {
2644 // Do over!
2645 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2646 }
2647 mWindowManager.executeAppTransition();
2648 return true;
2649 }
2650
2651 try {
2652 // Deliver all pending results.
2653 ArrayList a = next.results;
2654 if (a != null) {
2655 final int N = a.size();
2656 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002657 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 TAG, "Delivering results to " + next
2659 + ": " + a);
2660 next.app.thread.scheduleSendResult(next, a);
2661 }
2662 }
2663
2664 if (next.newIntents != null) {
2665 next.app.thread.scheduleNewIntent(next.newIntents, next);
2666 }
2667
2668 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2669 System.identityHashCode(next),
2670 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671
2672 next.app.thread.scheduleResumeActivity(next,
2673 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 pauseIfSleepingLocked();
2676
2677 } catch (Exception e) {
2678 // Whoops, need to restart this activity!
2679 next.state = lastState;
2680 mResumedActivity = lastResumedActivity;
2681 if (Config.LOGD) Log.d(TAG,
2682 "Restarting because process died: " + next);
2683 if (!next.hasBeenLaunched) {
2684 next.hasBeenLaunched = true;
2685 } else {
2686 if (SHOW_APP_STARTING_ICON) {
2687 mWindowManager.setAppStartingWindow(
2688 next, next.packageName, next.theme,
2689 next.nonLocalizedLabel,
2690 next.labelRes, next.icon, null, true);
2691 }
2692 }
2693 startSpecificActivityLocked(next, true, false);
2694 return true;
2695 }
2696
2697 // From this point on, if something goes wrong there is no way
2698 // to recover the activity.
2699 try {
2700 next.visible = true;
2701 completeResumeLocked(next);
2702 } catch (Exception e) {
2703 // If any exception gets thrown, toss away this
2704 // activity and try the next one.
2705 Log.w(TAG, "Exception thrown during resume of " + next, e);
2706 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2707 "resume-exception");
2708 return true;
2709 }
2710
2711 // Didn't need to use the icicle, and it is now out of date.
2712 next.icicle = null;
2713 next.haveState = false;
2714 next.stopped = false;
2715
2716 } else {
2717 // Whoops, need to restart this activity!
2718 if (!next.hasBeenLaunched) {
2719 next.hasBeenLaunched = true;
2720 } else {
2721 if (SHOW_APP_STARTING_ICON) {
2722 mWindowManager.setAppStartingWindow(
2723 next, next.packageName, next.theme,
2724 next.nonLocalizedLabel,
2725 next.labelRes, next.icon, null, true);
2726 }
2727 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2728 }
2729 startSpecificActivityLocked(next, true, true);
2730 }
2731
2732 return true;
2733 }
2734
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002735 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2736 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 final int NH = mHistory.size();
2738
2739 int addPos = -1;
2740
2741 if (!newTask) {
2742 // If starting in an existing task, find where that is...
2743 HistoryRecord next = null;
2744 boolean startIt = true;
2745 for (int i = NH-1; i >= 0; i--) {
2746 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2747 if (p.finishing) {
2748 continue;
2749 }
2750 if (p.task == r.task) {
2751 // Here it is! Now, if this is not yet visible to the
2752 // user, then just add it without starting; it will
2753 // get started when the user navigates back to it.
2754 addPos = i+1;
2755 if (!startIt) {
2756 mHistory.add(addPos, r);
2757 r.inHistory = true;
2758 r.task.numActivities++;
2759 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2760 r.info.screenOrientation, r.fullscreen);
2761 if (VALIDATE_TOKENS) {
2762 mWindowManager.validateAppTokens(mHistory);
2763 }
2764 return;
2765 }
2766 break;
2767 }
2768 if (p.fullscreen) {
2769 startIt = false;
2770 }
2771 next = p;
2772 }
2773 }
2774
2775 // Place a new activity at top of stack, so it is next to interact
2776 // with the user.
2777 if (addPos < 0) {
2778 addPos = mHistory.size();
2779 }
2780
2781 // If we are not placing the new activity frontmost, we do not want
2782 // to deliver the onUserLeaving callback to the actual frontmost
2783 // activity
2784 if (addPos < NH) {
2785 mUserLeaving = false;
2786 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2787 }
2788
2789 // Slot the activity into the history stack and proceed
2790 mHistory.add(addPos, r);
2791 r.inHistory = true;
2792 r.frontOfTask = newTask;
2793 r.task.numActivities++;
2794 if (NH > 0) {
2795 // We want to show the starting preview window if we are
2796 // switching to a new task, or the next activity's process is
2797 // not currently running.
2798 boolean showStartingIcon = newTask;
2799 ProcessRecord proc = r.app;
2800 if (proc == null) {
2801 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2802 }
2803 if (proc == null || proc.thread == null) {
2804 showStartingIcon = true;
2805 }
2806 if (DEBUG_TRANSITION) Log.v(TAG,
2807 "Prepare open transition: starting " + r);
2808 mWindowManager.prepareAppTransition(newTask
2809 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2810 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2811 mWindowManager.addAppToken(
2812 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2813 boolean doShow = true;
2814 if (newTask) {
2815 // Even though this activity is starting fresh, we still need
2816 // to reset it to make sure we apply affinities to move any
2817 // existing activities from other tasks in to it.
2818 // If the caller has requested that the target task be
2819 // reset, then do so.
2820 if ((r.intent.getFlags()
2821 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2822 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002823 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 }
2825 }
2826 if (SHOW_APP_STARTING_ICON && doShow) {
2827 // Figure out if we are transitioning from another activity that is
2828 // "has the same starting icon" as the next one. This allows the
2829 // window manager to keep the previous window it had previously
2830 // created, if it still had one.
2831 HistoryRecord prev = mResumedActivity;
2832 if (prev != null) {
2833 // We don't want to reuse the previous starting preview if:
2834 // (1) The current activity is in a different task.
2835 if (prev.task != r.task) prev = null;
2836 // (2) The current activity is already displayed.
2837 else if (prev.nowVisible) prev = null;
2838 }
2839 mWindowManager.setAppStartingWindow(
2840 r, r.packageName, r.theme, r.nonLocalizedLabel,
2841 r.labelRes, r.icon, prev, showStartingIcon);
2842 }
2843 } else {
2844 // If this is the first activity, don't do any fancy animations,
2845 // because there is nothing for it to animate on top of.
2846 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2847 r.info.screenOrientation, r.fullscreen);
2848 }
2849 if (VALIDATE_TOKENS) {
2850 mWindowManager.validateAppTokens(mHistory);
2851 }
2852
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002853 if (doResume) {
2854 resumeTopActivityLocked(null);
2855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002856 }
2857
2858 /**
2859 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002860 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2861 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 * an instance of that activity in the stack and, if found, finish all
2863 * activities on top of it and return the instance.
2864 *
2865 * @param newR Description of the new activity being started.
2866 * @return Returns the old activity that should be continue to be used,
2867 * or null if none was found.
2868 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002869 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002870 HistoryRecord newR, boolean doClear) {
2871 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002872
2873 // First find the requested task.
2874 while (i > 0) {
2875 i--;
2876 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2877 if (r.task.taskId == taskId) {
2878 i++;
2879 break;
2880 }
2881 }
2882
2883 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 while (i > 0) {
2885 i--;
2886 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2887 if (r.finishing) {
2888 continue;
2889 }
2890 if (r.task.taskId != taskId) {
2891 return null;
2892 }
2893 if (r.realActivity.equals(newR.realActivity)) {
2894 // Here it is! Now finish everything in front...
2895 HistoryRecord ret = r;
2896 if (doClear) {
2897 while (i < (mHistory.size()-1)) {
2898 i++;
2899 r = (HistoryRecord)mHistory.get(i);
2900 if (r.finishing) {
2901 continue;
2902 }
2903 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2904 null, "clear")) {
2905 i--;
2906 }
2907 }
2908 }
2909
2910 // Finally, if this is a normal launch mode (that is, not
2911 // expecting onNewIntent()), then we will finish the current
2912 // instance of the activity so a new fresh one can be started.
2913 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2914 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002915 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916 if (index >= 0) {
2917 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2918 null, "clear");
2919 }
2920 return null;
2921 }
2922 }
2923
2924 return ret;
2925 }
2926 }
2927
2928 return null;
2929 }
2930
2931 /**
2932 * Find the activity in the history stack within the given task. Returns
2933 * the index within the history at which it's found, or < 0 if not found.
2934 */
2935 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2936 int i = mHistory.size();
2937 while (i > 0) {
2938 i--;
2939 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2940 if (candidate.task.taskId != task) {
2941 break;
2942 }
2943 if (candidate.realActivity.equals(r.realActivity)) {
2944 return i;
2945 }
2946 }
2947
2948 return -1;
2949 }
2950
2951 /**
2952 * Reorder the history stack so that the activity at the given index is
2953 * brought to the front.
2954 */
2955 private final HistoryRecord moveActivityToFrontLocked(int where) {
2956 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2957 int top = mHistory.size();
2958 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2959 mHistory.add(top, newTop);
2960 oldTop.frontOfTask = false;
2961 newTop.frontOfTask = true;
2962 return newTop;
2963 }
2964
2965 /**
2966 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2967 * method will be called at the proper time.
2968 */
2969 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2970 boolean sent = false;
2971 if (r.state == ActivityState.RESUMED
2972 && r.app != null && r.app.thread != null) {
2973 try {
2974 ArrayList<Intent> ar = new ArrayList<Intent>();
2975 ar.add(new Intent(intent));
2976 r.app.thread.scheduleNewIntent(ar, r);
2977 sent = true;
2978 } catch (Exception e) {
2979 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2980 }
2981 }
2982 if (!sent) {
2983 r.addNewIntentLocked(new Intent(intent));
2984 }
2985 }
2986
2987 private final void logStartActivity(int tag, HistoryRecord r,
2988 TaskRecord task) {
2989 EventLog.writeEvent(tag,
2990 System.identityHashCode(r), task.taskId,
2991 r.shortComponentName, r.intent.getAction(),
2992 r.intent.getType(), r.intent.getDataString(),
2993 r.intent.getFlags());
2994 }
2995
2996 private final int startActivityLocked(IApplicationThread caller,
2997 Intent intent, String resolvedType,
2998 Uri[] grantedUriPermissions,
2999 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3000 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003001 int callingPid, int callingUid, boolean onlyIfNeeded,
3002 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 Log.i(TAG, "Starting activity: " + intent);
3004
3005 HistoryRecord sourceRecord = null;
3006 HistoryRecord resultRecord = null;
3007 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003008 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003009 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3011 if (index >= 0) {
3012 sourceRecord = (HistoryRecord)mHistory.get(index);
3013 if (requestCode >= 0 && !sourceRecord.finishing) {
3014 resultRecord = sourceRecord;
3015 }
3016 }
3017 }
3018
3019 int launchFlags = intent.getFlags();
3020
3021 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3022 && sourceRecord != null) {
3023 // Transfer the result target from the source activity to the new
3024 // one being started, including any failures.
3025 if (requestCode >= 0) {
3026 return START_FORWARD_AND_REQUEST_CONFLICT;
3027 }
3028 resultRecord = sourceRecord.resultTo;
3029 resultWho = sourceRecord.resultWho;
3030 requestCode = sourceRecord.requestCode;
3031 sourceRecord.resultTo = null;
3032 if (resultRecord != null) {
3033 resultRecord.removeResultsLocked(
3034 sourceRecord, resultWho, requestCode);
3035 }
3036 }
3037
3038 int err = START_SUCCESS;
3039
3040 if (intent.getComponent() == null) {
3041 // We couldn't find a class that can handle the given Intent.
3042 // That's the end of that!
3043 err = START_INTENT_NOT_RESOLVED;
3044 }
3045
3046 if (err == START_SUCCESS && aInfo == null) {
3047 // We couldn't find the specific class specified in the Intent.
3048 // Also the end of the line.
3049 err = START_CLASS_NOT_FOUND;
3050 }
3051
3052 ProcessRecord callerApp = null;
3053 if (err == START_SUCCESS && caller != null) {
3054 callerApp = getRecordForAppLocked(caller);
3055 if (callerApp != null) {
3056 callingPid = callerApp.pid;
3057 callingUid = callerApp.info.uid;
3058 } else {
3059 Log.w(TAG, "Unable to find app for caller " + caller
3060 + " (pid=" + callingPid + ") when starting: "
3061 + intent.toString());
3062 err = START_PERMISSION_DENIED;
3063 }
3064 }
3065
3066 if (err != START_SUCCESS) {
3067 if (resultRecord != null) {
3068 sendActivityResultLocked(-1,
3069 resultRecord, resultWho, requestCode,
3070 Activity.RESULT_CANCELED, null);
3071 }
3072 return err;
3073 }
3074
3075 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3076 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3077 if (perm != PackageManager.PERMISSION_GRANTED) {
3078 if (resultRecord != null) {
3079 sendActivityResultLocked(-1,
3080 resultRecord, resultWho, requestCode,
3081 Activity.RESULT_CANCELED, null);
3082 }
3083 String msg = "Permission Denial: starting " + intent.toString()
3084 + " from " + callerApp + " (pid=" + callingPid
3085 + ", uid=" + callingUid + ")"
3086 + " requires " + aInfo.permission;
3087 Log.w(TAG, msg);
3088 throw new SecurityException(msg);
3089 }
3090
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003091 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 boolean abort = false;
3093 try {
3094 // The Intent we give to the watcher has the extra data
3095 // stripped off, since it can contain private information.
3096 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003097 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098 aInfo.applicationInfo.packageName);
3099 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003100 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 }
3102
3103 if (abort) {
3104 if (resultRecord != null) {
3105 sendActivityResultLocked(-1,
3106 resultRecord, resultWho, requestCode,
3107 Activity.RESULT_CANCELED, null);
3108 }
3109 // We pretend to the caller that it was really started, but
3110 // they will just get a cancel result.
3111 return START_SUCCESS;
3112 }
3113 }
3114
3115 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3116 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003117 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003119 if (mResumedActivity == null
3120 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3121 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3122 PendingActivityLaunch pal = new PendingActivityLaunch();
3123 pal.r = r;
3124 pal.sourceRecord = sourceRecord;
3125 pal.grantedUriPermissions = grantedUriPermissions;
3126 pal.grantedMode = grantedMode;
3127 pal.onlyIfNeeded = onlyIfNeeded;
3128 mPendingActivityLaunches.add(pal);
3129 return START_SWITCHES_CANCELED;
3130 }
3131 }
3132
3133 if (mDidAppSwitch) {
3134 // This is the second allowed switch since we stopped switches,
3135 // so now just generally allow switches. Use case: user presses
3136 // home (switches disabled, switch to home, mDidAppSwitch now true);
3137 // user taps a home icon (coming from home so allowed, we hit here
3138 // and now allow anyone to switch again).
3139 mAppSwitchesAllowedTime = 0;
3140 } else {
3141 mDidAppSwitch = true;
3142 }
3143
3144 doPendingActivityLaunchesLocked(false);
3145
3146 return startActivityUncheckedLocked(r, sourceRecord,
3147 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3148 }
3149
3150 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3151 final int N = mPendingActivityLaunches.size();
3152 if (N <= 0) {
3153 return;
3154 }
3155 for (int i=0; i<N; i++) {
3156 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3157 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3158 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3159 doResume && i == (N-1));
3160 }
3161 mPendingActivityLaunches.clear();
3162 }
3163
3164 private final int startActivityUncheckedLocked(HistoryRecord r,
3165 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3166 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3167 final Intent intent = r.intent;
3168 final int callingUid = r.launchedFromUid;
3169
3170 int launchFlags = intent.getFlags();
3171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 // We'll invoke onUserLeaving before onPause only if the launching
3173 // activity did not explicitly state that this is an automated launch.
3174 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3175 if (DEBUG_USER_LEAVING) Log.v(TAG,
3176 "startActivity() => mUserLeaving=" + mUserLeaving);
3177
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003178 // If the caller has asked not to resume at this point, we make note
3179 // of this in the record so that we can skip it when trying to find
3180 // the top running activity.
3181 if (!doResume) {
3182 r.delayedResume = true;
3183 }
3184
3185 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3186 != 0 ? r : null;
3187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 // If the onlyIfNeeded flag is set, then we can do this if the activity
3189 // being launched is the same as the one making the call... or, as
3190 // a special case, if we do not know the caller then we count the
3191 // current top activity as the caller.
3192 if (onlyIfNeeded) {
3193 HistoryRecord checkedCaller = sourceRecord;
3194 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003195 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 }
3197 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3198 // Caller is not the same as launcher, so always needed.
3199 onlyIfNeeded = false;
3200 }
3201 }
3202
3203 if (grantedUriPermissions != null && callingUid > 0) {
3204 for (int i=0; i<grantedUriPermissions.length; i++) {
3205 grantUriPermissionLocked(callingUid, r.packageName,
3206 grantedUriPermissions[i], grantedMode, r);
3207 }
3208 }
3209
3210 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3211 intent, r);
3212
3213 if (sourceRecord == null) {
3214 // This activity is not being started from another... in this
3215 // case we -always- start a new task.
3216 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3217 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3218 + intent);
3219 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3220 }
3221 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3222 // The original activity who is starting us is running as a single
3223 // instance... this new activity it is starting must go on its
3224 // own task.
3225 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3226 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3227 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3228 // The activity being started is a single instance... it always
3229 // gets launched into its own task.
3230 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3231 }
3232
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003233 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 // For whatever reason this activity is being launched into a new
3235 // task... yet the caller has requested a result back. Well, that
3236 // is pretty messed up, so instead immediately send back a cancel
3237 // and let the new task continue launched as normal without a
3238 // dependency on its originator.
3239 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3240 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003241 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003242 Activity.RESULT_CANCELED, null);
3243 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 }
3245
3246 boolean addingToTask = false;
3247 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3248 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3249 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3250 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3251 // If bring to front is requested, and no result is requested, and
3252 // we can find a task that was started with this same
3253 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003254 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 // See if there is a task to bring to the front. If this is
3256 // a SINGLE_INSTANCE activity, there can be one and only one
3257 // instance of it in the history, and it is always in its own
3258 // unique task, so we do a special search.
3259 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3260 ? findTaskLocked(intent, r.info)
3261 : findActivityLocked(intent, r.info);
3262 if (taskTop != null) {
3263 if (taskTop.task.intent == null) {
3264 // This task was started because of movement of
3265 // the activity based on affinity... now that we
3266 // are actually launching it, we can assign the
3267 // base intent.
3268 taskTop.task.setIntent(intent, r.info);
3269 }
3270 // If the target task is not in the front, then we need
3271 // to bring it to the front... except... well, with
3272 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3273 // to have the same behavior as if a new instance was
3274 // being started, which means not bringing it to the front
3275 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003276 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 if (curTop.task != taskTop.task) {
3278 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3279 boolean callerAtFront = sourceRecord == null
3280 || curTop.task == sourceRecord.task;
3281 if (callerAtFront) {
3282 // We really do want to push this one into the
3283 // user's face, right now.
3284 moveTaskToFrontLocked(taskTop.task);
3285 }
3286 }
3287 // If the caller has requested that the target task be
3288 // reset, then do so.
3289 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3290 taskTop = resetTaskIfNeededLocked(taskTop, r);
3291 }
3292 if (onlyIfNeeded) {
3293 // We don't need to start a new activity, and
3294 // the client said not to do anything if that
3295 // is the case, so this is it! And for paranoia, make
3296 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003297 if (doResume) {
3298 resumeTopActivityLocked(null);
3299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 return START_RETURN_INTENT_TO_CALLER;
3301 }
3302 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3303 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3304 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3305 // In this situation we want to remove all activities
3306 // from the task up to the one being started. In most
3307 // cases this means we are resetting the task to its
3308 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003309 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 taskTop.task.taskId, r, true);
3311 if (top != null) {
3312 if (top.frontOfTask) {
3313 // Activity aliases may mean we use different
3314 // intents for the top activity, so make sure
3315 // the task now has the identity of the new
3316 // intent.
3317 top.task.setIntent(r.intent, r.info);
3318 }
3319 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3320 deliverNewIntentLocked(top, r.intent);
3321 } else {
3322 // A special case: we need to
3323 // start the activity because it is not currently
3324 // running, and the caller has asked to clear the
3325 // current task to have this activity at the top.
3326 addingToTask = true;
3327 // Now pretend like this activity is being started
3328 // by the top of its task, so it is put in the
3329 // right place.
3330 sourceRecord = taskTop;
3331 }
3332 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3333 // In this case the top activity on the task is the
3334 // same as the one being launched, so we take that
3335 // as a request to bring the task to the foreground.
3336 // If the top activity in the task is the root
3337 // activity, deliver this new intent to it if it
3338 // desires.
3339 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3340 && taskTop.realActivity.equals(r.realActivity)) {
3341 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3342 if (taskTop.frontOfTask) {
3343 taskTop.task.setIntent(r.intent, r.info);
3344 }
3345 deliverNewIntentLocked(taskTop, r.intent);
3346 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3347 // In this case we are launching the root activity
3348 // of the task, but with a different intent. We
3349 // should start a new instance on top.
3350 addingToTask = true;
3351 sourceRecord = taskTop;
3352 }
3353 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3354 // In this case an activity is being launched in to an
3355 // existing task, without resetting that task. This
3356 // is typically the situation of launching an activity
3357 // from a notification or shortcut. We want to place
3358 // the new activity on top of the current task.
3359 addingToTask = true;
3360 sourceRecord = taskTop;
3361 } else if (!taskTop.task.rootWasReset) {
3362 // In this case we are launching in to an existing task
3363 // that has not yet been started from its front door.
3364 // The current task has been brought to the front.
3365 // Ideally, we'd probably like to place this new task
3366 // at the bottom of its stack, but that's a little hard
3367 // to do with the current organization of the code so
3368 // for now we'll just drop it.
3369 taskTop.task.setIntent(r.intent, r.info);
3370 }
3371 if (!addingToTask) {
3372 // We didn't do anything... but it was needed (a.k.a., client
3373 // don't use that intent!) And for paranoia, make
3374 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003375 if (doResume) {
3376 resumeTopActivityLocked(null);
3377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 return START_TASK_TO_FRONT;
3379 }
3380 }
3381 }
3382 }
3383
3384 //String uri = r.intent.toURI();
3385 //Intent intent2 = new Intent(uri);
3386 //Log.i(TAG, "Given intent: " + r.intent);
3387 //Log.i(TAG, "URI is: " + uri);
3388 //Log.i(TAG, "To intent: " + intent2);
3389
3390 if (r.packageName != null) {
3391 // If the activity being launched is the same as the one currently
3392 // at the top, then we need to check if it should only be launched
3393 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003394 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3395 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 if (top.realActivity.equals(r.realActivity)) {
3397 if (top.app != null && top.app.thread != null) {
3398 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3399 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3400 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3401 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3402 // For paranoia, make sure we have correctly
3403 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003404 if (doResume) {
3405 resumeTopActivityLocked(null);
3406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 if (onlyIfNeeded) {
3408 // We don't need to start a new activity, and
3409 // the client said not to do anything if that
3410 // is the case, so this is it!
3411 return START_RETURN_INTENT_TO_CALLER;
3412 }
3413 deliverNewIntentLocked(top, r.intent);
3414 return START_DELIVERED_TO_TOP;
3415 }
3416 }
3417 }
3418 }
3419
3420 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003421 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003422 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003423 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 Activity.RESULT_CANCELED, null);
3425 }
3426 return START_CLASS_NOT_FOUND;
3427 }
3428
3429 boolean newTask = false;
3430
3431 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003432 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3434 // todo: should do better management of integers.
3435 mCurTask++;
3436 if (mCurTask <= 0) {
3437 mCurTask = 1;
3438 }
3439 r.task = new TaskRecord(mCurTask, r.info, intent,
3440 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3441 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3442 + " in new task " + r.task);
3443 newTask = true;
3444 addRecentTask(r.task);
3445
3446 } else if (sourceRecord != null) {
3447 if (!addingToTask &&
3448 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3449 // In this case, we are adding the activity to an existing
3450 // task, but the caller has asked to clear that task if the
3451 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003452 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453 sourceRecord.task.taskId, r, true);
3454 if (top != null) {
3455 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3456 deliverNewIntentLocked(top, r.intent);
3457 // For paranoia, make sure we have correctly
3458 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 if (doResume) {
3460 resumeTopActivityLocked(null);
3461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 return START_DELIVERED_TO_TOP;
3463 }
3464 } else if (!addingToTask &&
3465 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3466 // In this case, we are launching an activity in our own task
3467 // that may already be running somewhere in the history, and
3468 // we want to shuffle it to the front of the stack if so.
3469 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3470 if (where >= 0) {
3471 HistoryRecord top = moveActivityToFrontLocked(where);
3472 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3473 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003474 if (doResume) {
3475 resumeTopActivityLocked(null);
3476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 return START_DELIVERED_TO_TOP;
3478 }
3479 }
3480 // An existing activity is starting this new activity, so we want
3481 // to keep the new one in the same task as the one that is starting
3482 // it.
3483 r.task = sourceRecord.task;
3484 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3485 + " in existing task " + r.task);
3486
3487 } else {
3488 // This not being started from an existing activity, and not part
3489 // of a new task... just put it in the top task, though these days
3490 // this case should never happen.
3491 final int N = mHistory.size();
3492 HistoryRecord prev =
3493 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3494 r.task = prev != null
3495 ? prev.task
3496 : new TaskRecord(mCurTask, r.info, intent,
3497 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3498 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3499 + " in new guessed " + r.task);
3500 }
3501 if (newTask) {
3502 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3503 }
3504 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003505 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 return START_SUCCESS;
3507 }
3508
3509 public final int startActivity(IApplicationThread caller,
3510 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3511 int grantedMode, IBinder resultTo,
3512 String resultWho, int requestCode, boolean onlyIfNeeded,
3513 boolean debug) {
3514 // Refuse possible leaked file descriptors
3515 if (intent != null && intent.hasFileDescriptors()) {
3516 throw new IllegalArgumentException("File descriptors passed in Intent");
3517 }
3518
The Android Open Source Project4df24232009-03-05 14:34:35 -08003519 final boolean componentSpecified = intent.getComponent() != null;
3520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 // Don't modify the client's object!
3522 intent = new Intent(intent);
3523
3524 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 ActivityInfo aInfo;
3526 try {
3527 ResolveInfo rInfo =
3528 ActivityThread.getPackageManager().resolveIntent(
3529 intent, resolvedType,
3530 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003531 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 aInfo = rInfo != null ? rInfo.activityInfo : null;
3533 } catch (RemoteException e) {
3534 aInfo = null;
3535 }
3536
3537 if (aInfo != null) {
3538 // Store the found target back into the intent, because now that
3539 // we have it we never want to do this again. For example, if the
3540 // user navigates back to this point in the history, we should
3541 // always restart the exact same activity.
3542 intent.setComponent(new ComponentName(
3543 aInfo.applicationInfo.packageName, aInfo.name));
3544
3545 // Don't debug things in the system process
3546 if (debug) {
3547 if (!aInfo.processName.equals("system")) {
3548 setDebugApp(aInfo.processName, true, false);
3549 }
3550 }
3551 }
3552
3553 synchronized(this) {
3554 final long origId = Binder.clearCallingIdentity();
3555 int res = startActivityLocked(caller, intent, resolvedType,
3556 grantedUriPermissions, grantedMode, aInfo,
3557 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003558 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 Binder.restoreCallingIdentity(origId);
3560 return res;
3561 }
3562 }
3563
3564 public boolean startNextMatchingActivity(IBinder callingActivity,
3565 Intent intent) {
3566 // Refuse possible leaked file descriptors
3567 if (intent != null && intent.hasFileDescriptors() == true) {
3568 throw new IllegalArgumentException("File descriptors passed in Intent");
3569 }
3570
3571 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003572 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 if (index < 0) {
3574 return false;
3575 }
3576 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3577 if (r.app == null || r.app.thread == null) {
3578 // The caller is not running... d'oh!
3579 return false;
3580 }
3581 intent = new Intent(intent);
3582 // The caller is not allowed to change the data.
3583 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3584 // And we are resetting to find the next component...
3585 intent.setComponent(null);
3586
3587 ActivityInfo aInfo = null;
3588 try {
3589 List<ResolveInfo> resolves =
3590 ActivityThread.getPackageManager().queryIntentActivities(
3591 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003592 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593
3594 // Look for the original activity in the list...
3595 final int N = resolves != null ? resolves.size() : 0;
3596 for (int i=0; i<N; i++) {
3597 ResolveInfo rInfo = resolves.get(i);
3598 if (rInfo.activityInfo.packageName.equals(r.packageName)
3599 && rInfo.activityInfo.name.equals(r.info.name)) {
3600 // We found the current one... the next matching is
3601 // after it.
3602 i++;
3603 if (i<N) {
3604 aInfo = resolves.get(i).activityInfo;
3605 }
3606 break;
3607 }
3608 }
3609 } catch (RemoteException e) {
3610 }
3611
3612 if (aInfo == null) {
3613 // Nobody who is next!
3614 return false;
3615 }
3616
3617 intent.setComponent(new ComponentName(
3618 aInfo.applicationInfo.packageName, aInfo.name));
3619 intent.setFlags(intent.getFlags()&~(
3620 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3621 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3622 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3623 Intent.FLAG_ACTIVITY_NEW_TASK));
3624
3625 // Okay now we need to start the new activity, replacing the
3626 // currently running activity. This is a little tricky because
3627 // we want to start the new one as if the current one is finished,
3628 // but not finish the current one first so that there is no flicker.
3629 // And thus...
3630 final boolean wasFinishing = r.finishing;
3631 r.finishing = true;
3632
3633 // Propagate reply information over to the new activity.
3634 final HistoryRecord resultTo = r.resultTo;
3635 final String resultWho = r.resultWho;
3636 final int requestCode = r.requestCode;
3637 r.resultTo = null;
3638 if (resultTo != null) {
3639 resultTo.removeResultsLocked(r, resultWho, requestCode);
3640 }
3641
3642 final long origId = Binder.clearCallingIdentity();
3643 // XXX we are not dealing with propagating grantedUriPermissions...
3644 // those are not yet exposed to user code, so there is no need.
3645 int res = startActivityLocked(r.app.thread, intent,
3646 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003647 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 Binder.restoreCallingIdentity(origId);
3649
3650 r.finishing = wasFinishing;
3651 if (res != START_SUCCESS) {
3652 return false;
3653 }
3654 return true;
3655 }
3656 }
3657
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003658 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 Intent intent, String resolvedType, IBinder resultTo,
3660 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003661
3662 // This is so super not safe, that only the system (or okay root)
3663 // can do it.
3664 final int callingUid = Binder.getCallingUid();
3665 if (callingUid != 0 && callingUid != Process.myUid()) {
3666 throw new SecurityException(
3667 "startActivityInPackage only available to the system");
3668 }
3669
The Android Open Source Project4df24232009-03-05 14:34:35 -08003670 final boolean componentSpecified = intent.getComponent() != null;
3671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003672 // Don't modify the client's object!
3673 intent = new Intent(intent);
3674
3675 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 ActivityInfo aInfo;
3677 try {
3678 ResolveInfo rInfo =
3679 ActivityThread.getPackageManager().resolveIntent(
3680 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003681 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682 aInfo = rInfo != null ? rInfo.activityInfo : null;
3683 } catch (RemoteException e) {
3684 aInfo = null;
3685 }
3686
3687 if (aInfo != null) {
3688 // Store the found target back into the intent, because now that
3689 // we have it we never want to do this again. For example, if the
3690 // user navigates back to this point in the history, we should
3691 // always restart the exact same activity.
3692 intent.setComponent(new ComponentName(
3693 aInfo.applicationInfo.packageName, aInfo.name));
3694 }
3695
3696 synchronized(this) {
3697 return startActivityLocked(null, intent, resolvedType,
3698 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003699 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 }
3701 }
3702
3703 private final void addRecentTask(TaskRecord task) {
3704 // Remove any existing entries that are the same kind of task.
3705 int N = mRecentTasks.size();
3706 for (int i=0; i<N; i++) {
3707 TaskRecord tr = mRecentTasks.get(i);
3708 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3709 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3710 mRecentTasks.remove(i);
3711 i--;
3712 N--;
3713 if (task.intent == null) {
3714 // If the new recent task we are adding is not fully
3715 // specified, then replace it with the existing recent task.
3716 task = tr;
3717 }
3718 }
3719 }
3720 if (N >= MAX_RECENT_TASKS) {
3721 mRecentTasks.remove(N-1);
3722 }
3723 mRecentTasks.add(0, task);
3724 }
3725
3726 public void setRequestedOrientation(IBinder token,
3727 int requestedOrientation) {
3728 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003729 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003730 if (index < 0) {
3731 return;
3732 }
3733 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3734 final long origId = Binder.clearCallingIdentity();
3735 mWindowManager.setAppOrientation(r, requestedOrientation);
3736 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003737 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003738 r.mayFreezeScreenLocked(r.app) ? r : null);
3739 if (config != null) {
3740 r.frozenBeforeDestroy = true;
3741 if (!updateConfigurationLocked(config, r)) {
3742 resumeTopActivityLocked(null);
3743 }
3744 }
3745 Binder.restoreCallingIdentity(origId);
3746 }
3747 }
3748
3749 public int getRequestedOrientation(IBinder token) {
3750 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003751 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003752 if (index < 0) {
3753 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3754 }
3755 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3756 return mWindowManager.getAppOrientation(r);
3757 }
3758 }
3759
3760 private final void stopActivityLocked(HistoryRecord r) {
3761 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3762 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3763 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3764 if (!r.finishing) {
3765 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3766 "no-history");
3767 }
3768 } else if (r.app != null && r.app.thread != null) {
3769 if (mFocusedActivity == r) {
3770 setFocusedActivityLocked(topRunningActivityLocked(null));
3771 }
3772 r.resumeKeyDispatchingLocked();
3773 try {
3774 r.stopped = false;
3775 r.state = ActivityState.STOPPING;
3776 if (DEBUG_VISBILITY) Log.v(
3777 TAG, "Stopping visible=" + r.visible + " for " + r);
3778 if (!r.visible) {
3779 mWindowManager.setAppVisibility(r, false);
3780 }
3781 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3782 } catch (Exception e) {
3783 // Maybe just ignore exceptions here... if the process
3784 // has crashed, our death notification will clean things
3785 // up.
3786 Log.w(TAG, "Exception thrown during pause", e);
3787 // Just in case, assume it to be stopped.
3788 r.stopped = true;
3789 r.state = ActivityState.STOPPED;
3790 if (r.configDestroy) {
3791 destroyActivityLocked(r, true);
3792 }
3793 }
3794 }
3795 }
3796
3797 /**
3798 * @return Returns true if the activity is being finished, false if for
3799 * some reason it is being left as-is.
3800 */
3801 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3802 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003803 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 TAG, "Finishing activity: token=" + token
3805 + ", result=" + resultCode + ", data=" + resultData);
3806
Dianne Hackborn75b03852009-06-12 15:43:26 -07003807 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003808 if (index < 0) {
3809 return false;
3810 }
3811 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3812
3813 // Is this the last activity left?
3814 boolean lastActivity = true;
3815 for (int i=mHistory.size()-1; i>=0; i--) {
3816 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3817 if (!p.finishing && p != r) {
3818 lastActivity = false;
3819 break;
3820 }
3821 }
3822
3823 // If this is the last activity, but it is the home activity, then
3824 // just don't finish it.
3825 if (lastActivity) {
3826 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3827 return false;
3828 }
3829 }
3830
3831 finishActivityLocked(r, index, resultCode, resultData, reason);
3832 return true;
3833 }
3834
3835 /**
3836 * @return Returns true if this activity has been removed from the history
3837 * list, or false if it is still in the list and will be removed later.
3838 */
3839 private final boolean finishActivityLocked(HistoryRecord r, int index,
3840 int resultCode, Intent resultData, String reason) {
3841 if (r.finishing) {
3842 Log.w(TAG, "Duplicate finish request for " + r);
3843 return false;
3844 }
3845
3846 r.finishing = true;
3847 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3848 System.identityHashCode(r),
3849 r.task.taskId, r.shortComponentName, reason);
3850 r.task.numActivities--;
3851 if (r.frontOfTask && index < (mHistory.size()-1)) {
3852 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3853 if (next.task == r.task) {
3854 next.frontOfTask = true;
3855 }
3856 }
3857
3858 r.pauseKeyDispatchingLocked();
3859 if (mFocusedActivity == r) {
3860 setFocusedActivityLocked(topRunningActivityLocked(null));
3861 }
3862
3863 // send the result
3864 HistoryRecord resultTo = r.resultTo;
3865 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003866 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3867 + " who=" + r.resultWho + " req=" + r.requestCode
3868 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003869 if (r.info.applicationInfo.uid > 0) {
3870 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3871 r.packageName, resultData, r);
3872 }
3873 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3874 resultData);
3875 r.resultTo = null;
3876 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003877 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878
3879 // Make sure this HistoryRecord is not holding on to other resources,
3880 // because clients have remote IPC references to this object so we
3881 // can't assume that will go away and want to avoid circular IPC refs.
3882 r.results = null;
3883 r.pendingResults = null;
3884 r.newIntents = null;
3885 r.icicle = null;
3886
3887 if (mPendingThumbnails.size() > 0) {
3888 // There are clients waiting to receive thumbnails so, in case
3889 // this is an activity that someone is waiting for, add it
3890 // to the pending list so we can correctly update the clients.
3891 mCancelledThumbnails.add(r);
3892 }
3893
3894 if (mResumedActivity == r) {
3895 boolean endTask = index <= 0
3896 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3897 if (DEBUG_TRANSITION) Log.v(TAG,
3898 "Prepare close transition: finishing " + r);
3899 mWindowManager.prepareAppTransition(endTask
3900 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3901 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3902
3903 // Tell window manager to prepare for this one to be removed.
3904 mWindowManager.setAppVisibility(r, false);
3905
3906 if (mPausingActivity == null) {
3907 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3908 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3909 startPausingLocked(false, false);
3910 }
3911
3912 } else if (r.state != ActivityState.PAUSING) {
3913 // If the activity is PAUSING, we will complete the finish once
3914 // it is done pausing; else we can just directly finish it here.
3915 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3916 return finishCurrentActivityLocked(r, index,
3917 FINISH_AFTER_PAUSE) == null;
3918 } else {
3919 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3920 }
3921
3922 return false;
3923 }
3924
3925 private static final int FINISH_IMMEDIATELY = 0;
3926 private static final int FINISH_AFTER_PAUSE = 1;
3927 private static final int FINISH_AFTER_VISIBLE = 2;
3928
3929 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3930 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003931 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003932 if (index < 0) {
3933 return null;
3934 }
3935
3936 return finishCurrentActivityLocked(r, index, mode);
3937 }
3938
3939 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3940 int index, int mode) {
3941 // First things first: if this activity is currently visible,
3942 // and the resumed activity is not yet visible, then hold off on
3943 // finishing until the resumed one becomes visible.
3944 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3945 if (!mStoppingActivities.contains(r)) {
3946 mStoppingActivities.add(r);
3947 if (mStoppingActivities.size() > 3) {
3948 // If we already have a few activities waiting to stop,
3949 // then give up on things going idle and start clearing
3950 // them out.
3951 Message msg = Message.obtain();
3952 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3953 mHandler.sendMessage(msg);
3954 }
3955 }
3956 r.state = ActivityState.STOPPING;
3957 updateOomAdjLocked();
3958 return r;
3959 }
3960
3961 // make sure the record is cleaned out of other places.
3962 mStoppingActivities.remove(r);
3963 mWaitingVisibleActivities.remove(r);
3964 if (mResumedActivity == r) {
3965 mResumedActivity = null;
3966 }
3967 final ActivityState prevState = r.state;
3968 r.state = ActivityState.FINISHING;
3969
3970 if (mode == FINISH_IMMEDIATELY
3971 || prevState == ActivityState.STOPPED
3972 || prevState == ActivityState.INITIALIZING) {
3973 // If this activity is already stopped, we can just finish
3974 // it right now.
3975 return destroyActivityLocked(r, true) ? null : r;
3976 } else {
3977 // Need to go through the full pause cycle to get this
3978 // activity into the stopped state and then finish it.
3979 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3980 mFinishingActivities.add(r);
3981 resumeTopActivityLocked(null);
3982 }
3983 return r;
3984 }
3985
3986 /**
3987 * This is the internal entry point for handling Activity.finish().
3988 *
3989 * @param token The Binder token referencing the Activity we want to finish.
3990 * @param resultCode Result code, if any, from this Activity.
3991 * @param resultData Result data (Intent), if any, from this Activity.
3992 *
3993 * @result Returns true if the activity successfully finished, or false if it is still running.
3994 */
3995 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3996 // Refuse possible leaked file descriptors
3997 if (resultData != null && resultData.hasFileDescriptors() == true) {
3998 throw new IllegalArgumentException("File descriptors passed in Intent");
3999 }
4000
4001 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004002 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004003 // Find the first activity that is not finishing.
4004 HistoryRecord next = topRunningActivityLocked(token, 0);
4005 if (next != null) {
4006 // ask watcher if this is allowed
4007 boolean resumeOK = true;
4008 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004009 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004010 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004011 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004012 }
4013
4014 if (!resumeOK) {
4015 return false;
4016 }
4017 }
4018 }
4019 final long origId = Binder.clearCallingIdentity();
4020 boolean res = requestFinishActivityLocked(token, resultCode,
4021 resultData, "app-request");
4022 Binder.restoreCallingIdentity(origId);
4023 return res;
4024 }
4025 }
4026
4027 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4028 String resultWho, int requestCode, int resultCode, Intent data) {
4029
4030 if (callingUid > 0) {
4031 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4032 data, r);
4033 }
4034
The Android Open Source Project10592532009-03-18 17:39:46 -07004035 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4036 + " : who=" + resultWho + " req=" + requestCode
4037 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004038 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4039 try {
4040 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4041 list.add(new ResultInfo(resultWho, requestCode,
4042 resultCode, data));
4043 r.app.thread.scheduleSendResult(r, list);
4044 return;
4045 } catch (Exception e) {
4046 Log.w(TAG, "Exception thrown sending result to " + r, e);
4047 }
4048 }
4049
4050 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4051 }
4052
4053 public final void finishSubActivity(IBinder token, String resultWho,
4054 int requestCode) {
4055 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004056 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004057 if (index < 0) {
4058 return;
4059 }
4060 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4061
4062 final long origId = Binder.clearCallingIdentity();
4063
4064 int i;
4065 for (i=mHistory.size()-1; i>=0; i--) {
4066 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4067 if (r.resultTo == self && r.requestCode == requestCode) {
4068 if ((r.resultWho == null && resultWho == null) ||
4069 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4070 finishActivityLocked(r, i,
4071 Activity.RESULT_CANCELED, null, "request-sub");
4072 }
4073 }
4074 }
4075
4076 Binder.restoreCallingIdentity(origId);
4077 }
4078 }
4079
4080 /**
4081 * Perform clean-up of service connections in an activity record.
4082 */
4083 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4084 // Throw away any services that have been bound by this activity.
4085 if (r.connections != null) {
4086 Iterator<ConnectionRecord> it = r.connections.iterator();
4087 while (it.hasNext()) {
4088 ConnectionRecord c = it.next();
4089 removeConnectionLocked(c, null, r);
4090 }
4091 r.connections = null;
4092 }
4093 }
4094
4095 /**
4096 * Perform the common clean-up of an activity record. This is called both
4097 * as part of destroyActivityLocked() (when destroying the client-side
4098 * representation) and cleaning things up as a result of its hosting
4099 * processing going away, in which case there is no remaining client-side
4100 * state to destroy so only the cleanup here is needed.
4101 */
4102 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4103 if (mResumedActivity == r) {
4104 mResumedActivity = null;
4105 }
4106 if (mFocusedActivity == r) {
4107 mFocusedActivity = null;
4108 }
4109
4110 r.configDestroy = false;
4111 r.frozenBeforeDestroy = false;
4112
4113 // Make sure this record is no longer in the pending finishes list.
4114 // This could happen, for example, if we are trimming activities
4115 // down to the max limit while they are still waiting to finish.
4116 mFinishingActivities.remove(r);
4117 mWaitingVisibleActivities.remove(r);
4118
4119 // Remove any pending results.
4120 if (r.finishing && r.pendingResults != null) {
4121 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4122 PendingIntentRecord rec = apr.get();
4123 if (rec != null) {
4124 cancelIntentSenderLocked(rec, false);
4125 }
4126 }
4127 r.pendingResults = null;
4128 }
4129
4130 if (cleanServices) {
4131 cleanUpActivityServicesLocked(r);
4132 }
4133
4134 if (mPendingThumbnails.size() > 0) {
4135 // There are clients waiting to receive thumbnails so, in case
4136 // this is an activity that someone is waiting for, add it
4137 // to the pending list so we can correctly update the clients.
4138 mCancelledThumbnails.add(r);
4139 }
4140
4141 // Get rid of any pending idle timeouts.
4142 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4143 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4144 }
4145
4146 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4147 if (r.state != ActivityState.DESTROYED) {
4148 mHistory.remove(r);
4149 r.inHistory = false;
4150 r.state = ActivityState.DESTROYED;
4151 mWindowManager.removeAppToken(r);
4152 if (VALIDATE_TOKENS) {
4153 mWindowManager.validateAppTokens(mHistory);
4154 }
4155 cleanUpActivityServicesLocked(r);
4156 removeActivityUriPermissionsLocked(r);
4157 }
4158 }
4159
4160 /**
4161 * Destroy the current CLIENT SIDE instance of an activity. This may be
4162 * called both when actually finishing an activity, or when performing
4163 * a configuration switch where we destroy the current client-side object
4164 * but then create a new client-side object for this same HistoryRecord.
4165 */
4166 private final boolean destroyActivityLocked(HistoryRecord r,
4167 boolean removeFromApp) {
4168 if (DEBUG_SWITCH) Log.v(
4169 TAG, "Removing activity: token=" + r
4170 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4171 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4172 System.identityHashCode(r),
4173 r.task.taskId, r.shortComponentName);
4174
4175 boolean removedFromHistory = false;
4176
4177 cleanUpActivityLocked(r, false);
4178
4179 if (r.app != null) {
4180 if (removeFromApp) {
4181 int idx = r.app.activities.indexOf(r);
4182 if (idx >= 0) {
4183 r.app.activities.remove(idx);
4184 }
4185 if (r.persistent) {
4186 decPersistentCountLocked(r.app);
4187 }
4188 }
4189
4190 boolean skipDestroy = false;
4191
4192 try {
4193 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4194 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4195 r.configChangeFlags);
4196 } catch (Exception e) {
4197 // We can just ignore exceptions here... if the process
4198 // has crashed, our death notification will clean things
4199 // up.
4200 //Log.w(TAG, "Exception thrown during finish", e);
4201 if (r.finishing) {
4202 removeActivityFromHistoryLocked(r);
4203 removedFromHistory = true;
4204 skipDestroy = true;
4205 }
4206 }
4207
4208 r.app = null;
4209 r.nowVisible = false;
4210
4211 if (r.finishing && !skipDestroy) {
4212 r.state = ActivityState.DESTROYING;
4213 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4214 msg.obj = r;
4215 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4216 } else {
4217 r.state = ActivityState.DESTROYED;
4218 }
4219 } else {
4220 // remove this record from the history.
4221 if (r.finishing) {
4222 removeActivityFromHistoryLocked(r);
4223 removedFromHistory = true;
4224 } else {
4225 r.state = ActivityState.DESTROYED;
4226 }
4227 }
4228
4229 r.configChangeFlags = 0;
4230
4231 if (!mLRUActivities.remove(r)) {
4232 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4233 }
4234
4235 return removedFromHistory;
4236 }
4237
4238 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4239 ProcessRecord app)
4240 {
4241 int i = list.size();
4242 if (localLOGV) Log.v(
4243 TAG, "Removing app " + app + " from list " + list
4244 + " with " + i + " entries");
4245 while (i > 0) {
4246 i--;
4247 HistoryRecord r = (HistoryRecord)list.get(i);
4248 if (localLOGV) Log.v(
4249 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4250 if (r.app == app) {
4251 if (localLOGV) Log.v(TAG, "Removing this entry!");
4252 list.remove(i);
4253 }
4254 }
4255 }
4256
4257 /**
4258 * Main function for removing an existing process from the activity manager
4259 * as a result of that process going away. Clears out all connections
4260 * to the process.
4261 */
4262 private final void handleAppDiedLocked(ProcessRecord app,
4263 boolean restarting) {
4264 cleanUpApplicationRecordLocked(app, restarting, -1);
4265 if (!restarting) {
4266 mLRUProcesses.remove(app);
4267 }
4268
4269 // Just in case...
4270 if (mPausingActivity != null && mPausingActivity.app == app) {
4271 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4272 mPausingActivity = null;
4273 }
4274 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4275 mLastPausedActivity = null;
4276 }
4277
4278 // Remove this application's activities from active lists.
4279 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4280 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4281 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4282 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4283
4284 boolean atTop = true;
4285 boolean hasVisibleActivities = false;
4286
4287 // Clean out the history list.
4288 int i = mHistory.size();
4289 if (localLOGV) Log.v(
4290 TAG, "Removing app " + app + " from history with " + i + " entries");
4291 while (i > 0) {
4292 i--;
4293 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4294 if (localLOGV) Log.v(
4295 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4296 if (r.app == app) {
4297 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4298 if (localLOGV) Log.v(
4299 TAG, "Removing this entry! frozen=" + r.haveState
4300 + " finishing=" + r.finishing);
4301 mHistory.remove(i);
4302
4303 r.inHistory = false;
4304 mWindowManager.removeAppToken(r);
4305 if (VALIDATE_TOKENS) {
4306 mWindowManager.validateAppTokens(mHistory);
4307 }
4308 removeActivityUriPermissionsLocked(r);
4309
4310 } else {
4311 // We have the current state for this activity, so
4312 // it can be restarted later when needed.
4313 if (localLOGV) Log.v(
4314 TAG, "Keeping entry, setting app to null");
4315 if (r.visible) {
4316 hasVisibleActivities = true;
4317 }
4318 r.app = null;
4319 r.nowVisible = false;
4320 if (!r.haveState) {
4321 r.icicle = null;
4322 }
4323 }
4324
4325 cleanUpActivityLocked(r, true);
4326 r.state = ActivityState.STOPPED;
4327 }
4328 atTop = false;
4329 }
4330
4331 app.activities.clear();
4332
4333 if (app.instrumentationClass != null) {
4334 Log.w(TAG, "Crash of app " + app.processName
4335 + " running instrumentation " + app.instrumentationClass);
4336 Bundle info = new Bundle();
4337 info.putString("shortMsg", "Process crashed.");
4338 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4339 }
4340
4341 if (!restarting) {
4342 if (!resumeTopActivityLocked(null)) {
4343 // If there was nothing to resume, and we are not already
4344 // restarting this process, but there is a visible activity that
4345 // is hosted by the process... then make sure all visible
4346 // activities are running, taking care of restarting this
4347 // process.
4348 if (hasVisibleActivities) {
4349 ensureActivitiesVisibleLocked(null, 0);
4350 }
4351 }
4352 }
4353 }
4354
4355 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4356 IBinder threadBinder = thread.asBinder();
4357
4358 // Find the application record.
4359 int count = mLRUProcesses.size();
4360 int i;
4361 for (i=0; i<count; i++) {
4362 ProcessRecord rec = mLRUProcesses.get(i);
4363 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4364 return i;
4365 }
4366 }
4367 return -1;
4368 }
4369
4370 private final ProcessRecord getRecordForAppLocked(
4371 IApplicationThread thread) {
4372 if (thread == null) {
4373 return null;
4374 }
4375
4376 int appIndex = getLRURecordIndexForAppLocked(thread);
4377 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4378 }
4379
4380 private final void appDiedLocked(ProcessRecord app, int pid,
4381 IApplicationThread thread) {
4382
4383 mProcDeaths[0]++;
4384
4385 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4386 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4387 + ") has died.");
4388 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4389 if (localLOGV) Log.v(
4390 TAG, "Dying app: " + app + ", pid: " + pid
4391 + ", thread: " + thread.asBinder());
4392 boolean doLowMem = app.instrumentationClass == null;
4393 handleAppDiedLocked(app, false);
4394
4395 if (doLowMem) {
4396 // If there are no longer any background processes running,
4397 // and the app that died was not running instrumentation,
4398 // then tell everyone we are now low on memory.
4399 boolean haveBg = false;
4400 int count = mLRUProcesses.size();
4401 int i;
4402 for (i=0; i<count; i++) {
4403 ProcessRecord rec = mLRUProcesses.get(i);
4404 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4405 haveBg = true;
4406 break;
4407 }
4408 }
4409
4410 if (!haveBg) {
4411 Log.i(TAG, "Low Memory: No more background processes.");
4412 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4413 for (i=0; i<count; i++) {
4414 ProcessRecord rec = mLRUProcesses.get(i);
4415 if (rec.thread != null) {
4416 rec.lastRequestedGc = SystemClock.uptimeMillis();
4417 try {
4418 rec.thread.scheduleLowMemory();
4419 } catch (RemoteException e) {
4420 // Don't care if the process is gone.
4421 }
4422 }
4423 }
4424 }
4425 }
4426 } else if (Config.LOGD) {
4427 Log.d(TAG, "Received spurious death notification for thread "
4428 + thread.asBinder());
4429 }
4430 }
4431
4432 final String readFile(String filename) {
4433 try {
4434 FileInputStream fs = new FileInputStream(filename);
4435 byte[] inp = new byte[8192];
4436 int size = fs.read(inp);
4437 fs.close();
4438 return new String(inp, 0, 0, size);
4439 } catch (java.io.IOException e) {
4440 }
4441 return "";
4442 }
4443
4444 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4445 final String annotation) {
4446 if (app.notResponding || app.crashing) {
4447 return;
4448 }
4449
4450 // Log the ANR to the event log.
4451 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4452
4453 // If we are on a secure build and the application is not interesting to the user (it is
4454 // not visible or in the background), just kill it instead of displaying a dialog.
4455 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4456 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4457 Process.killProcess(app.pid);
4458 return;
4459 }
4460
4461 // DeviceMonitor.start();
4462
4463 String processInfo = null;
4464 if (MONITOR_CPU_USAGE) {
4465 updateCpuStatsNow();
4466 synchronized (mProcessStatsThread) {
4467 processInfo = mProcessStats.printCurrentState();
4468 }
4469 }
4470
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004471 StringBuilder info = mStringBuilder;
4472 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004473 info.append("ANR (application not responding) in process: ");
4474 info.append(app.processName);
4475 if (annotation != null) {
4476 info.append("\nAnnotation: ");
4477 info.append(annotation);
4478 }
4479 if (MONITOR_CPU_USAGE) {
4480 info.append("\nCPU usage:\n");
4481 info.append(processInfo);
4482 }
4483 Log.i(TAG, info.toString());
4484
4485 // The application is not responding. Dump as many thread traces as we can.
4486 boolean fileDump = prepareTraceFile(true);
4487 if (!fileDump) {
4488 // Dumping traces to the log, just dump the process that isn't responding so
4489 // we don't overflow the log
4490 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4491 } else {
4492 // Dumping traces to a file so dump all active processes we know about
4493 synchronized (this) {
4494 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4495 ProcessRecord r = mLRUProcesses.get(i);
4496 if (r.thread != null) {
4497 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4498 }
4499 }
4500 }
4501 }
4502
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004503 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004504 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004505 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004506 app.pid, info.toString());
4507 if (res != 0) {
4508 if (res < 0) {
4509 // wait until the SIGQUIT has had a chance to process before killing the
4510 // process.
4511 try {
4512 wait(2000);
4513 } catch (InterruptedException e) {
4514 }
4515
4516 Process.killProcess(app.pid);
4517 return;
4518 }
4519 }
4520 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004521 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004522 }
4523 }
4524
4525 makeAppNotRespondingLocked(app,
4526 activity != null ? activity.shortComponentName : null,
4527 annotation != null ? "ANR " + annotation : "ANR",
4528 info.toString(), null);
4529 Message msg = Message.obtain();
4530 HashMap map = new HashMap();
4531 msg.what = SHOW_NOT_RESPONDING_MSG;
4532 msg.obj = map;
4533 map.put("app", app);
4534 if (activity != null) {
4535 map.put("activity", activity);
4536 }
4537
4538 mHandler.sendMessage(msg);
4539 return;
4540 }
4541
4542 /**
4543 * If a stack trace file has been configured, prepare the filesystem
4544 * by creating the directory if it doesn't exist and optionally
4545 * removing the old trace file.
4546 *
4547 * @param removeExisting If set, the existing trace file will be removed.
4548 * @return Returns true if the trace file preparations succeeded
4549 */
4550 public static boolean prepareTraceFile(boolean removeExisting) {
4551 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4552 boolean fileReady = false;
4553 if (!TextUtils.isEmpty(tracesPath)) {
4554 File f = new File(tracesPath);
4555 if (!f.exists()) {
4556 // Ensure the enclosing directory exists
4557 File dir = f.getParentFile();
4558 if (!dir.exists()) {
4559 fileReady = dir.mkdirs();
4560 FileUtils.setPermissions(dir.getAbsolutePath(),
4561 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4562 } else if (dir.isDirectory()) {
4563 fileReady = true;
4564 }
4565 } else if (removeExisting) {
4566 // Remove the previous traces file, so we don't fill the disk.
4567 // The VM will recreate it
4568 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4569 fileReady = f.delete();
4570 }
4571 }
4572
4573 return fileReady;
4574 }
4575
4576
4577 private final void decPersistentCountLocked(ProcessRecord app)
4578 {
4579 app.persistentActivities--;
4580 if (app.persistentActivities > 0) {
4581 // Still more of 'em...
4582 return;
4583 }
4584 if (app.persistent) {
4585 // Ah, but the application itself is persistent. Whatever!
4586 return;
4587 }
4588
4589 // App is no longer persistent... make sure it and the ones
4590 // following it in the LRU list have the correc oom_adj.
4591 updateOomAdjLocked();
4592 }
4593
4594 public void setPersistent(IBinder token, boolean isPersistent) {
4595 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4596 != PackageManager.PERMISSION_GRANTED) {
4597 String msg = "Permission Denial: setPersistent() from pid="
4598 + Binder.getCallingPid()
4599 + ", uid=" + Binder.getCallingUid()
4600 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4601 Log.w(TAG, msg);
4602 throw new SecurityException(msg);
4603 }
4604
4605 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004606 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004607 if (index < 0) {
4608 return;
4609 }
4610 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4611 ProcessRecord app = r.app;
4612
4613 if (localLOGV) Log.v(
4614 TAG, "Setting persistence " + isPersistent + ": " + r);
4615
4616 if (isPersistent) {
4617 if (r.persistent) {
4618 // Okay okay, I heard you already!
4619 if (localLOGV) Log.v(TAG, "Already persistent!");
4620 return;
4621 }
4622 r.persistent = true;
4623 app.persistentActivities++;
4624 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4625 if (app.persistentActivities > 1) {
4626 // We aren't the first...
4627 if (localLOGV) Log.v(TAG, "Not the first!");
4628 return;
4629 }
4630 if (app.persistent) {
4631 // This would be redundant.
4632 if (localLOGV) Log.v(TAG, "App is persistent!");
4633 return;
4634 }
4635
4636 // App is now persistent... make sure it and the ones
4637 // following it now have the correct oom_adj.
4638 final long origId = Binder.clearCallingIdentity();
4639 updateOomAdjLocked();
4640 Binder.restoreCallingIdentity(origId);
4641
4642 } else {
4643 if (!r.persistent) {
4644 // Okay okay, I heard you already!
4645 return;
4646 }
4647 r.persistent = false;
4648 final long origId = Binder.clearCallingIdentity();
4649 decPersistentCountLocked(app);
4650 Binder.restoreCallingIdentity(origId);
4651
4652 }
4653 }
4654 }
4655
4656 public boolean clearApplicationUserData(final String packageName,
4657 final IPackageDataObserver observer) {
4658 int uid = Binder.getCallingUid();
4659 int pid = Binder.getCallingPid();
4660 long callingId = Binder.clearCallingIdentity();
4661 try {
4662 IPackageManager pm = ActivityThread.getPackageManager();
4663 int pkgUid = -1;
4664 synchronized(this) {
4665 try {
4666 pkgUid = pm.getPackageUid(packageName);
4667 } catch (RemoteException e) {
4668 }
4669 if (pkgUid == -1) {
4670 Log.w(TAG, "Invalid packageName:" + packageName);
4671 return false;
4672 }
4673 if (uid == pkgUid || checkComponentPermission(
4674 android.Manifest.permission.CLEAR_APP_USER_DATA,
4675 pid, uid, -1)
4676 == PackageManager.PERMISSION_GRANTED) {
4677 restartPackageLocked(packageName, pkgUid);
4678 } else {
4679 throw new SecurityException(pid+" does not have permission:"+
4680 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4681 "for process:"+packageName);
4682 }
4683 }
4684
4685 try {
4686 //clear application user data
4687 pm.clearApplicationUserData(packageName, observer);
4688 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4689 Uri.fromParts("package", packageName, null));
4690 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4691 broadcastIntentLocked(null, null, intent,
4692 null, null, 0, null, null, null,
4693 false, false, MY_PID, Process.SYSTEM_UID);
4694 } catch (RemoteException e) {
4695 }
4696 } finally {
4697 Binder.restoreCallingIdentity(callingId);
4698 }
4699 return true;
4700 }
4701
4702 public void restartPackage(final String packageName) {
4703 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4704 != PackageManager.PERMISSION_GRANTED) {
4705 String msg = "Permission Denial: restartPackage() from pid="
4706 + Binder.getCallingPid()
4707 + ", uid=" + Binder.getCallingUid()
4708 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4709 Log.w(TAG, msg);
4710 throw new SecurityException(msg);
4711 }
4712
4713 long callingId = Binder.clearCallingIdentity();
4714 try {
4715 IPackageManager pm = ActivityThread.getPackageManager();
4716 int pkgUid = -1;
4717 synchronized(this) {
4718 try {
4719 pkgUid = pm.getPackageUid(packageName);
4720 } catch (RemoteException e) {
4721 }
4722 if (pkgUid == -1) {
4723 Log.w(TAG, "Invalid packageName: " + packageName);
4724 return;
4725 }
4726 restartPackageLocked(packageName, pkgUid);
4727 }
4728 } finally {
4729 Binder.restoreCallingIdentity(callingId);
4730 }
4731 }
4732
4733 private void restartPackageLocked(final String packageName, int uid) {
4734 uninstallPackageLocked(packageName, uid, false);
4735 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4736 Uri.fromParts("package", packageName, null));
4737 intent.putExtra(Intent.EXTRA_UID, uid);
4738 broadcastIntentLocked(null, null, intent,
4739 null, null, 0, null, null, null,
4740 false, false, MY_PID, Process.SYSTEM_UID);
4741 }
4742
4743 private final void uninstallPackageLocked(String name, int uid,
4744 boolean callerWillRestart) {
4745 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4746
4747 int i, N;
4748
4749 final String procNamePrefix = name + ":";
4750 if (uid < 0) {
4751 try {
4752 uid = ActivityThread.getPackageManager().getPackageUid(name);
4753 } catch (RemoteException e) {
4754 }
4755 }
4756
4757 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4758 while (badApps.hasNext()) {
4759 SparseArray<Long> ba = badApps.next();
4760 if (ba.get(uid) != null) {
4761 badApps.remove();
4762 }
4763 }
4764
4765 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4766
4767 // Remove all processes this package may have touched: all with the
4768 // same UID (except for the system or root user), and all whose name
4769 // matches the package name.
4770 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4771 final int NA = apps.size();
4772 for (int ia=0; ia<NA; ia++) {
4773 ProcessRecord app = apps.valueAt(ia);
4774 if (app.removed) {
4775 procs.add(app);
4776 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4777 || app.processName.equals(name)
4778 || app.processName.startsWith(procNamePrefix)) {
4779 app.removed = true;
4780 procs.add(app);
4781 }
4782 }
4783 }
4784
4785 N = procs.size();
4786 for (i=0; i<N; i++) {
4787 removeProcessLocked(procs.get(i), callerWillRestart);
4788 }
4789
4790 for (i=mHistory.size()-1; i>=0; i--) {
4791 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4792 if (r.packageName.equals(name)) {
4793 if (Config.LOGD) Log.d(
4794 TAG, " Force finishing activity "
4795 + r.intent.getComponent().flattenToShortString());
4796 if (r.app != null) {
4797 r.app.removed = true;
4798 }
4799 r.app = null;
4800 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4801 }
4802 }
4803
4804 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4805 for (ServiceRecord service : mServices.values()) {
4806 if (service.packageName.equals(name)) {
4807 if (service.app != null) {
4808 service.app.removed = true;
4809 }
4810 service.app = null;
4811 services.add(service);
4812 }
4813 }
4814
4815 N = services.size();
4816 for (i=0; i<N; i++) {
4817 bringDownServiceLocked(services.get(i), true);
4818 }
4819
4820 resumeTopActivityLocked(null);
4821 }
4822
4823 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4824 final String name = app.processName;
4825 final int uid = app.info.uid;
4826 if (Config.LOGD) Log.d(
4827 TAG, "Force removing process " + app + " (" + name
4828 + "/" + uid + ")");
4829
4830 mProcessNames.remove(name, uid);
4831 boolean needRestart = false;
4832 if (app.pid > 0 && app.pid != MY_PID) {
4833 int pid = app.pid;
4834 synchronized (mPidsSelfLocked) {
4835 mPidsSelfLocked.remove(pid);
4836 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4837 }
4838 handleAppDiedLocked(app, true);
4839 mLRUProcesses.remove(app);
4840 Process.killProcess(pid);
4841
4842 if (app.persistent) {
4843 if (!callerWillRestart) {
4844 addAppLocked(app.info);
4845 } else {
4846 needRestart = true;
4847 }
4848 }
4849 } else {
4850 mRemovedProcesses.add(app);
4851 }
4852
4853 return needRestart;
4854 }
4855
4856 private final void processStartTimedOutLocked(ProcessRecord app) {
4857 final int pid = app.pid;
4858 boolean gone = false;
4859 synchronized (mPidsSelfLocked) {
4860 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4861 if (knownApp != null && knownApp.thread == null) {
4862 mPidsSelfLocked.remove(pid);
4863 gone = true;
4864 }
4865 }
4866
4867 if (gone) {
4868 Log.w(TAG, "Process " + app + " failed to attach");
4869 mProcessNames.remove(app.processName, app.info.uid);
4870 Process.killProcess(pid);
4871 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4872 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4873 mPendingBroadcast = null;
4874 scheduleBroadcastsLocked();
4875 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004876 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4877 Log.w(TAG, "Unattached app died before backup, skipping");
4878 try {
4879 IBackupManager bm = IBackupManager.Stub.asInterface(
4880 ServiceManager.getService(Context.BACKUP_SERVICE));
4881 bm.agentDisconnected(app.info.packageName);
4882 } catch (RemoteException e) {
4883 // Can't happen; the backup manager is local
4884 }
4885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004886 } else {
4887 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4888 }
4889 }
4890
4891 private final boolean attachApplicationLocked(IApplicationThread thread,
4892 int pid) {
4893
4894 // Find the application record that is being attached... either via
4895 // the pid if we are running in multiple processes, or just pull the
4896 // next app record if we are emulating process with anonymous threads.
4897 ProcessRecord app;
4898 if (pid != MY_PID && pid >= 0) {
4899 synchronized (mPidsSelfLocked) {
4900 app = mPidsSelfLocked.get(pid);
4901 }
4902 } else if (mStartingProcesses.size() > 0) {
4903 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004904 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004905 } else {
4906 app = null;
4907 }
4908
4909 if (app == null) {
4910 Log.w(TAG, "No pending application record for pid " + pid
4911 + " (IApplicationThread " + thread + "); dropping process");
4912 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4913 if (pid > 0 && pid != MY_PID) {
4914 Process.killProcess(pid);
4915 } else {
4916 try {
4917 thread.scheduleExit();
4918 } catch (Exception e) {
4919 // Ignore exceptions.
4920 }
4921 }
4922 return false;
4923 }
4924
4925 // If this application record is still attached to a previous
4926 // process, clean it up now.
4927 if (app.thread != null) {
4928 handleAppDiedLocked(app, true);
4929 }
4930
4931 // Tell the process all about itself.
4932
4933 if (localLOGV) Log.v(
4934 TAG, "Binding process pid " + pid + " to record " + app);
4935
4936 String processName = app.processName;
4937 try {
4938 thread.asBinder().linkToDeath(new AppDeathRecipient(
4939 app, pid, thread), 0);
4940 } catch (RemoteException e) {
4941 app.resetPackageList();
4942 startProcessLocked(app, "link fail", processName);
4943 return false;
4944 }
4945
4946 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4947
4948 app.thread = thread;
4949 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004950 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004951 app.forcingToForeground = null;
4952 app.foregroundServices = false;
4953 app.debugging = false;
4954
4955 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4956
4957 List providers = generateApplicationProvidersLocked(app);
4958
4959 if (localLOGV) Log.v(
4960 TAG, "New app record " + app
4961 + " thread=" + thread.asBinder() + " pid=" + pid);
4962 try {
4963 int testMode = IApplicationThread.DEBUG_OFF;
4964 if (mDebugApp != null && mDebugApp.equals(processName)) {
4965 testMode = mWaitForDebugger
4966 ? IApplicationThread.DEBUG_WAIT
4967 : IApplicationThread.DEBUG_ON;
4968 app.debugging = true;
4969 if (mDebugTransient) {
4970 mDebugApp = mOrigDebugApp;
4971 mWaitForDebugger = mOrigWaitForDebugger;
4972 }
4973 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004974 // If the app is being launched for restore or full backup, set it up specially
4975 boolean isRestrictedBackupMode = false;
4976 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4977 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4978 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4979 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004980 ensurePackageDexOpt(app.instrumentationInfo != null
4981 ? app.instrumentationInfo.packageName
4982 : app.info.packageName);
4983 if (app.instrumentationClass != null) {
4984 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004985 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004986 thread.bindApplication(processName, app.instrumentationInfo != null
4987 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004988 app.instrumentationClass, app.instrumentationProfileFile,
4989 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004990 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004991 updateLRUListLocked(app, false);
4992 app.lastRequestedGc = SystemClock.uptimeMillis();
4993 } catch (Exception e) {
4994 // todo: Yikes! What should we do? For now we will try to
4995 // start another process, but that could easily get us in
4996 // an infinite loop of restarting processes...
4997 Log.w(TAG, "Exception thrown during bind!", e);
4998
4999 app.resetPackageList();
5000 startProcessLocked(app, "bind fail", processName);
5001 return false;
5002 }
5003
5004 // Remove this record from the list of starting applications.
5005 mPersistentStartingProcesses.remove(app);
5006 mProcessesOnHold.remove(app);
5007
5008 boolean badApp = false;
5009 boolean didSomething = false;
5010
5011 // See if the top visible activity is waiting to run in this process...
5012 HistoryRecord hr = topRunningActivityLocked(null);
5013 if (hr != null) {
5014 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5015 && processName.equals(hr.processName)) {
5016 try {
5017 if (realStartActivityLocked(hr, app, true, true)) {
5018 didSomething = true;
5019 }
5020 } catch (Exception e) {
5021 Log.w(TAG, "Exception in new application when starting activity "
5022 + hr.intent.getComponent().flattenToShortString(), e);
5023 badApp = true;
5024 }
5025 } else {
5026 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5027 }
5028 }
5029
5030 // Find any services that should be running in this process...
5031 if (!badApp && mPendingServices.size() > 0) {
5032 ServiceRecord sr = null;
5033 try {
5034 for (int i=0; i<mPendingServices.size(); i++) {
5035 sr = mPendingServices.get(i);
5036 if (app.info.uid != sr.appInfo.uid
5037 || !processName.equals(sr.processName)) {
5038 continue;
5039 }
5040
5041 mPendingServices.remove(i);
5042 i--;
5043 realStartServiceLocked(sr, app);
5044 didSomething = true;
5045 }
5046 } catch (Exception e) {
5047 Log.w(TAG, "Exception in new application when starting service "
5048 + sr.shortName, e);
5049 badApp = true;
5050 }
5051 }
5052
5053 // Check if the next broadcast receiver is in this process...
5054 BroadcastRecord br = mPendingBroadcast;
5055 if (!badApp && br != null && br.curApp == app) {
5056 try {
5057 mPendingBroadcast = null;
5058 processCurBroadcastLocked(br, app);
5059 didSomething = true;
5060 } catch (Exception e) {
5061 Log.w(TAG, "Exception in new application when starting receiver "
5062 + br.curComponent.flattenToShortString(), e);
5063 badApp = true;
5064 logBroadcastReceiverDiscard(br);
5065 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5066 br.resultExtras, br.resultAbort, true);
5067 scheduleBroadcastsLocked();
5068 }
5069 }
5070
Christopher Tate181fafa2009-05-14 11:12:14 -07005071 // Check whether the next backup agent is in this process...
5072 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5073 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005074 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005075 try {
5076 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5077 } catch (Exception e) {
5078 Log.w(TAG, "Exception scheduling backup agent creation: ");
5079 e.printStackTrace();
5080 }
5081 }
5082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005083 if (badApp) {
5084 // todo: Also need to kill application to deal with all
5085 // kinds of exceptions.
5086 handleAppDiedLocked(app, false);
5087 return false;
5088 }
5089
5090 if (!didSomething) {
5091 updateOomAdjLocked();
5092 }
5093
5094 return true;
5095 }
5096
5097 public final void attachApplication(IApplicationThread thread) {
5098 synchronized (this) {
5099 int callingPid = Binder.getCallingPid();
5100 final long origId = Binder.clearCallingIdentity();
5101 attachApplicationLocked(thread, callingPid);
5102 Binder.restoreCallingIdentity(origId);
5103 }
5104 }
5105
5106 public final void activityIdle(IBinder token) {
5107 final long origId = Binder.clearCallingIdentity();
5108 activityIdleInternal(token, false);
5109 Binder.restoreCallingIdentity(origId);
5110 }
5111
5112 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5113 boolean remove) {
5114 int N = mStoppingActivities.size();
5115 if (N <= 0) return null;
5116
5117 ArrayList<HistoryRecord> stops = null;
5118
5119 final boolean nowVisible = mResumedActivity != null
5120 && mResumedActivity.nowVisible
5121 && !mResumedActivity.waitingVisible;
5122 for (int i=0; i<N; i++) {
5123 HistoryRecord s = mStoppingActivities.get(i);
5124 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5125 + nowVisible + " waitingVisible=" + s.waitingVisible
5126 + " finishing=" + s.finishing);
5127 if (s.waitingVisible && nowVisible) {
5128 mWaitingVisibleActivities.remove(s);
5129 s.waitingVisible = false;
5130 if (s.finishing) {
5131 // If this activity is finishing, it is sitting on top of
5132 // everyone else but we now know it is no longer needed...
5133 // so get rid of it. Otherwise, we need to go through the
5134 // normal flow and hide it once we determine that it is
5135 // hidden by the activities in front of it.
5136 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5137 mWindowManager.setAppVisibility(s, false);
5138 }
5139 }
5140 if (!s.waitingVisible && remove) {
5141 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5142 if (stops == null) {
5143 stops = new ArrayList<HistoryRecord>();
5144 }
5145 stops.add(s);
5146 mStoppingActivities.remove(i);
5147 N--;
5148 i--;
5149 }
5150 }
5151
5152 return stops;
5153 }
5154
5155 void enableScreenAfterBoot() {
5156 mWindowManager.enableScreenAfterBoot();
5157 }
5158
5159 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5160 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5161
5162 ArrayList<HistoryRecord> stops = null;
5163 ArrayList<HistoryRecord> finishes = null;
5164 ArrayList<HistoryRecord> thumbnails = null;
5165 int NS = 0;
5166 int NF = 0;
5167 int NT = 0;
5168 IApplicationThread sendThumbnail = null;
5169 boolean booting = false;
5170 boolean enableScreen = false;
5171
5172 synchronized (this) {
5173 if (token != null) {
5174 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5175 }
5176
5177 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005178 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005179 if (index >= 0) {
5180 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5181
5182 // No longer need to keep the device awake.
5183 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5184 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5185 mLaunchingActivity.release();
5186 }
5187
5188 // We are now idle. If someone is waiting for a thumbnail from
5189 // us, we can now deliver.
5190 r.idle = true;
5191 scheduleAppGcsLocked();
5192 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5193 sendThumbnail = r.app.thread;
5194 r.thumbnailNeeded = false;
5195 }
5196
5197 // If this activity is fullscreen, set up to hide those under it.
5198
5199 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5200 ensureActivitiesVisibleLocked(null, 0);
5201
5202 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5203 if (!mBooted && !fromTimeout) {
5204 mBooted = true;
5205 enableScreen = true;
5206 }
5207 }
5208
5209 // Atomically retrieve all of the other things to do.
5210 stops = processStoppingActivitiesLocked(true);
5211 NS = stops != null ? stops.size() : 0;
5212 if ((NF=mFinishingActivities.size()) > 0) {
5213 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5214 mFinishingActivities.clear();
5215 }
5216 if ((NT=mCancelledThumbnails.size()) > 0) {
5217 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5218 mCancelledThumbnails.clear();
5219 }
5220
5221 booting = mBooting;
5222 mBooting = false;
5223 }
5224
5225 int i;
5226
5227 // Send thumbnail if requested.
5228 if (sendThumbnail != null) {
5229 try {
5230 sendThumbnail.requestThumbnail(token);
5231 } catch (Exception e) {
5232 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5233 sendPendingThumbnail(null, token, null, null, true);
5234 }
5235 }
5236
5237 // Stop any activities that are scheduled to do so but have been
5238 // waiting for the next one to start.
5239 for (i=0; i<NS; i++) {
5240 HistoryRecord r = (HistoryRecord)stops.get(i);
5241 synchronized (this) {
5242 if (r.finishing) {
5243 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5244 } else {
5245 stopActivityLocked(r);
5246 }
5247 }
5248 }
5249
5250 // Finish any activities that are scheduled to do so but have been
5251 // waiting for the next one to start.
5252 for (i=0; i<NF; i++) {
5253 HistoryRecord r = (HistoryRecord)finishes.get(i);
5254 synchronized (this) {
5255 destroyActivityLocked(r, true);
5256 }
5257 }
5258
5259 // Report back to any thumbnail receivers.
5260 for (i=0; i<NT; i++) {
5261 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5262 sendPendingThumbnail(r, null, null, null, true);
5263 }
5264
5265 if (booting) {
5266 // Ensure that any processes we had put on hold are now started
5267 // up.
5268 final int NP = mProcessesOnHold.size();
5269 if (NP > 0) {
5270 ArrayList<ProcessRecord> procs =
5271 new ArrayList<ProcessRecord>(mProcessesOnHold);
5272 for (int ip=0; ip<NP; ip++) {
5273 this.startProcessLocked(procs.get(ip), "on-hold", null);
5274 }
5275 }
5276 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5277 // Tell anyone interested that we are done booting!
5278 synchronized (this) {
5279 broadcastIntentLocked(null, null,
5280 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5281 null, null, 0, null, null,
5282 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5283 false, false, MY_PID, Process.SYSTEM_UID);
5284 }
5285 }
5286 }
5287
5288 trimApplications();
5289 //dump();
5290 //mWindowManager.dump();
5291
5292 if (enableScreen) {
5293 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5294 SystemClock.uptimeMillis());
5295 enableScreenAfterBoot();
5296 }
5297 }
5298
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005299 final void ensureScreenEnabled() {
5300 boolean enableScreen;
5301 synchronized (this) {
5302 enableScreen = !mBooted;
5303 mBooted = true;
5304 }
5305
5306 if (enableScreen) {
5307 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5308 SystemClock.uptimeMillis());
5309 enableScreenAfterBoot();
5310 }
5311 }
5312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 public final void activityPaused(IBinder token, Bundle icicle) {
5314 // Refuse possible leaked file descriptors
5315 if (icicle != null && icicle.hasFileDescriptors()) {
5316 throw new IllegalArgumentException("File descriptors passed in Bundle");
5317 }
5318
5319 final long origId = Binder.clearCallingIdentity();
5320 activityPaused(token, icicle, false);
5321 Binder.restoreCallingIdentity(origId);
5322 }
5323
5324 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5325 if (DEBUG_PAUSE) Log.v(
5326 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5327 + ", timeout=" + timeout);
5328
5329 HistoryRecord r = null;
5330
5331 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005332 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005333 if (index >= 0) {
5334 r = (HistoryRecord)mHistory.get(index);
5335 if (!timeout) {
5336 r.icicle = icicle;
5337 r.haveState = true;
5338 }
5339 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5340 if (mPausingActivity == r) {
5341 r.state = ActivityState.PAUSED;
5342 completePauseLocked();
5343 } else {
5344 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5345 System.identityHashCode(r), r.shortComponentName,
5346 mPausingActivity != null
5347 ? mPausingActivity.shortComponentName : "(none)");
5348 }
5349 }
5350 }
5351 }
5352
5353 public final void activityStopped(IBinder token, Bitmap thumbnail,
5354 CharSequence description) {
5355 if (localLOGV) Log.v(
5356 TAG, "Activity stopped: token=" + token);
5357
5358 HistoryRecord r = null;
5359
5360 final long origId = Binder.clearCallingIdentity();
5361
5362 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005363 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005364 if (index >= 0) {
5365 r = (HistoryRecord)mHistory.get(index);
5366 r.thumbnail = thumbnail;
5367 r.description = description;
5368 r.stopped = true;
5369 r.state = ActivityState.STOPPED;
5370 if (!r.finishing) {
5371 if (r.configDestroy) {
5372 destroyActivityLocked(r, true);
5373 resumeTopActivityLocked(null);
5374 }
5375 }
5376 }
5377 }
5378
5379 if (r != null) {
5380 sendPendingThumbnail(r, null, null, null, false);
5381 }
5382
5383 trimApplications();
5384
5385 Binder.restoreCallingIdentity(origId);
5386 }
5387
5388 public final void activityDestroyed(IBinder token) {
5389 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5390 synchronized (this) {
5391 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5392
Dianne Hackborn75b03852009-06-12 15:43:26 -07005393 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 if (index >= 0) {
5395 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5396 if (r.state == ActivityState.DESTROYING) {
5397 final long origId = Binder.clearCallingIdentity();
5398 removeActivityFromHistoryLocked(r);
5399 Binder.restoreCallingIdentity(origId);
5400 }
5401 }
5402 }
5403 }
5404
5405 public String getCallingPackage(IBinder token) {
5406 synchronized (this) {
5407 HistoryRecord r = getCallingRecordLocked(token);
5408 return r != null && r.app != null ? r.app.processName : null;
5409 }
5410 }
5411
5412 public ComponentName getCallingActivity(IBinder token) {
5413 synchronized (this) {
5414 HistoryRecord r = getCallingRecordLocked(token);
5415 return r != null ? r.intent.getComponent() : null;
5416 }
5417 }
5418
5419 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005420 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005421 if (index >= 0) {
5422 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5423 if (r != null) {
5424 return r.resultTo;
5425 }
5426 }
5427 return null;
5428 }
5429
5430 public ComponentName getActivityClassForToken(IBinder token) {
5431 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005432 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005433 if (index >= 0) {
5434 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5435 return r.intent.getComponent();
5436 }
5437 return null;
5438 }
5439 }
5440
5441 public String getPackageForToken(IBinder token) {
5442 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005443 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005444 if (index >= 0) {
5445 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5446 return r.packageName;
5447 }
5448 return null;
5449 }
5450 }
5451
5452 public IIntentSender getIntentSender(int type,
5453 String packageName, IBinder token, String resultWho,
5454 int requestCode, Intent intent, String resolvedType, int flags) {
5455 // Refuse possible leaked file descriptors
5456 if (intent != null && intent.hasFileDescriptors() == true) {
5457 throw new IllegalArgumentException("File descriptors passed in Intent");
5458 }
5459
5460 synchronized(this) {
5461 int callingUid = Binder.getCallingUid();
5462 try {
5463 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5464 Process.supportsProcesses()) {
5465 int uid = ActivityThread.getPackageManager()
5466 .getPackageUid(packageName);
5467 if (uid != Binder.getCallingUid()) {
5468 String msg = "Permission Denial: getIntentSender() from pid="
5469 + Binder.getCallingPid()
5470 + ", uid=" + Binder.getCallingUid()
5471 + ", (need uid=" + uid + ")"
5472 + " is not allowed to send as package " + packageName;
5473 Log.w(TAG, msg);
5474 throw new SecurityException(msg);
5475 }
5476 }
5477 } catch (RemoteException e) {
5478 throw new SecurityException(e);
5479 }
5480 HistoryRecord activity = null;
5481 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005482 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005483 if (index < 0) {
5484 return null;
5485 }
5486 activity = (HistoryRecord)mHistory.get(index);
5487 if (activity.finishing) {
5488 return null;
5489 }
5490 }
5491
5492 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5493 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5494 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5495 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5496 |PendingIntent.FLAG_UPDATE_CURRENT);
5497
5498 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5499 type, packageName, activity, resultWho,
5500 requestCode, intent, resolvedType, flags);
5501 WeakReference<PendingIntentRecord> ref;
5502 ref = mIntentSenderRecords.get(key);
5503 PendingIntentRecord rec = ref != null ? ref.get() : null;
5504 if (rec != null) {
5505 if (!cancelCurrent) {
5506 if (updateCurrent) {
5507 rec.key.requestIntent.replaceExtras(intent);
5508 }
5509 return rec;
5510 }
5511 rec.canceled = true;
5512 mIntentSenderRecords.remove(key);
5513 }
5514 if (noCreate) {
5515 return rec;
5516 }
5517 rec = new PendingIntentRecord(this, key, callingUid);
5518 mIntentSenderRecords.put(key, rec.ref);
5519 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5520 if (activity.pendingResults == null) {
5521 activity.pendingResults
5522 = new HashSet<WeakReference<PendingIntentRecord>>();
5523 }
5524 activity.pendingResults.add(rec.ref);
5525 }
5526 return rec;
5527 }
5528 }
5529
5530 public void cancelIntentSender(IIntentSender sender) {
5531 if (!(sender instanceof PendingIntentRecord)) {
5532 return;
5533 }
5534 synchronized(this) {
5535 PendingIntentRecord rec = (PendingIntentRecord)sender;
5536 try {
5537 int uid = ActivityThread.getPackageManager()
5538 .getPackageUid(rec.key.packageName);
5539 if (uid != Binder.getCallingUid()) {
5540 String msg = "Permission Denial: cancelIntentSender() from pid="
5541 + Binder.getCallingPid()
5542 + ", uid=" + Binder.getCallingUid()
5543 + " is not allowed to cancel packges "
5544 + rec.key.packageName;
5545 Log.w(TAG, msg);
5546 throw new SecurityException(msg);
5547 }
5548 } catch (RemoteException e) {
5549 throw new SecurityException(e);
5550 }
5551 cancelIntentSenderLocked(rec, true);
5552 }
5553 }
5554
5555 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5556 rec.canceled = true;
5557 mIntentSenderRecords.remove(rec.key);
5558 if (cleanActivity && rec.key.activity != null) {
5559 rec.key.activity.pendingResults.remove(rec.ref);
5560 }
5561 }
5562
5563 public String getPackageForIntentSender(IIntentSender pendingResult) {
5564 if (!(pendingResult instanceof PendingIntentRecord)) {
5565 return null;
5566 }
5567 synchronized(this) {
5568 try {
5569 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5570 return res.key.packageName;
5571 } catch (ClassCastException e) {
5572 }
5573 }
5574 return null;
5575 }
5576
5577 public void setProcessLimit(int max) {
5578 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5579 "setProcessLimit()");
5580 mProcessLimit = max;
5581 }
5582
5583 public int getProcessLimit() {
5584 return mProcessLimit;
5585 }
5586
5587 void foregroundTokenDied(ForegroundToken token) {
5588 synchronized (ActivityManagerService.this) {
5589 synchronized (mPidsSelfLocked) {
5590 ForegroundToken cur
5591 = mForegroundProcesses.get(token.pid);
5592 if (cur != token) {
5593 return;
5594 }
5595 mForegroundProcesses.remove(token.pid);
5596 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5597 if (pr == null) {
5598 return;
5599 }
5600 pr.forcingToForeground = null;
5601 pr.foregroundServices = false;
5602 }
5603 updateOomAdjLocked();
5604 }
5605 }
5606
5607 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5608 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5609 "setProcessForeground()");
5610 synchronized(this) {
5611 boolean changed = false;
5612
5613 synchronized (mPidsSelfLocked) {
5614 ProcessRecord pr = mPidsSelfLocked.get(pid);
5615 if (pr == null) {
5616 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5617 return;
5618 }
5619 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5620 if (oldToken != null) {
5621 oldToken.token.unlinkToDeath(oldToken, 0);
5622 mForegroundProcesses.remove(pid);
5623 pr.forcingToForeground = null;
5624 changed = true;
5625 }
5626 if (isForeground && token != null) {
5627 ForegroundToken newToken = new ForegroundToken() {
5628 public void binderDied() {
5629 foregroundTokenDied(this);
5630 }
5631 };
5632 newToken.pid = pid;
5633 newToken.token = token;
5634 try {
5635 token.linkToDeath(newToken, 0);
5636 mForegroundProcesses.put(pid, newToken);
5637 pr.forcingToForeground = token;
5638 changed = true;
5639 } catch (RemoteException e) {
5640 // If the process died while doing this, we will later
5641 // do the cleanup with the process death link.
5642 }
5643 }
5644 }
5645
5646 if (changed) {
5647 updateOomAdjLocked();
5648 }
5649 }
5650 }
5651
5652 // =========================================================
5653 // PERMISSIONS
5654 // =========================================================
5655
5656 static class PermissionController extends IPermissionController.Stub {
5657 ActivityManagerService mActivityManagerService;
5658 PermissionController(ActivityManagerService activityManagerService) {
5659 mActivityManagerService = activityManagerService;
5660 }
5661
5662 public boolean checkPermission(String permission, int pid, int uid) {
5663 return mActivityManagerService.checkPermission(permission, pid,
5664 uid) == PackageManager.PERMISSION_GRANTED;
5665 }
5666 }
5667
5668 /**
5669 * This can be called with or without the global lock held.
5670 */
5671 int checkComponentPermission(String permission, int pid, int uid,
5672 int reqUid) {
5673 // We might be performing an operation on behalf of an indirect binder
5674 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5675 // client identity accordingly before proceeding.
5676 Identity tlsIdentity = sCallerIdentity.get();
5677 if (tlsIdentity != null) {
5678 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5679 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5680 uid = tlsIdentity.uid;
5681 pid = tlsIdentity.pid;
5682 }
5683
5684 // Root, system server and our own process get to do everything.
5685 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5686 !Process.supportsProcesses()) {
5687 return PackageManager.PERMISSION_GRANTED;
5688 }
5689 // If the target requires a specific UID, always fail for others.
5690 if (reqUid >= 0 && uid != reqUid) {
5691 return PackageManager.PERMISSION_DENIED;
5692 }
5693 if (permission == null) {
5694 return PackageManager.PERMISSION_GRANTED;
5695 }
5696 try {
5697 return ActivityThread.getPackageManager()
5698 .checkUidPermission(permission, uid);
5699 } catch (RemoteException e) {
5700 // Should never happen, but if it does... deny!
5701 Log.e(TAG, "PackageManager is dead?!?", e);
5702 }
5703 return PackageManager.PERMISSION_DENIED;
5704 }
5705
5706 /**
5707 * As the only public entry point for permissions checking, this method
5708 * can enforce the semantic that requesting a check on a null global
5709 * permission is automatically denied. (Internally a null permission
5710 * string is used when calling {@link #checkComponentPermission} in cases
5711 * when only uid-based security is needed.)
5712 *
5713 * This can be called with or without the global lock held.
5714 */
5715 public int checkPermission(String permission, int pid, int uid) {
5716 if (permission == null) {
5717 return PackageManager.PERMISSION_DENIED;
5718 }
5719 return checkComponentPermission(permission, pid, uid, -1);
5720 }
5721
5722 /**
5723 * Binder IPC calls go through the public entry point.
5724 * This can be called with or without the global lock held.
5725 */
5726 int checkCallingPermission(String permission) {
5727 return checkPermission(permission,
5728 Binder.getCallingPid(),
5729 Binder.getCallingUid());
5730 }
5731
5732 /**
5733 * This can be called with or without the global lock held.
5734 */
5735 void enforceCallingPermission(String permission, String func) {
5736 if (checkCallingPermission(permission)
5737 == PackageManager.PERMISSION_GRANTED) {
5738 return;
5739 }
5740
5741 String msg = "Permission Denial: " + func + " from pid="
5742 + Binder.getCallingPid()
5743 + ", uid=" + Binder.getCallingUid()
5744 + " requires " + permission;
5745 Log.w(TAG, msg);
5746 throw new SecurityException(msg);
5747 }
5748
5749 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5750 ProviderInfo pi, int uid, int modeFlags) {
5751 try {
5752 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5753 if ((pi.readPermission != null) &&
5754 (pm.checkUidPermission(pi.readPermission, uid)
5755 != PackageManager.PERMISSION_GRANTED)) {
5756 return false;
5757 }
5758 }
5759 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5760 if ((pi.writePermission != null) &&
5761 (pm.checkUidPermission(pi.writePermission, uid)
5762 != PackageManager.PERMISSION_GRANTED)) {
5763 return false;
5764 }
5765 }
5766 return true;
5767 } catch (RemoteException e) {
5768 return false;
5769 }
5770 }
5771
5772 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5773 int modeFlags) {
5774 // Root gets to do everything.
5775 if (uid == 0 || !Process.supportsProcesses()) {
5776 return true;
5777 }
5778 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5779 if (perms == null) return false;
5780 UriPermission perm = perms.get(uri);
5781 if (perm == null) return false;
5782 return (modeFlags&perm.modeFlags) == modeFlags;
5783 }
5784
5785 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5786 // Another redirected-binder-call permissions check as in
5787 // {@link checkComponentPermission}.
5788 Identity tlsIdentity = sCallerIdentity.get();
5789 if (tlsIdentity != null) {
5790 uid = tlsIdentity.uid;
5791 pid = tlsIdentity.pid;
5792 }
5793
5794 // Our own process gets to do everything.
5795 if (pid == MY_PID) {
5796 return PackageManager.PERMISSION_GRANTED;
5797 }
5798 synchronized(this) {
5799 return checkUriPermissionLocked(uri, uid, modeFlags)
5800 ? PackageManager.PERMISSION_GRANTED
5801 : PackageManager.PERMISSION_DENIED;
5802 }
5803 }
5804
5805 private void grantUriPermissionLocked(int callingUid,
5806 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5807 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5808 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5809 if (modeFlags == 0) {
5810 return;
5811 }
5812
5813 final IPackageManager pm = ActivityThread.getPackageManager();
5814
5815 // If this is not a content: uri, we can't do anything with it.
5816 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5817 return;
5818 }
5819
5820 String name = uri.getAuthority();
5821 ProviderInfo pi = null;
5822 ContentProviderRecord cpr
5823 = (ContentProviderRecord)mProvidersByName.get(name);
5824 if (cpr != null) {
5825 pi = cpr.info;
5826 } else {
5827 try {
5828 pi = pm.resolveContentProvider(name,
5829 PackageManager.GET_URI_PERMISSION_PATTERNS);
5830 } catch (RemoteException ex) {
5831 }
5832 }
5833 if (pi == null) {
5834 Log.w(TAG, "No content provider found for: " + name);
5835 return;
5836 }
5837
5838 int targetUid;
5839 try {
5840 targetUid = pm.getPackageUid(targetPkg);
5841 if (targetUid < 0) {
5842 return;
5843 }
5844 } catch (RemoteException ex) {
5845 return;
5846 }
5847
5848 // First... does the target actually need this permission?
5849 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5850 // No need to grant the target this permission.
5851 return;
5852 }
5853
5854 // Second... maybe someone else has already granted the
5855 // permission?
5856 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5857 // No need to grant the target this permission.
5858 return;
5859 }
5860
5861 // Third... is the provider allowing granting of URI permissions?
5862 if (!pi.grantUriPermissions) {
5863 throw new SecurityException("Provider " + pi.packageName
5864 + "/" + pi.name
5865 + " does not allow granting of Uri permissions (uri "
5866 + uri + ")");
5867 }
5868 if (pi.uriPermissionPatterns != null) {
5869 final int N = pi.uriPermissionPatterns.length;
5870 boolean allowed = false;
5871 for (int i=0; i<N; i++) {
5872 if (pi.uriPermissionPatterns[i] != null
5873 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5874 allowed = true;
5875 break;
5876 }
5877 }
5878 if (!allowed) {
5879 throw new SecurityException("Provider " + pi.packageName
5880 + "/" + pi.name
5881 + " does not allow granting of permission to path of Uri "
5882 + uri);
5883 }
5884 }
5885
5886 // Fourth... does the caller itself have permission to access
5887 // this uri?
5888 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5889 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5890 throw new SecurityException("Uid " + callingUid
5891 + " does not have permission to uri " + uri);
5892 }
5893 }
5894
5895 // Okay! So here we are: the caller has the assumed permission
5896 // to the uri, and the target doesn't. Let's now give this to
5897 // the target.
5898
5899 HashMap<Uri, UriPermission> targetUris
5900 = mGrantedUriPermissions.get(targetUid);
5901 if (targetUris == null) {
5902 targetUris = new HashMap<Uri, UriPermission>();
5903 mGrantedUriPermissions.put(targetUid, targetUris);
5904 }
5905
5906 UriPermission perm = targetUris.get(uri);
5907 if (perm == null) {
5908 perm = new UriPermission(targetUid, uri);
5909 targetUris.put(uri, perm);
5910
5911 }
5912 perm.modeFlags |= modeFlags;
5913 if (activity == null) {
5914 perm.globalModeFlags |= modeFlags;
5915 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5916 perm.readActivities.add(activity);
5917 if (activity.readUriPermissions == null) {
5918 activity.readUriPermissions = new HashSet<UriPermission>();
5919 }
5920 activity.readUriPermissions.add(perm);
5921 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5922 perm.writeActivities.add(activity);
5923 if (activity.writeUriPermissions == null) {
5924 activity.writeUriPermissions = new HashSet<UriPermission>();
5925 }
5926 activity.writeUriPermissions.add(perm);
5927 }
5928 }
5929
5930 private void grantUriPermissionFromIntentLocked(int callingUid,
5931 String targetPkg, Intent intent, HistoryRecord activity) {
5932 if (intent == null) {
5933 return;
5934 }
5935 Uri data = intent.getData();
5936 if (data == null) {
5937 return;
5938 }
5939 grantUriPermissionLocked(callingUid, targetPkg, data,
5940 intent.getFlags(), activity);
5941 }
5942
5943 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5944 Uri uri, int modeFlags) {
5945 synchronized(this) {
5946 final ProcessRecord r = getRecordForAppLocked(caller);
5947 if (r == null) {
5948 throw new SecurityException("Unable to find app for caller "
5949 + caller
5950 + " when granting permission to uri " + uri);
5951 }
5952 if (targetPkg == null) {
5953 Log.w(TAG, "grantUriPermission: null target");
5954 return;
5955 }
5956 if (uri == null) {
5957 Log.w(TAG, "grantUriPermission: null uri");
5958 return;
5959 }
5960
5961 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5962 null);
5963 }
5964 }
5965
5966 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5967 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5968 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5969 HashMap<Uri, UriPermission> perms
5970 = mGrantedUriPermissions.get(perm.uid);
5971 if (perms != null) {
5972 perms.remove(perm.uri);
5973 if (perms.size() == 0) {
5974 mGrantedUriPermissions.remove(perm.uid);
5975 }
5976 }
5977 }
5978 }
5979
5980 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5981 if (activity.readUriPermissions != null) {
5982 for (UriPermission perm : activity.readUriPermissions) {
5983 perm.readActivities.remove(activity);
5984 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5985 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5986 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5987 removeUriPermissionIfNeededLocked(perm);
5988 }
5989 }
5990 }
5991 if (activity.writeUriPermissions != null) {
5992 for (UriPermission perm : activity.writeUriPermissions) {
5993 perm.writeActivities.remove(activity);
5994 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5995 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5996 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5997 removeUriPermissionIfNeededLocked(perm);
5998 }
5999 }
6000 }
6001 }
6002
6003 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6004 int modeFlags) {
6005 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6006 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6007 if (modeFlags == 0) {
6008 return;
6009 }
6010
6011 final IPackageManager pm = ActivityThread.getPackageManager();
6012
6013 final String authority = uri.getAuthority();
6014 ProviderInfo pi = null;
6015 ContentProviderRecord cpr
6016 = (ContentProviderRecord)mProvidersByName.get(authority);
6017 if (cpr != null) {
6018 pi = cpr.info;
6019 } else {
6020 try {
6021 pi = pm.resolveContentProvider(authority,
6022 PackageManager.GET_URI_PERMISSION_PATTERNS);
6023 } catch (RemoteException ex) {
6024 }
6025 }
6026 if (pi == null) {
6027 Log.w(TAG, "No content provider found for: " + authority);
6028 return;
6029 }
6030
6031 // Does the caller have this permission on the URI?
6032 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6033 // Right now, if you are not the original owner of the permission,
6034 // you are not allowed to revoke it.
6035 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6036 throw new SecurityException("Uid " + callingUid
6037 + " does not have permission to uri " + uri);
6038 //}
6039 }
6040
6041 // Go through all of the permissions and remove any that match.
6042 final List<String> SEGMENTS = uri.getPathSegments();
6043 if (SEGMENTS != null) {
6044 final int NS = SEGMENTS.size();
6045 int N = mGrantedUriPermissions.size();
6046 for (int i=0; i<N; i++) {
6047 HashMap<Uri, UriPermission> perms
6048 = mGrantedUriPermissions.valueAt(i);
6049 Iterator<UriPermission> it = perms.values().iterator();
6050 toploop:
6051 while (it.hasNext()) {
6052 UriPermission perm = it.next();
6053 Uri targetUri = perm.uri;
6054 if (!authority.equals(targetUri.getAuthority())) {
6055 continue;
6056 }
6057 List<String> targetSegments = targetUri.getPathSegments();
6058 if (targetSegments == null) {
6059 continue;
6060 }
6061 if (targetSegments.size() < NS) {
6062 continue;
6063 }
6064 for (int j=0; j<NS; j++) {
6065 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6066 continue toploop;
6067 }
6068 }
6069 perm.clearModes(modeFlags);
6070 if (perm.modeFlags == 0) {
6071 it.remove();
6072 }
6073 }
6074 if (perms.size() == 0) {
6075 mGrantedUriPermissions.remove(
6076 mGrantedUriPermissions.keyAt(i));
6077 N--;
6078 i--;
6079 }
6080 }
6081 }
6082 }
6083
6084 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6085 int modeFlags) {
6086 synchronized(this) {
6087 final ProcessRecord r = getRecordForAppLocked(caller);
6088 if (r == null) {
6089 throw new SecurityException("Unable to find app for caller "
6090 + caller
6091 + " when revoking permission to uri " + uri);
6092 }
6093 if (uri == null) {
6094 Log.w(TAG, "revokeUriPermission: null uri");
6095 return;
6096 }
6097
6098 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6099 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6100 if (modeFlags == 0) {
6101 return;
6102 }
6103
6104 final IPackageManager pm = ActivityThread.getPackageManager();
6105
6106 final String authority = uri.getAuthority();
6107 ProviderInfo pi = null;
6108 ContentProviderRecord cpr
6109 = (ContentProviderRecord)mProvidersByName.get(authority);
6110 if (cpr != null) {
6111 pi = cpr.info;
6112 } else {
6113 try {
6114 pi = pm.resolveContentProvider(authority,
6115 PackageManager.GET_URI_PERMISSION_PATTERNS);
6116 } catch (RemoteException ex) {
6117 }
6118 }
6119 if (pi == null) {
6120 Log.w(TAG, "No content provider found for: " + authority);
6121 return;
6122 }
6123
6124 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6125 }
6126 }
6127
6128 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6129 synchronized (this) {
6130 ProcessRecord app =
6131 who != null ? getRecordForAppLocked(who) : null;
6132 if (app == null) return;
6133
6134 Message msg = Message.obtain();
6135 msg.what = WAIT_FOR_DEBUGGER_MSG;
6136 msg.obj = app;
6137 msg.arg1 = waiting ? 1 : 0;
6138 mHandler.sendMessage(msg);
6139 }
6140 }
6141
6142 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6143 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006144 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006145 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006146 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006147 }
6148
6149 // =========================================================
6150 // TASK MANAGEMENT
6151 // =========================================================
6152
6153 public List getTasks(int maxNum, int flags,
6154 IThumbnailReceiver receiver) {
6155 ArrayList list = new ArrayList();
6156
6157 PendingThumbnailsRecord pending = null;
6158 IApplicationThread topThumbnail = null;
6159 HistoryRecord topRecord = null;
6160
6161 synchronized(this) {
6162 if (localLOGV) Log.v(
6163 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6164 + ", receiver=" + receiver);
6165
6166 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6167 != PackageManager.PERMISSION_GRANTED) {
6168 if (receiver != null) {
6169 // If the caller wants to wait for pending thumbnails,
6170 // it ain't gonna get them.
6171 try {
6172 receiver.finished();
6173 } catch (RemoteException ex) {
6174 }
6175 }
6176 String msg = "Permission Denial: getTasks() from pid="
6177 + Binder.getCallingPid()
6178 + ", uid=" + Binder.getCallingUid()
6179 + " requires " + android.Manifest.permission.GET_TASKS;
6180 Log.w(TAG, msg);
6181 throw new SecurityException(msg);
6182 }
6183
6184 int pos = mHistory.size()-1;
6185 HistoryRecord next =
6186 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6187 HistoryRecord top = null;
6188 CharSequence topDescription = null;
6189 TaskRecord curTask = null;
6190 int numActivities = 0;
6191 int numRunning = 0;
6192 while (pos >= 0 && maxNum > 0) {
6193 final HistoryRecord r = next;
6194 pos--;
6195 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6196
6197 // Initialize state for next task if needed.
6198 if (top == null ||
6199 (top.state == ActivityState.INITIALIZING
6200 && top.task == r.task)) {
6201 top = r;
6202 topDescription = r.description;
6203 curTask = r.task;
6204 numActivities = numRunning = 0;
6205 }
6206
6207 // Add 'r' into the current task.
6208 numActivities++;
6209 if (r.app != null && r.app.thread != null) {
6210 numRunning++;
6211 }
6212 if (topDescription == null) {
6213 topDescription = r.description;
6214 }
6215
6216 if (localLOGV) Log.v(
6217 TAG, r.intent.getComponent().flattenToShortString()
6218 + ": task=" + r.task);
6219
6220 // If the next one is a different task, generate a new
6221 // TaskInfo entry for what we have.
6222 if (next == null || next.task != curTask) {
6223 ActivityManager.RunningTaskInfo ci
6224 = new ActivityManager.RunningTaskInfo();
6225 ci.id = curTask.taskId;
6226 ci.baseActivity = r.intent.getComponent();
6227 ci.topActivity = top.intent.getComponent();
6228 ci.thumbnail = top.thumbnail;
6229 ci.description = topDescription;
6230 ci.numActivities = numActivities;
6231 ci.numRunning = numRunning;
6232 //System.out.println(
6233 // "#" + maxNum + ": " + " descr=" + ci.description);
6234 if (ci.thumbnail == null && receiver != null) {
6235 if (localLOGV) Log.v(
6236 TAG, "State=" + top.state + "Idle=" + top.idle
6237 + " app=" + top.app
6238 + " thr=" + (top.app != null ? top.app.thread : null));
6239 if (top.state == ActivityState.RESUMED
6240 || top.state == ActivityState.PAUSING) {
6241 if (top.idle && top.app != null
6242 && top.app.thread != null) {
6243 topRecord = top;
6244 topThumbnail = top.app.thread;
6245 } else {
6246 top.thumbnailNeeded = true;
6247 }
6248 }
6249 if (pending == null) {
6250 pending = new PendingThumbnailsRecord(receiver);
6251 }
6252 pending.pendingRecords.add(top);
6253 }
6254 list.add(ci);
6255 maxNum--;
6256 top = null;
6257 }
6258 }
6259
6260 if (pending != null) {
6261 mPendingThumbnails.add(pending);
6262 }
6263 }
6264
6265 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6266
6267 if (topThumbnail != null) {
6268 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6269 try {
6270 topThumbnail.requestThumbnail(topRecord);
6271 } catch (Exception e) {
6272 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6273 sendPendingThumbnail(null, topRecord, null, null, true);
6274 }
6275 }
6276
6277 if (pending == null && receiver != null) {
6278 // In this case all thumbnails were available and the client
6279 // is being asked to be told when the remaining ones come in...
6280 // which is unusually, since the top-most currently running
6281 // activity should never have a canned thumbnail! Oh well.
6282 try {
6283 receiver.finished();
6284 } catch (RemoteException ex) {
6285 }
6286 }
6287
6288 return list;
6289 }
6290
6291 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6292 int flags) {
6293 synchronized (this) {
6294 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6295 "getRecentTasks()");
6296
6297 final int N = mRecentTasks.size();
6298 ArrayList<ActivityManager.RecentTaskInfo> res
6299 = new ArrayList<ActivityManager.RecentTaskInfo>(
6300 maxNum < N ? maxNum : N);
6301 for (int i=0; i<N && maxNum > 0; i++) {
6302 TaskRecord tr = mRecentTasks.get(i);
6303 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6304 || (tr.intent == null)
6305 || ((tr.intent.getFlags()
6306 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6307 ActivityManager.RecentTaskInfo rti
6308 = new ActivityManager.RecentTaskInfo();
6309 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6310 rti.baseIntent = new Intent(
6311 tr.intent != null ? tr.intent : tr.affinityIntent);
6312 rti.origActivity = tr.origActivity;
6313 res.add(rti);
6314 maxNum--;
6315 }
6316 }
6317 return res;
6318 }
6319 }
6320
6321 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6322 int j;
6323 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6324 TaskRecord jt = startTask;
6325
6326 // First look backwards
6327 for (j=startIndex-1; j>=0; j--) {
6328 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6329 if (r.task != jt) {
6330 jt = r.task;
6331 if (affinity.equals(jt.affinity)) {
6332 return j;
6333 }
6334 }
6335 }
6336
6337 // Now look forwards
6338 final int N = mHistory.size();
6339 jt = startTask;
6340 for (j=startIndex+1; j<N; j++) {
6341 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6342 if (r.task != jt) {
6343 if (affinity.equals(jt.affinity)) {
6344 return j;
6345 }
6346 jt = r.task;
6347 }
6348 }
6349
6350 // Might it be at the top?
6351 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6352 return N-1;
6353 }
6354
6355 return -1;
6356 }
6357
6358 /**
6359 * Perform a reset of the given task, if needed as part of launching it.
6360 * Returns the new HistoryRecord at the top of the task.
6361 */
6362 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6363 HistoryRecord newActivity) {
6364 boolean forceReset = (newActivity.info.flags
6365 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6366 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6367 if ((newActivity.info.flags
6368 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6369 forceReset = true;
6370 }
6371 }
6372
6373 final TaskRecord task = taskTop.task;
6374
6375 // We are going to move through the history list so that we can look
6376 // at each activity 'target' with 'below' either the interesting
6377 // activity immediately below it in the stack or null.
6378 HistoryRecord target = null;
6379 int targetI = 0;
6380 int taskTopI = -1;
6381 int replyChainEnd = -1;
6382 int lastReparentPos = -1;
6383 for (int i=mHistory.size()-1; i>=-1; i--) {
6384 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6385
6386 if (below != null && below.finishing) {
6387 continue;
6388 }
6389 if (target == null) {
6390 target = below;
6391 targetI = i;
6392 // If we were in the middle of a reply chain before this
6393 // task, it doesn't appear like the root of the chain wants
6394 // anything interesting, so drop it.
6395 replyChainEnd = -1;
6396 continue;
6397 }
6398
6399 final int flags = target.info.flags;
6400
6401 final boolean finishOnTaskLaunch =
6402 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6403 final boolean allowTaskReparenting =
6404 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6405
6406 if (target.task == task) {
6407 // We are inside of the task being reset... we'll either
6408 // finish this activity, push it out for another task,
6409 // or leave it as-is. We only do this
6410 // for activities that are not the root of the task (since
6411 // if we finish the root, we may no longer have the task!).
6412 if (taskTopI < 0) {
6413 taskTopI = targetI;
6414 }
6415 if (below != null && below.task == task) {
6416 final boolean clearWhenTaskReset =
6417 (target.intent.getFlags()
6418 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006419 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006420 // If this activity is sending a reply to a previous
6421 // activity, we can't do anything with it now until
6422 // we reach the start of the reply chain.
6423 // XXX note that we are assuming the result is always
6424 // to the previous activity, which is almost always
6425 // the case but we really shouldn't count on.
6426 if (replyChainEnd < 0) {
6427 replyChainEnd = targetI;
6428 }
Ed Heyl73798232009-03-24 21:32:21 -07006429 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006430 && target.taskAffinity != null
6431 && !target.taskAffinity.equals(task.affinity)) {
6432 // If this activity has an affinity for another
6433 // task, then we need to move it out of here. We will
6434 // move it as far out of the way as possible, to the
6435 // bottom of the activity stack. This also keeps it
6436 // correctly ordered with any activities we previously
6437 // moved.
6438 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6439 if (target.taskAffinity != null
6440 && target.taskAffinity.equals(p.task.affinity)) {
6441 // If the activity currently at the bottom has the
6442 // same task affinity as the one we are moving,
6443 // then merge it into the same task.
6444 target.task = p.task;
6445 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6446 + " out to bottom task " + p.task);
6447 } else {
6448 mCurTask++;
6449 if (mCurTask <= 0) {
6450 mCurTask = 1;
6451 }
6452 target.task = new TaskRecord(mCurTask, target.info, null,
6453 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6454 target.task.affinityIntent = target.intent;
6455 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6456 + " out to new task " + target.task);
6457 }
6458 mWindowManager.setAppGroupId(target, task.taskId);
6459 if (replyChainEnd < 0) {
6460 replyChainEnd = targetI;
6461 }
6462 int dstPos = 0;
6463 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6464 p = (HistoryRecord)mHistory.get(srcPos);
6465 if (p.finishing) {
6466 continue;
6467 }
6468 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6469 + " out to target's task " + target.task);
6470 task.numActivities--;
6471 p.task = target.task;
6472 target.task.numActivities++;
6473 mHistory.remove(srcPos);
6474 mHistory.add(dstPos, p);
6475 mWindowManager.moveAppToken(dstPos, p);
6476 mWindowManager.setAppGroupId(p, p.task.taskId);
6477 dstPos++;
6478 if (VALIDATE_TOKENS) {
6479 mWindowManager.validateAppTokens(mHistory);
6480 }
6481 i++;
6482 }
6483 if (taskTop == p) {
6484 taskTop = below;
6485 }
6486 if (taskTopI == replyChainEnd) {
6487 taskTopI = -1;
6488 }
6489 replyChainEnd = -1;
6490 addRecentTask(target.task);
6491 } else if (forceReset || finishOnTaskLaunch
6492 || clearWhenTaskReset) {
6493 // If the activity should just be removed -- either
6494 // because it asks for it, or the task should be
6495 // cleared -- then finish it and anything that is
6496 // part of its reply chain.
6497 if (clearWhenTaskReset) {
6498 // In this case, we want to finish this activity
6499 // and everything above it, so be sneaky and pretend
6500 // like these are all in the reply chain.
6501 replyChainEnd = targetI+1;
6502 while (replyChainEnd < mHistory.size() &&
6503 ((HistoryRecord)mHistory.get(
6504 replyChainEnd)).task == task) {
6505 replyChainEnd++;
6506 }
6507 replyChainEnd--;
6508 } else if (replyChainEnd < 0) {
6509 replyChainEnd = targetI;
6510 }
6511 HistoryRecord p = null;
6512 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6513 p = (HistoryRecord)mHistory.get(srcPos);
6514 if (p.finishing) {
6515 continue;
6516 }
6517 if (finishActivityLocked(p, srcPos,
6518 Activity.RESULT_CANCELED, null, "reset")) {
6519 replyChainEnd--;
6520 srcPos--;
6521 }
6522 }
6523 if (taskTop == p) {
6524 taskTop = below;
6525 }
6526 if (taskTopI == replyChainEnd) {
6527 taskTopI = -1;
6528 }
6529 replyChainEnd = -1;
6530 } else {
6531 // If we were in the middle of a chain, well the
6532 // activity that started it all doesn't want anything
6533 // special, so leave it all as-is.
6534 replyChainEnd = -1;
6535 }
6536 } else {
6537 // Reached the bottom of the task -- any reply chain
6538 // should be left as-is.
6539 replyChainEnd = -1;
6540 }
6541
6542 } else if (target.resultTo != null) {
6543 // If this activity is sending a reply to a previous
6544 // activity, we can't do anything with it now until
6545 // we reach the start of the reply chain.
6546 // XXX note that we are assuming the result is always
6547 // to the previous activity, which is almost always
6548 // the case but we really shouldn't count on.
6549 if (replyChainEnd < 0) {
6550 replyChainEnd = targetI;
6551 }
6552
6553 } else if (taskTopI >= 0 && allowTaskReparenting
6554 && task.affinity != null
6555 && task.affinity.equals(target.taskAffinity)) {
6556 // We are inside of another task... if this activity has
6557 // an affinity for our task, then either remove it if we are
6558 // clearing or move it over to our task. Note that
6559 // we currently punt on the case where we are resetting a
6560 // task that is not at the top but who has activities above
6561 // with an affinity to it... this is really not a normal
6562 // case, and we will need to later pull that task to the front
6563 // and usually at that point we will do the reset and pick
6564 // up those remaining activities. (This only happens if
6565 // someone starts an activity in a new task from an activity
6566 // in a task that is not currently on top.)
6567 if (forceReset || finishOnTaskLaunch) {
6568 if (replyChainEnd < 0) {
6569 replyChainEnd = targetI;
6570 }
6571 HistoryRecord p = null;
6572 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6573 p = (HistoryRecord)mHistory.get(srcPos);
6574 if (p.finishing) {
6575 continue;
6576 }
6577 if (finishActivityLocked(p, srcPos,
6578 Activity.RESULT_CANCELED, null, "reset")) {
6579 taskTopI--;
6580 lastReparentPos--;
6581 replyChainEnd--;
6582 srcPos--;
6583 }
6584 }
6585 replyChainEnd = -1;
6586 } else {
6587 if (replyChainEnd < 0) {
6588 replyChainEnd = targetI;
6589 }
6590 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6591 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6592 if (p.finishing) {
6593 continue;
6594 }
6595 if (lastReparentPos < 0) {
6596 lastReparentPos = taskTopI;
6597 taskTop = p;
6598 } else {
6599 lastReparentPos--;
6600 }
6601 mHistory.remove(srcPos);
6602 p.task.numActivities--;
6603 p.task = task;
6604 mHistory.add(lastReparentPos, p);
6605 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6606 + " in to resetting task " + task);
6607 task.numActivities++;
6608 mWindowManager.moveAppToken(lastReparentPos, p);
6609 mWindowManager.setAppGroupId(p, p.task.taskId);
6610 if (VALIDATE_TOKENS) {
6611 mWindowManager.validateAppTokens(mHistory);
6612 }
6613 }
6614 replyChainEnd = -1;
6615
6616 // Now we've moved it in to place... but what if this is
6617 // a singleTop activity and we have put it on top of another
6618 // instance of the same activity? Then we drop the instance
6619 // below so it remains singleTop.
6620 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6621 for (int j=lastReparentPos-1; j>=0; j--) {
6622 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6623 if (p.finishing) {
6624 continue;
6625 }
6626 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6627 if (finishActivityLocked(p, j,
6628 Activity.RESULT_CANCELED, null, "replace")) {
6629 taskTopI--;
6630 lastReparentPos--;
6631 }
6632 }
6633 }
6634 }
6635 }
6636 }
6637
6638 target = below;
6639 targetI = i;
6640 }
6641
6642 return taskTop;
6643 }
6644
6645 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006646 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006647 */
6648 public void moveTaskToFront(int task) {
6649 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6650 "moveTaskToFront()");
6651
6652 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006653 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6654 Binder.getCallingUid(), "Task to front")) {
6655 return;
6656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006657 final long origId = Binder.clearCallingIdentity();
6658 try {
6659 int N = mRecentTasks.size();
6660 for (int i=0; i<N; i++) {
6661 TaskRecord tr = mRecentTasks.get(i);
6662 if (tr.taskId == task) {
6663 moveTaskToFrontLocked(tr);
6664 return;
6665 }
6666 }
6667 for (int i=mHistory.size()-1; i>=0; i--) {
6668 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6669 if (hr.task.taskId == task) {
6670 moveTaskToFrontLocked(hr.task);
6671 return;
6672 }
6673 }
6674 } finally {
6675 Binder.restoreCallingIdentity(origId);
6676 }
6677 }
6678 }
6679
6680 private final void moveTaskToFrontLocked(TaskRecord tr) {
6681 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6682
6683 final int task = tr.taskId;
6684 int top = mHistory.size()-1;
6685
6686 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6687 // nothing to do!
6688 return;
6689 }
6690
6691 if (DEBUG_TRANSITION) Log.v(TAG,
6692 "Prepare to front transition: task=" + tr);
6693 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6694
6695 ArrayList moved = new ArrayList();
6696
6697 // Applying the affinities may have removed entries from the history,
6698 // so get the size again.
6699 top = mHistory.size()-1;
6700 int pos = top;
6701
6702 // Shift all activities with this task up to the top
6703 // of the stack, keeping them in the same internal order.
6704 while (pos >= 0) {
6705 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6706 if (localLOGV) Log.v(
6707 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6708 boolean first = true;
6709 if (r.task.taskId == task) {
6710 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6711 mHistory.remove(pos);
6712 mHistory.add(top, r);
6713 moved.add(0, r);
6714 top--;
6715 if (first) {
6716 addRecentTask(r.task);
6717 first = false;
6718 }
6719 }
6720 pos--;
6721 }
6722
6723 mWindowManager.moveAppTokensToTop(moved);
6724 if (VALIDATE_TOKENS) {
6725 mWindowManager.validateAppTokens(mHistory);
6726 }
6727
6728 finishTaskMove(task);
6729 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6730 }
6731
6732 private final void finishTaskMove(int task) {
6733 resumeTopActivityLocked(null);
6734 }
6735
6736 public void moveTaskToBack(int task) {
6737 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6738 "moveTaskToBack()");
6739
6740 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006741 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6742 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6743 Binder.getCallingUid(), "Task to back")) {
6744 return;
6745 }
6746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006747 final long origId = Binder.clearCallingIdentity();
6748 moveTaskToBackLocked(task);
6749 Binder.restoreCallingIdentity(origId);
6750 }
6751 }
6752
6753 /**
6754 * Moves an activity, and all of the other activities within the same task, to the bottom
6755 * of the history stack. The activity's order within the task is unchanged.
6756 *
6757 * @param token A reference to the activity we wish to move
6758 * @param nonRoot If false then this only works if the activity is the root
6759 * of a task; if true it will work for any activity in a task.
6760 * @return Returns true if the move completed, false if not.
6761 */
6762 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6763 synchronized(this) {
6764 final long origId = Binder.clearCallingIdentity();
6765 int taskId = getTaskForActivityLocked(token, !nonRoot);
6766 if (taskId >= 0) {
6767 return moveTaskToBackLocked(taskId);
6768 }
6769 Binder.restoreCallingIdentity(origId);
6770 }
6771 return false;
6772 }
6773
6774 /**
6775 * Worker method for rearranging history stack. Implements the function of moving all
6776 * activities for a specific task (gathering them if disjoint) into a single group at the
6777 * bottom of the stack.
6778 *
6779 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6780 * to premeptively cancel the move.
6781 *
6782 * @param task The taskId to collect and move to the bottom.
6783 * @return Returns true if the move completed, false if not.
6784 */
6785 private final boolean moveTaskToBackLocked(int task) {
6786 Log.i(TAG, "moveTaskToBack: " + task);
6787
6788 // If we have a watcher, preflight the move before committing to it. First check
6789 // for *other* available tasks, but if none are available, then try again allowing the
6790 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006791 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006792 HistoryRecord next = topRunningActivityLocked(null, task);
6793 if (next == null) {
6794 next = topRunningActivityLocked(null, 0);
6795 }
6796 if (next != null) {
6797 // ask watcher if this is allowed
6798 boolean moveOK = true;
6799 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006800 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006801 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006802 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006803 }
6804 if (!moveOK) {
6805 return false;
6806 }
6807 }
6808 }
6809
6810 ArrayList moved = new ArrayList();
6811
6812 if (DEBUG_TRANSITION) Log.v(TAG,
6813 "Prepare to back transition: task=" + task);
6814 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6815
6816 final int N = mHistory.size();
6817 int bottom = 0;
6818 int pos = 0;
6819
6820 // Shift all activities with this task down to the bottom
6821 // of the stack, keeping them in the same internal order.
6822 while (pos < N) {
6823 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6824 if (localLOGV) Log.v(
6825 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6826 if (r.task.taskId == task) {
6827 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6828 mHistory.remove(pos);
6829 mHistory.add(bottom, r);
6830 moved.add(r);
6831 bottom++;
6832 }
6833 pos++;
6834 }
6835
6836 mWindowManager.moveAppTokensToBottom(moved);
6837 if (VALIDATE_TOKENS) {
6838 mWindowManager.validateAppTokens(mHistory);
6839 }
6840
6841 finishTaskMove(task);
6842 return true;
6843 }
6844
6845 public void moveTaskBackwards(int task) {
6846 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6847 "moveTaskBackwards()");
6848
6849 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006850 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6851 Binder.getCallingUid(), "Task backwards")) {
6852 return;
6853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006854 final long origId = Binder.clearCallingIdentity();
6855 moveTaskBackwardsLocked(task);
6856 Binder.restoreCallingIdentity(origId);
6857 }
6858 }
6859
6860 private final void moveTaskBackwardsLocked(int task) {
6861 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6862 }
6863
6864 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6865 synchronized(this) {
6866 return getTaskForActivityLocked(token, onlyRoot);
6867 }
6868 }
6869
6870 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6871 final int N = mHistory.size();
6872 TaskRecord lastTask = null;
6873 for (int i=0; i<N; i++) {
6874 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6875 if (r == token) {
6876 if (!onlyRoot || lastTask != r.task) {
6877 return r.task.taskId;
6878 }
6879 return -1;
6880 }
6881 lastTask = r.task;
6882 }
6883
6884 return -1;
6885 }
6886
6887 /**
6888 * Returns the top activity in any existing task matching the given
6889 * Intent. Returns null if no such task is found.
6890 */
6891 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6892 ComponentName cls = intent.getComponent();
6893 if (info.targetActivity != null) {
6894 cls = new ComponentName(info.packageName, info.targetActivity);
6895 }
6896
6897 TaskRecord cp = null;
6898
6899 final int N = mHistory.size();
6900 for (int i=(N-1); i>=0; i--) {
6901 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6902 if (!r.finishing && r.task != cp
6903 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6904 cp = r.task;
6905 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6906 // + "/aff=" + r.task.affinity + " to new cls="
6907 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6908 if (r.task.affinity != null) {
6909 if (r.task.affinity.equals(info.taskAffinity)) {
6910 //Log.i(TAG, "Found matching affinity!");
6911 return r;
6912 }
6913 } else if (r.task.intent != null
6914 && r.task.intent.getComponent().equals(cls)) {
6915 //Log.i(TAG, "Found matching class!");
6916 //dump();
6917 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6918 return r;
6919 } else if (r.task.affinityIntent != null
6920 && r.task.affinityIntent.getComponent().equals(cls)) {
6921 //Log.i(TAG, "Found matching class!");
6922 //dump();
6923 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6924 return r;
6925 }
6926 }
6927 }
6928
6929 return null;
6930 }
6931
6932 /**
6933 * Returns the first activity (starting from the top of the stack) that
6934 * is the same as the given activity. Returns null if no such activity
6935 * is found.
6936 */
6937 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6938 ComponentName cls = intent.getComponent();
6939 if (info.targetActivity != null) {
6940 cls = new ComponentName(info.packageName, info.targetActivity);
6941 }
6942
6943 final int N = mHistory.size();
6944 for (int i=(N-1); i>=0; i--) {
6945 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6946 if (!r.finishing) {
6947 if (r.intent.getComponent().equals(cls)) {
6948 //Log.i(TAG, "Found matching class!");
6949 //dump();
6950 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6951 return r;
6952 }
6953 }
6954 }
6955
6956 return null;
6957 }
6958
6959 public void finishOtherInstances(IBinder token, ComponentName className) {
6960 synchronized(this) {
6961 final long origId = Binder.clearCallingIdentity();
6962
6963 int N = mHistory.size();
6964 TaskRecord lastTask = null;
6965 for (int i=0; i<N; i++) {
6966 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6967 if (r.realActivity.equals(className)
6968 && r != token && lastTask != r.task) {
6969 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6970 null, "others")) {
6971 i--;
6972 N--;
6973 }
6974 }
6975 lastTask = r.task;
6976 }
6977
6978 Binder.restoreCallingIdentity(origId);
6979 }
6980 }
6981
6982 // =========================================================
6983 // THUMBNAILS
6984 // =========================================================
6985
6986 public void reportThumbnail(IBinder token,
6987 Bitmap thumbnail, CharSequence description) {
6988 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6989 final long origId = Binder.clearCallingIdentity();
6990 sendPendingThumbnail(null, token, thumbnail, description, true);
6991 Binder.restoreCallingIdentity(origId);
6992 }
6993
6994 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6995 Bitmap thumbnail, CharSequence description, boolean always) {
6996 TaskRecord task = null;
6997 ArrayList receivers = null;
6998
6999 //System.out.println("Send pending thumbnail: " + r);
7000
7001 synchronized(this) {
7002 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007003 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007004 if (index < 0) {
7005 return;
7006 }
7007 r = (HistoryRecord)mHistory.get(index);
7008 }
7009 if (thumbnail == null) {
7010 thumbnail = r.thumbnail;
7011 description = r.description;
7012 }
7013 if (thumbnail == null && !always) {
7014 // If there is no thumbnail, and this entry is not actually
7015 // going away, then abort for now and pick up the next
7016 // thumbnail we get.
7017 return;
7018 }
7019 task = r.task;
7020
7021 int N = mPendingThumbnails.size();
7022 int i=0;
7023 while (i<N) {
7024 PendingThumbnailsRecord pr =
7025 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7026 //System.out.println("Looking in " + pr.pendingRecords);
7027 if (pr.pendingRecords.remove(r)) {
7028 if (receivers == null) {
7029 receivers = new ArrayList();
7030 }
7031 receivers.add(pr);
7032 if (pr.pendingRecords.size() == 0) {
7033 pr.finished = true;
7034 mPendingThumbnails.remove(i);
7035 N--;
7036 continue;
7037 }
7038 }
7039 i++;
7040 }
7041 }
7042
7043 if (receivers != null) {
7044 final int N = receivers.size();
7045 for (int i=0; i<N; i++) {
7046 try {
7047 PendingThumbnailsRecord pr =
7048 (PendingThumbnailsRecord)receivers.get(i);
7049 pr.receiver.newThumbnail(
7050 task != null ? task.taskId : -1, thumbnail, description);
7051 if (pr.finished) {
7052 pr.receiver.finished();
7053 }
7054 } catch (Exception e) {
7055 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7056 }
7057 }
7058 }
7059 }
7060
7061 // =========================================================
7062 // CONTENT PROVIDERS
7063 // =========================================================
7064
7065 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7066 List providers = null;
7067 try {
7068 providers = ActivityThread.getPackageManager().
7069 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007070 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007071 } catch (RemoteException ex) {
7072 }
7073 if (providers != null) {
7074 final int N = providers.size();
7075 for (int i=0; i<N; i++) {
7076 ProviderInfo cpi =
7077 (ProviderInfo)providers.get(i);
7078 ContentProviderRecord cpr =
7079 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7080 if (cpr == null) {
7081 cpr = new ContentProviderRecord(cpi, app.info);
7082 mProvidersByClass.put(cpi.name, cpr);
7083 }
7084 app.pubProviders.put(cpi.name, cpr);
7085 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007086 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007087 }
7088 }
7089 return providers;
7090 }
7091
7092 private final String checkContentProviderPermissionLocked(
7093 ProviderInfo cpi, ProcessRecord r, int mode) {
7094 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7095 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7096 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7097 cpi.exported ? -1 : cpi.applicationInfo.uid)
7098 == PackageManager.PERMISSION_GRANTED
7099 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7100 return null;
7101 }
7102 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7103 cpi.exported ? -1 : cpi.applicationInfo.uid)
7104 == PackageManager.PERMISSION_GRANTED) {
7105 return null;
7106 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007107
7108 PathPermission[] pps = cpi.pathPermissions;
7109 if (pps != null) {
7110 int i = pps.length;
7111 while (i > 0) {
7112 i--;
7113 PathPermission pp = pps[i];
7114 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7115 cpi.exported ? -1 : cpi.applicationInfo.uid)
7116 == PackageManager.PERMISSION_GRANTED
7117 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7118 return null;
7119 }
7120 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7121 cpi.exported ? -1 : cpi.applicationInfo.uid)
7122 == PackageManager.PERMISSION_GRANTED) {
7123 return null;
7124 }
7125 }
7126 }
7127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007128 String msg = "Permission Denial: opening provider " + cpi.name
7129 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7130 + ", uid=" + callingUid + ") requires "
7131 + cpi.readPermission + " or " + cpi.writePermission;
7132 Log.w(TAG, msg);
7133 return msg;
7134 }
7135
7136 private final ContentProviderHolder getContentProviderImpl(
7137 IApplicationThread caller, String name) {
7138 ContentProviderRecord cpr;
7139 ProviderInfo cpi = null;
7140
7141 synchronized(this) {
7142 ProcessRecord r = null;
7143 if (caller != null) {
7144 r = getRecordForAppLocked(caller);
7145 if (r == null) {
7146 throw new SecurityException(
7147 "Unable to find app for caller " + caller
7148 + " (pid=" + Binder.getCallingPid()
7149 + ") when getting content provider " + name);
7150 }
7151 }
7152
7153 // First check if this content provider has been published...
7154 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7155 if (cpr != null) {
7156 cpi = cpr.info;
7157 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7158 return new ContentProviderHolder(cpi,
7159 cpi.readPermission != null
7160 ? cpi.readPermission : cpi.writePermission);
7161 }
7162
7163 if (r != null && cpr.canRunHere(r)) {
7164 // This provider has been published or is in the process
7165 // of being published... but it is also allowed to run
7166 // in the caller's process, so don't make a connection
7167 // and just let the caller instantiate its own instance.
7168 if (cpr.provider != null) {
7169 // don't give caller the provider object, it needs
7170 // to make its own.
7171 cpr = new ContentProviderRecord(cpr);
7172 }
7173 return cpr;
7174 }
7175
7176 final long origId = Binder.clearCallingIdentity();
7177
7178 // In this case the provider is a single instance, so we can
7179 // return it right away.
7180 if (r != null) {
7181 r.conProviders.add(cpr);
7182 cpr.clients.add(r);
7183 } else {
7184 cpr.externals++;
7185 }
7186
7187 if (cpr.app != null) {
7188 updateOomAdjLocked(cpr.app);
7189 }
7190
7191 Binder.restoreCallingIdentity(origId);
7192
7193 } else {
7194 try {
7195 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007196 resolveContentProvider(name,
7197 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007198 } catch (RemoteException ex) {
7199 }
7200 if (cpi == null) {
7201 return null;
7202 }
7203
7204 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7205 return new ContentProviderHolder(cpi,
7206 cpi.readPermission != null
7207 ? cpi.readPermission : cpi.writePermission);
7208 }
7209
7210 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7211 final boolean firstClass = cpr == null;
7212 if (firstClass) {
7213 try {
7214 ApplicationInfo ai =
7215 ActivityThread.getPackageManager().
7216 getApplicationInfo(
7217 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007218 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007219 if (ai == null) {
7220 Log.w(TAG, "No package info for content provider "
7221 + cpi.name);
7222 return null;
7223 }
7224 cpr = new ContentProviderRecord(cpi, ai);
7225 } catch (RemoteException ex) {
7226 // pm is in same process, this will never happen.
7227 }
7228 }
7229
7230 if (r != null && cpr.canRunHere(r)) {
7231 // If this is a multiprocess provider, then just return its
7232 // info and allow the caller to instantiate it. Only do
7233 // this if the provider is the same user as the caller's
7234 // process, or can run as root (so can be in any process).
7235 return cpr;
7236 }
7237
7238 if (false) {
7239 RuntimeException e = new RuntimeException("foo");
7240 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7241 // + " pruid " + ai.uid + "): " + cpi.className, e);
7242 }
7243
7244 // This is single process, and our app is now connecting to it.
7245 // See if we are already in the process of launching this
7246 // provider.
7247 final int N = mLaunchingProviders.size();
7248 int i;
7249 for (i=0; i<N; i++) {
7250 if (mLaunchingProviders.get(i) == cpr) {
7251 break;
7252 }
7253 if (false) {
7254 final ContentProviderRecord rec =
7255 (ContentProviderRecord)mLaunchingProviders.get(i);
7256 if (rec.info.name.equals(cpr.info.name)) {
7257 cpr = rec;
7258 break;
7259 }
7260 }
7261 }
7262
7263 // If the provider is not already being launched, then get it
7264 // started.
7265 if (i >= N) {
7266 final long origId = Binder.clearCallingIdentity();
7267 ProcessRecord proc = startProcessLocked(cpi.processName,
7268 cpr.appInfo, false, 0, "content provider",
7269 new ComponentName(cpi.applicationInfo.packageName,
7270 cpi.name));
7271 if (proc == null) {
7272 Log.w(TAG, "Unable to launch app "
7273 + cpi.applicationInfo.packageName + "/"
7274 + cpi.applicationInfo.uid + " for provider "
7275 + name + ": process is bad");
7276 return null;
7277 }
7278 cpr.launchingApp = proc;
7279 mLaunchingProviders.add(cpr);
7280 Binder.restoreCallingIdentity(origId);
7281 }
7282
7283 // Make sure the provider is published (the same provider class
7284 // may be published under multiple names).
7285 if (firstClass) {
7286 mProvidersByClass.put(cpi.name, cpr);
7287 }
7288 mProvidersByName.put(name, cpr);
7289
7290 if (r != null) {
7291 r.conProviders.add(cpr);
7292 cpr.clients.add(r);
7293 } else {
7294 cpr.externals++;
7295 }
7296 }
7297 }
7298
7299 // Wait for the provider to be published...
7300 synchronized (cpr) {
7301 while (cpr.provider == null) {
7302 if (cpr.launchingApp == null) {
7303 Log.w(TAG, "Unable to launch app "
7304 + cpi.applicationInfo.packageName + "/"
7305 + cpi.applicationInfo.uid + " for provider "
7306 + name + ": launching app became null");
7307 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7308 cpi.applicationInfo.packageName,
7309 cpi.applicationInfo.uid, name);
7310 return null;
7311 }
7312 try {
7313 cpr.wait();
7314 } catch (InterruptedException ex) {
7315 }
7316 }
7317 }
7318 return cpr;
7319 }
7320
7321 public final ContentProviderHolder getContentProvider(
7322 IApplicationThread caller, String name) {
7323 if (caller == null) {
7324 String msg = "null IApplicationThread when getting content provider "
7325 + name;
7326 Log.w(TAG, msg);
7327 throw new SecurityException(msg);
7328 }
7329
7330 return getContentProviderImpl(caller, name);
7331 }
7332
7333 private ContentProviderHolder getContentProviderExternal(String name) {
7334 return getContentProviderImpl(null, name);
7335 }
7336
7337 /**
7338 * Drop a content provider from a ProcessRecord's bookkeeping
7339 * @param cpr
7340 */
7341 public void removeContentProvider(IApplicationThread caller, String name) {
7342 synchronized (this) {
7343 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7344 if(cpr == null) {
7345 //remove from mProvidersByClass
7346 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7347 return;
7348 }
7349 final ProcessRecord r = getRecordForAppLocked(caller);
7350 if (r == null) {
7351 throw new SecurityException(
7352 "Unable to find app for caller " + caller +
7353 " when removing content provider " + name);
7354 }
7355 //update content provider record entry info
7356 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7357 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7358 r.info.processName+" from process "+localCpr.appInfo.processName);
7359 if(localCpr.appInfo.processName == r.info.processName) {
7360 //should not happen. taken care of as a local provider
7361 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7362 return;
7363 } else {
7364 localCpr.clients.remove(r);
7365 r.conProviders.remove(localCpr);
7366 }
7367 updateOomAdjLocked();
7368 }
7369 }
7370
7371 private void removeContentProviderExternal(String name) {
7372 synchronized (this) {
7373 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7374 if(cpr == null) {
7375 //remove from mProvidersByClass
7376 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7377 return;
7378 }
7379
7380 //update content provider record entry info
7381 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7382 localCpr.externals--;
7383 if (localCpr.externals < 0) {
7384 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7385 }
7386 updateOomAdjLocked();
7387 }
7388 }
7389
7390 public final void publishContentProviders(IApplicationThread caller,
7391 List<ContentProviderHolder> providers) {
7392 if (providers == null) {
7393 return;
7394 }
7395
7396 synchronized(this) {
7397 final ProcessRecord r = getRecordForAppLocked(caller);
7398 if (r == null) {
7399 throw new SecurityException(
7400 "Unable to find app for caller " + caller
7401 + " (pid=" + Binder.getCallingPid()
7402 + ") when publishing content providers");
7403 }
7404
7405 final long origId = Binder.clearCallingIdentity();
7406
7407 final int N = providers.size();
7408 for (int i=0; i<N; i++) {
7409 ContentProviderHolder src = providers.get(i);
7410 if (src == null || src.info == null || src.provider == null) {
7411 continue;
7412 }
7413 ContentProviderRecord dst =
7414 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7415 if (dst != null) {
7416 mProvidersByClass.put(dst.info.name, dst);
7417 String names[] = dst.info.authority.split(";");
7418 for (int j = 0; j < names.length; j++) {
7419 mProvidersByName.put(names[j], dst);
7420 }
7421
7422 int NL = mLaunchingProviders.size();
7423 int j;
7424 for (j=0; j<NL; j++) {
7425 if (mLaunchingProviders.get(j) == dst) {
7426 mLaunchingProviders.remove(j);
7427 j--;
7428 NL--;
7429 }
7430 }
7431 synchronized (dst) {
7432 dst.provider = src.provider;
7433 dst.app = r;
7434 dst.notifyAll();
7435 }
7436 updateOomAdjLocked(r);
7437 }
7438 }
7439
7440 Binder.restoreCallingIdentity(origId);
7441 }
7442 }
7443
7444 public static final void installSystemProviders() {
7445 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7446 List providers = mSelf.generateApplicationProvidersLocked(app);
7447 mSystemThread.installSystemProviders(providers);
7448 }
7449
7450 // =========================================================
7451 // GLOBAL MANAGEMENT
7452 // =========================================================
7453
7454 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7455 ApplicationInfo info, String customProcess) {
7456 String proc = customProcess != null ? customProcess : info.processName;
7457 BatteryStatsImpl.Uid.Proc ps = null;
7458 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7459 synchronized (stats) {
7460 ps = stats.getProcessStatsLocked(info.uid, proc);
7461 }
7462 return new ProcessRecord(ps, thread, info, proc);
7463 }
7464
7465 final ProcessRecord addAppLocked(ApplicationInfo info) {
7466 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7467
7468 if (app == null) {
7469 app = newProcessRecordLocked(null, info, null);
7470 mProcessNames.put(info.processName, info.uid, app);
7471 updateLRUListLocked(app, true);
7472 }
7473
7474 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7475 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7476 app.persistent = true;
7477 app.maxAdj = CORE_SERVER_ADJ;
7478 }
7479 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7480 mPersistentStartingProcesses.add(app);
7481 startProcessLocked(app, "added application", app.processName);
7482 }
7483
7484 return app;
7485 }
7486
7487 public void unhandledBack() {
7488 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7489 "unhandledBack()");
7490
7491 synchronized(this) {
7492 int count = mHistory.size();
7493 if (Config.LOGD) Log.d(
7494 TAG, "Performing unhandledBack(): stack size = " + count);
7495 if (count > 1) {
7496 final long origId = Binder.clearCallingIdentity();
7497 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7498 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7499 Binder.restoreCallingIdentity(origId);
7500 }
7501 }
7502 }
7503
7504 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7505 String name = uri.getAuthority();
7506 ContentProviderHolder cph = getContentProviderExternal(name);
7507 ParcelFileDescriptor pfd = null;
7508 if (cph != null) {
7509 // We record the binder invoker's uid in thread-local storage before
7510 // going to the content provider to open the file. Later, in the code
7511 // that handles all permissions checks, we look for this uid and use
7512 // that rather than the Activity Manager's own uid. The effect is that
7513 // we do the check against the caller's permissions even though it looks
7514 // to the content provider like the Activity Manager itself is making
7515 // the request.
7516 sCallerIdentity.set(new Identity(
7517 Binder.getCallingPid(), Binder.getCallingUid()));
7518 try {
7519 pfd = cph.provider.openFile(uri, "r");
7520 } catch (FileNotFoundException e) {
7521 // do nothing; pfd will be returned null
7522 } finally {
7523 // Ensure that whatever happens, we clean up the identity state
7524 sCallerIdentity.remove();
7525 }
7526
7527 // We've got the fd now, so we're done with the provider.
7528 removeContentProviderExternal(name);
7529 } else {
7530 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7531 }
7532 return pfd;
7533 }
7534
7535 public void goingToSleep() {
7536 synchronized(this) {
7537 mSleeping = true;
7538 mWindowManager.setEventDispatching(false);
7539
7540 if (mResumedActivity != null) {
7541 pauseIfSleepingLocked();
7542 } else {
7543 Log.w(TAG, "goingToSleep with no resumed activity!");
7544 }
7545 }
7546 }
7547
Dianne Hackborn55280a92009-05-07 15:53:46 -07007548 public boolean shutdown(int timeout) {
7549 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7550 != PackageManager.PERMISSION_GRANTED) {
7551 throw new SecurityException("Requires permission "
7552 + android.Manifest.permission.SHUTDOWN);
7553 }
7554
7555 boolean timedout = false;
7556
7557 synchronized(this) {
7558 mShuttingDown = true;
7559 mWindowManager.setEventDispatching(false);
7560
7561 if (mResumedActivity != null) {
7562 pauseIfSleepingLocked();
7563 final long endTime = System.currentTimeMillis() + timeout;
7564 while (mResumedActivity != null || mPausingActivity != null) {
7565 long delay = endTime - System.currentTimeMillis();
7566 if (delay <= 0) {
7567 Log.w(TAG, "Activity manager shutdown timed out");
7568 timedout = true;
7569 break;
7570 }
7571 try {
7572 this.wait();
7573 } catch (InterruptedException e) {
7574 }
7575 }
7576 }
7577 }
7578
7579 mUsageStatsService.shutdown();
7580 mBatteryStatsService.shutdown();
7581
7582 return timedout;
7583 }
7584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007585 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007586 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007587 if (!mGoingToSleep.isHeld()) {
7588 mGoingToSleep.acquire();
7589 if (mLaunchingActivity.isHeld()) {
7590 mLaunchingActivity.release();
7591 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7592 }
7593 }
7594
7595 // If we are not currently pausing an activity, get the current
7596 // one to pause. If we are pausing one, we will just let that stuff
7597 // run and release the wake lock when all done.
7598 if (mPausingActivity == null) {
7599 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7600 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7601 startPausingLocked(false, true);
7602 }
7603 }
7604 }
7605
7606 public void wakingUp() {
7607 synchronized(this) {
7608 if (mGoingToSleep.isHeld()) {
7609 mGoingToSleep.release();
7610 }
7611 mWindowManager.setEventDispatching(true);
7612 mSleeping = false;
7613 resumeTopActivityLocked(null);
7614 }
7615 }
7616
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007617 public void stopAppSwitches() {
7618 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7619 != PackageManager.PERMISSION_GRANTED) {
7620 throw new SecurityException("Requires permission "
7621 + android.Manifest.permission.STOP_APP_SWITCHES);
7622 }
7623
7624 synchronized(this) {
7625 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7626 + APP_SWITCH_DELAY_TIME;
7627 mDidAppSwitch = false;
7628 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7629 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7630 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7631 }
7632 }
7633
7634 public void resumeAppSwitches() {
7635 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7636 != PackageManager.PERMISSION_GRANTED) {
7637 throw new SecurityException("Requires permission "
7638 + android.Manifest.permission.STOP_APP_SWITCHES);
7639 }
7640
7641 synchronized(this) {
7642 // Note that we don't execute any pending app switches... we will
7643 // let those wait until either the timeout, or the next start
7644 // activity request.
7645 mAppSwitchesAllowedTime = 0;
7646 }
7647 }
7648
7649 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7650 String name) {
7651 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7652 return true;
7653 }
7654
7655 final int perm = checkComponentPermission(
7656 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7657 callingUid, -1);
7658 if (perm == PackageManager.PERMISSION_GRANTED) {
7659 return true;
7660 }
7661
7662 Log.w(TAG, name + " request from " + callingUid + " stopped");
7663 return false;
7664 }
7665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007666 public void setDebugApp(String packageName, boolean waitForDebugger,
7667 boolean persistent) {
7668 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7669 "setDebugApp()");
7670
7671 // Note that this is not really thread safe if there are multiple
7672 // callers into it at the same time, but that's not a situation we
7673 // care about.
7674 if (persistent) {
7675 final ContentResolver resolver = mContext.getContentResolver();
7676 Settings.System.putString(
7677 resolver, Settings.System.DEBUG_APP,
7678 packageName);
7679 Settings.System.putInt(
7680 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7681 waitForDebugger ? 1 : 0);
7682 }
7683
7684 synchronized (this) {
7685 if (!persistent) {
7686 mOrigDebugApp = mDebugApp;
7687 mOrigWaitForDebugger = mWaitForDebugger;
7688 }
7689 mDebugApp = packageName;
7690 mWaitForDebugger = waitForDebugger;
7691 mDebugTransient = !persistent;
7692 if (packageName != null) {
7693 final long origId = Binder.clearCallingIdentity();
7694 uninstallPackageLocked(packageName, -1, false);
7695 Binder.restoreCallingIdentity(origId);
7696 }
7697 }
7698 }
7699
7700 public void setAlwaysFinish(boolean enabled) {
7701 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7702 "setAlwaysFinish()");
7703
7704 Settings.System.putInt(
7705 mContext.getContentResolver(),
7706 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7707
7708 synchronized (this) {
7709 mAlwaysFinishActivities = enabled;
7710 }
7711 }
7712
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007713 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007714 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007715 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007716 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007717 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007718 }
7719 }
7720
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007721 public void registerActivityWatcher(IActivityWatcher watcher) {
7722 mWatchers.register(watcher);
7723 }
7724
7725 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7726 mWatchers.unregister(watcher);
7727 }
7728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007729 public final void enterSafeMode() {
7730 synchronized(this) {
7731 // It only makes sense to do this before the system is ready
7732 // and started launching other packages.
7733 if (!mSystemReady) {
7734 try {
7735 ActivityThread.getPackageManager().enterSafeMode();
7736 } catch (RemoteException e) {
7737 }
7738
7739 View v = LayoutInflater.from(mContext).inflate(
7740 com.android.internal.R.layout.safe_mode, null);
7741 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7742 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7743 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7744 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7745 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7746 lp.format = v.getBackground().getOpacity();
7747 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7748 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7749 ((WindowManager)mContext.getSystemService(
7750 Context.WINDOW_SERVICE)).addView(v, lp);
7751 }
7752 }
7753 }
7754
7755 public void noteWakeupAlarm(IIntentSender sender) {
7756 if (!(sender instanceof PendingIntentRecord)) {
7757 return;
7758 }
7759 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7760 synchronized (stats) {
7761 if (mBatteryStatsService.isOnBattery()) {
7762 mBatteryStatsService.enforceCallingPermission();
7763 PendingIntentRecord rec = (PendingIntentRecord)sender;
7764 int MY_UID = Binder.getCallingUid();
7765 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7766 BatteryStatsImpl.Uid.Pkg pkg =
7767 stats.getPackageStatsLocked(uid, rec.key.packageName);
7768 pkg.incWakeupsLocked();
7769 }
7770 }
7771 }
7772
7773 public boolean killPidsForMemory(int[] pids) {
7774 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7775 throw new SecurityException("killPidsForMemory only available to the system");
7776 }
7777
7778 // XXX Note: don't acquire main activity lock here, because the window
7779 // manager calls in with its locks held.
7780
7781 boolean killed = false;
7782 synchronized (mPidsSelfLocked) {
7783 int[] types = new int[pids.length];
7784 int worstType = 0;
7785 for (int i=0; i<pids.length; i++) {
7786 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7787 if (proc != null) {
7788 int type = proc.setAdj;
7789 types[i] = type;
7790 if (type > worstType) {
7791 worstType = type;
7792 }
7793 }
7794 }
7795
7796 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7797 // then constrain it so we will kill all hidden procs.
7798 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7799 worstType = HIDDEN_APP_MIN_ADJ;
7800 }
7801 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7802 for (int i=0; i<pids.length; i++) {
7803 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7804 if (proc == null) {
7805 continue;
7806 }
7807 int adj = proc.setAdj;
7808 if (adj >= worstType) {
7809 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7810 + adj + ")");
7811 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7812 proc.processName, adj);
7813 killed = true;
7814 Process.killProcess(pids[i]);
7815 }
7816 }
7817 }
7818 return killed;
7819 }
7820
7821 public void reportPss(IApplicationThread caller, int pss) {
7822 Watchdog.PssRequestor req;
7823 String name;
7824 ProcessRecord callerApp;
7825 synchronized (this) {
7826 if (caller == null) {
7827 return;
7828 }
7829 callerApp = getRecordForAppLocked(caller);
7830 if (callerApp == null) {
7831 return;
7832 }
7833 callerApp.lastPss = pss;
7834 req = callerApp;
7835 name = callerApp.processName;
7836 }
7837 Watchdog.getInstance().reportPss(req, name, pss);
7838 if (!callerApp.persistent) {
7839 removeRequestedPss(callerApp);
7840 }
7841 }
7842
7843 public void requestPss(Runnable completeCallback) {
7844 ArrayList<ProcessRecord> procs;
7845 synchronized (this) {
7846 mRequestPssCallback = completeCallback;
7847 mRequestPssList.clear();
7848 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7849 ProcessRecord proc = mLRUProcesses.get(i);
7850 if (!proc.persistent) {
7851 mRequestPssList.add(proc);
7852 }
7853 }
7854 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7855 }
7856
7857 int oldPri = Process.getThreadPriority(Process.myTid());
7858 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7859 for (int i=procs.size()-1; i>=0; i--) {
7860 ProcessRecord proc = procs.get(i);
7861 proc.lastPss = 0;
7862 proc.requestPss();
7863 }
7864 Process.setThreadPriority(oldPri);
7865 }
7866
7867 void removeRequestedPss(ProcessRecord proc) {
7868 Runnable callback = null;
7869 synchronized (this) {
7870 if (mRequestPssList.remove(proc)) {
7871 if (mRequestPssList.size() == 0) {
7872 callback = mRequestPssCallback;
7873 mRequestPssCallback = null;
7874 }
7875 }
7876 }
7877
7878 if (callback != null) {
7879 callback.run();
7880 }
7881 }
7882
7883 public void collectPss(Watchdog.PssStats stats) {
7884 stats.mEmptyPss = 0;
7885 stats.mEmptyCount = 0;
7886 stats.mBackgroundPss = 0;
7887 stats.mBackgroundCount = 0;
7888 stats.mServicePss = 0;
7889 stats.mServiceCount = 0;
7890 stats.mVisiblePss = 0;
7891 stats.mVisibleCount = 0;
7892 stats.mForegroundPss = 0;
7893 stats.mForegroundCount = 0;
7894 stats.mNoPssCount = 0;
7895 synchronized (this) {
7896 int i;
7897 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7898 ? mProcDeaths.length : stats.mProcDeaths.length;
7899 int aggr = 0;
7900 for (i=0; i<NPD; i++) {
7901 aggr += mProcDeaths[i];
7902 stats.mProcDeaths[i] = aggr;
7903 }
7904 while (i<stats.mProcDeaths.length) {
7905 stats.mProcDeaths[i] = 0;
7906 i++;
7907 }
7908
7909 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7910 ProcessRecord proc = mLRUProcesses.get(i);
7911 if (proc.persistent) {
7912 continue;
7913 }
7914 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7915 if (proc.lastPss == 0) {
7916 stats.mNoPssCount++;
7917 continue;
7918 }
7919 if (proc.setAdj == EMPTY_APP_ADJ) {
7920 stats.mEmptyPss += proc.lastPss;
7921 stats.mEmptyCount++;
7922 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7923 stats.mEmptyPss += proc.lastPss;
7924 stats.mEmptyCount++;
7925 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7926 stats.mBackgroundPss += proc.lastPss;
7927 stats.mBackgroundCount++;
7928 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7929 stats.mVisiblePss += proc.lastPss;
7930 stats.mVisibleCount++;
7931 } else {
7932 stats.mForegroundPss += proc.lastPss;
7933 stats.mForegroundCount++;
7934 }
7935 }
7936 }
7937 }
7938
7939 public final void startRunning(String pkg, String cls, String action,
7940 String data) {
7941 synchronized(this) {
7942 if (mStartRunning) {
7943 return;
7944 }
7945 mStartRunning = true;
7946 mTopComponent = pkg != null && cls != null
7947 ? new ComponentName(pkg, cls) : null;
7948 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7949 mTopData = data;
7950 if (!mSystemReady) {
7951 return;
7952 }
7953 }
7954
7955 systemReady();
7956 }
7957
7958 private void retrieveSettings() {
7959 final ContentResolver resolver = mContext.getContentResolver();
7960 String debugApp = Settings.System.getString(
7961 resolver, Settings.System.DEBUG_APP);
7962 boolean waitForDebugger = Settings.System.getInt(
7963 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7964 boolean alwaysFinishActivities = Settings.System.getInt(
7965 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7966
7967 Configuration configuration = new Configuration();
7968 Settings.System.getConfiguration(resolver, configuration);
7969
7970 synchronized (this) {
7971 mDebugApp = mOrigDebugApp = debugApp;
7972 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7973 mAlwaysFinishActivities = alwaysFinishActivities;
7974 // This happens before any activities are started, so we can
7975 // change mConfiguration in-place.
7976 mConfiguration.updateFrom(configuration);
7977 }
7978 }
7979
7980 public boolean testIsSystemReady() {
7981 // no need to synchronize(this) just to read & return the value
7982 return mSystemReady;
7983 }
7984
7985 public void systemReady() {
7986 // In the simulator, startRunning will never have been called, which
7987 // normally sets a few crucial variables. Do it here instead.
7988 if (!Process.supportsProcesses()) {
7989 mStartRunning = true;
7990 mTopAction = Intent.ACTION_MAIN;
7991 }
7992
7993 synchronized(this) {
7994 if (mSystemReady) {
7995 return;
7996 }
7997 mSystemReady = true;
7998 if (!mStartRunning) {
7999 return;
8000 }
8001 }
8002
8003 if (Config.LOGD) Log.d(TAG, "Start running!");
8004 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8005 SystemClock.uptimeMillis());
8006
8007 synchronized(this) {
8008 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8009 ResolveInfo ri = mContext.getPackageManager()
8010 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008011 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008012 CharSequence errorMsg = null;
8013 if (ri != null) {
8014 ActivityInfo ai = ri.activityInfo;
8015 ApplicationInfo app = ai.applicationInfo;
8016 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8017 mTopAction = Intent.ACTION_FACTORY_TEST;
8018 mTopData = null;
8019 mTopComponent = new ComponentName(app.packageName,
8020 ai.name);
8021 } else {
8022 errorMsg = mContext.getResources().getText(
8023 com.android.internal.R.string.factorytest_not_system);
8024 }
8025 } else {
8026 errorMsg = mContext.getResources().getText(
8027 com.android.internal.R.string.factorytest_no_action);
8028 }
8029 if (errorMsg != null) {
8030 mTopAction = null;
8031 mTopData = null;
8032 mTopComponent = null;
8033 Message msg = Message.obtain();
8034 msg.what = SHOW_FACTORY_ERROR_MSG;
8035 msg.getData().putCharSequence("msg", errorMsg);
8036 mHandler.sendMessage(msg);
8037 }
8038 }
8039 }
8040
8041 retrieveSettings();
8042
8043 synchronized (this) {
8044 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8045 try {
8046 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008047 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008048 if (apps != null) {
8049 int N = apps.size();
8050 int i;
8051 for (i=0; i<N; i++) {
8052 ApplicationInfo info
8053 = (ApplicationInfo)apps.get(i);
8054 if (info != null &&
8055 !info.packageName.equals("android")) {
8056 addAppLocked(info);
8057 }
8058 }
8059 }
8060 } catch (RemoteException ex) {
8061 // pm is in same process, this will never happen.
8062 }
8063 }
8064
8065 try {
8066 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8067 Message msg = Message.obtain();
8068 msg.what = SHOW_UID_ERROR_MSG;
8069 mHandler.sendMessage(msg);
8070 }
8071 } catch (RemoteException e) {
8072 }
8073
8074 // Start up initial activity.
8075 mBooting = true;
8076 resumeTopActivityLocked(null);
8077 }
8078 }
8079
8080 boolean makeAppCrashingLocked(ProcessRecord app,
8081 String tag, String shortMsg, String longMsg, byte[] crashData) {
8082 app.crashing = true;
8083 app.crashingReport = generateProcessError(app,
8084 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8085 startAppProblemLocked(app);
8086 app.stopFreezingAllLocked();
8087 return handleAppCrashLocked(app);
8088 }
8089
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008090 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8091 IPackageManager pm = ActivityThread.getPackageManager();
8092 try {
8093 // was an installer package name specified when this app was
8094 // installed?
8095 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8096 if (installerPackageName == null) {
8097 return null;
8098 }
8099
8100 // is there an Activity in this package that handles ACTION_APP_ERROR?
8101 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008102 intent.setPackage(installerPackageName);
8103 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008104 if (info == null || info.activityInfo == null) {
8105 return null;
8106 }
8107
8108 return new ComponentName(installerPackageName, info.activityInfo.name);
8109 } catch (RemoteException e) {
8110 // will return null and no error report will be delivered
8111 }
8112 return null;
8113 }
8114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008115 void makeAppNotRespondingLocked(ProcessRecord app,
8116 String tag, String shortMsg, String longMsg, byte[] crashData) {
8117 app.notResponding = true;
8118 app.notRespondingReport = generateProcessError(app,
8119 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8120 crashData);
8121 startAppProblemLocked(app);
8122 app.stopFreezingAllLocked();
8123 }
8124
8125 /**
8126 * Generate a process error record, suitable for attachment to a ProcessRecord.
8127 *
8128 * @param app The ProcessRecord in which the error occurred.
8129 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8130 * ActivityManager.AppErrorStateInfo
8131 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8132 * @param shortMsg Short message describing the crash.
8133 * @param longMsg Long message describing the crash.
8134 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8135 *
8136 * @return Returns a fully-formed AppErrorStateInfo record.
8137 */
8138 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8139 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8140 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8141
8142 report.condition = condition;
8143 report.processName = app.processName;
8144 report.pid = app.pid;
8145 report.uid = app.info.uid;
8146 report.tag = tag;
8147 report.shortMsg = shortMsg;
8148 report.longMsg = longMsg;
8149 report.crashData = crashData;
8150
8151 return report;
8152 }
8153
8154 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8155 boolean crashed) {
8156 synchronized (this) {
8157 app.crashing = false;
8158 app.crashingReport = null;
8159 app.notResponding = false;
8160 app.notRespondingReport = null;
8161 if (app.anrDialog == fromDialog) {
8162 app.anrDialog = null;
8163 }
8164 if (app.waitDialog == fromDialog) {
8165 app.waitDialog = null;
8166 }
8167 if (app.pid > 0 && app.pid != MY_PID) {
8168 if (crashed) {
8169 handleAppCrashLocked(app);
8170 }
8171 Log.i(ActivityManagerService.TAG, "Killing process "
8172 + app.processName
8173 + " (pid=" + app.pid + ") at user's request");
8174 Process.killProcess(app.pid);
8175 }
8176
8177 }
8178 }
8179
8180 boolean handleAppCrashLocked(ProcessRecord app) {
8181 long now = SystemClock.uptimeMillis();
8182
8183 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8184 app.info.uid);
8185 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8186 // This process loses!
8187 Log.w(TAG, "Process " + app.info.processName
8188 + " has crashed too many times: killing!");
8189 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8190 app.info.processName, app.info.uid);
8191 killServicesLocked(app, false);
8192 for (int i=mHistory.size()-1; i>=0; i--) {
8193 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8194 if (r.app == app) {
8195 if (Config.LOGD) Log.d(
8196 TAG, " Force finishing activity "
8197 + r.intent.getComponent().flattenToShortString());
8198 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8199 }
8200 }
8201 if (!app.persistent) {
8202 // We don't want to start this process again until the user
8203 // explicitly does so... but for persistent process, we really
8204 // need to keep it running. If a persistent process is actually
8205 // repeatedly crashing, then badness for everyone.
8206 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8207 app.info.processName);
8208 mBadProcesses.put(app.info.processName, app.info.uid, now);
8209 app.bad = true;
8210 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8211 app.removed = true;
8212 removeProcessLocked(app, false);
8213 return false;
8214 }
8215 }
8216
8217 // Bump up the crash count of any services currently running in the proc.
8218 if (app.services.size() != 0) {
8219 // Any services running in the application need to be placed
8220 // back in the pending list.
8221 Iterator it = app.services.iterator();
8222 while (it.hasNext()) {
8223 ServiceRecord sr = (ServiceRecord)it.next();
8224 sr.crashCount++;
8225 }
8226 }
8227
8228 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8229 return true;
8230 }
8231
8232 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008233 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008234 skipCurrentReceiverLocked(app);
8235 }
8236
8237 void skipCurrentReceiverLocked(ProcessRecord app) {
8238 boolean reschedule = false;
8239 BroadcastRecord r = app.curReceiver;
8240 if (r != null) {
8241 // The current broadcast is waiting for this app's receiver
8242 // to be finished. Looks like that's not going to happen, so
8243 // let the broadcast continue.
8244 logBroadcastReceiverDiscard(r);
8245 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8246 r.resultExtras, r.resultAbort, true);
8247 reschedule = true;
8248 }
8249 r = mPendingBroadcast;
8250 if (r != null && r.curApp == app) {
8251 if (DEBUG_BROADCAST) Log.v(TAG,
8252 "skip & discard pending app " + r);
8253 logBroadcastReceiverDiscard(r);
8254 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8255 r.resultExtras, r.resultAbort, true);
8256 reschedule = true;
8257 }
8258 if (reschedule) {
8259 scheduleBroadcastsLocked();
8260 }
8261 }
8262
8263 public int handleApplicationError(IBinder app, int flags,
8264 String tag, String shortMsg, String longMsg, byte[] crashData) {
8265 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008266 ProcessRecord r = null;
8267 synchronized (this) {
8268 if (app != null) {
8269 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8270 final int NA = apps.size();
8271 for (int ia=0; ia<NA; ia++) {
8272 ProcessRecord p = apps.valueAt(ia);
8273 if (p.thread != null && p.thread.asBinder() == app) {
8274 r = p;
8275 break;
8276 }
8277 }
8278 }
8279 }
8280
8281 if (r != null) {
8282 // The application has crashed. Send the SIGQUIT to the process so
8283 // that it can dump its state.
8284 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8285 //Log.i(TAG, "Current system threads:");
8286 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8287 }
8288
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008289 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008290 try {
8291 String name = r != null ? r.processName : null;
8292 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008293 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008294 shortMsg, longMsg, crashData)) {
8295 Log.w(TAG, "Force-killing crashed app " + name
8296 + " at watcher's request");
8297 Process.killProcess(pid);
8298 return 0;
8299 }
8300 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008301 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008302 }
8303 }
8304
8305 final long origId = Binder.clearCallingIdentity();
8306
8307 // If this process is running instrumentation, finish it.
8308 if (r != null && r.instrumentationClass != null) {
8309 Log.w(TAG, "Error in app " + r.processName
8310 + " running instrumentation " + r.instrumentationClass + ":");
8311 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8312 if (longMsg != null) Log.w(TAG, " " + longMsg);
8313 Bundle info = new Bundle();
8314 info.putString("shortMsg", shortMsg);
8315 info.putString("longMsg", longMsg);
8316 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8317 Binder.restoreCallingIdentity(origId);
8318 return 0;
8319 }
8320
8321 if (r != null) {
8322 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8323 return 0;
8324 }
8325 } else {
8326 Log.w(TAG, "Some application object " + app + " tag " + tag
8327 + " has crashed, but I don't know who it is.");
8328 Log.w(TAG, "ShortMsg:" + shortMsg);
8329 Log.w(TAG, "LongMsg:" + longMsg);
8330 Binder.restoreCallingIdentity(origId);
8331 return 0;
8332 }
8333
8334 Message msg = Message.obtain();
8335 msg.what = SHOW_ERROR_MSG;
8336 HashMap data = new HashMap();
8337 data.put("result", result);
8338 data.put("app", r);
8339 data.put("flags", flags);
8340 data.put("shortMsg", shortMsg);
8341 data.put("longMsg", longMsg);
8342 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8343 // For system processes, submit crash data to the server.
8344 data.put("crashData", crashData);
8345 }
8346 msg.obj = data;
8347 mHandler.sendMessage(msg);
8348
8349 Binder.restoreCallingIdentity(origId);
8350 }
8351
8352 int res = result.get();
8353
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008354 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008355 synchronized (this) {
8356 if (r != null) {
8357 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8358 SystemClock.uptimeMillis());
8359 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008360 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8361 appErrorIntent = createAppErrorIntentLocked(r);
8362 res = AppErrorDialog.FORCE_QUIT;
8363 }
8364 }
8365
8366 if (appErrorIntent != null) {
8367 try {
8368 mContext.startActivity(appErrorIntent);
8369 } catch (ActivityNotFoundException e) {
8370 Log.w(TAG, "bug report receiver dissappeared", e);
8371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008372 }
8373
8374 return res;
8375 }
8376
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008377 Intent createAppErrorIntentLocked(ProcessRecord r) {
8378 ApplicationErrorReport report = createAppErrorReportLocked(r);
8379 if (report == null) {
8380 return null;
8381 }
8382 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8383 result.setComponent(r.errorReportReceiver);
8384 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8385 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8386 return result;
8387 }
8388
8389 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8390 if (r.errorReportReceiver == null) {
8391 return null;
8392 }
8393
8394 if (!r.crashing && !r.notResponding) {
8395 return null;
8396 }
8397
8398 try {
8399 ApplicationErrorReport report = new ApplicationErrorReport();
8400 report.packageName = r.info.packageName;
8401 report.installerPackageName = r.errorReportReceiver.getPackageName();
8402 report.processName = r.processName;
8403
8404 if (r.crashing) {
8405 report.type = ApplicationErrorReport.TYPE_CRASH;
8406 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8407
8408 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8409 r.crashingReport.crashData);
8410 DataInputStream dataStream = new DataInputStream(byteStream);
8411 CrashData crashData = new CrashData(dataStream);
8412 ThrowableData throwData = crashData.getThrowableData();
8413
8414 report.time = crashData.getTime();
8415 report.crashInfo.stackTrace = throwData.toString();
8416
Jacek Surazskif829a782009-06-11 22:47:02 +02008417 // Extract the source of the exception, useful for report
8418 // clustering. Also extract the "deepest" non-null exception
8419 // message.
8420 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008421 while (throwData.getCause() != null) {
8422 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008423 String msg = throwData.getMessage();
8424 if (msg != null && msg.length() > 0) {
8425 exceptionMessage = msg;
8426 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008427 }
8428 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008429 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008430 report.crashInfo.exceptionClassName = throwData.getType();
8431 report.crashInfo.throwFileName = trace.getFileName();
8432 report.crashInfo.throwClassName = trace.getClassName();
8433 report.crashInfo.throwMethodName = trace.getMethodName();
8434 } else if (r.notResponding) {
8435 report.type = ApplicationErrorReport.TYPE_ANR;
8436 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8437
8438 report.anrInfo.activity = r.notRespondingReport.tag;
8439 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8440 report.anrInfo.info = r.notRespondingReport.longMsg;
8441 }
8442
8443 return report;
8444 } catch (IOException e) {
8445 // we don't send it
8446 }
8447
8448 return null;
8449 }
8450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008451 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8452 // assume our apps are happy - lazy create the list
8453 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8454
8455 synchronized (this) {
8456
8457 // iterate across all processes
8458 final int N = mLRUProcesses.size();
8459 for (int i = 0; i < N; i++) {
8460 ProcessRecord app = mLRUProcesses.get(i);
8461 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8462 // This one's in trouble, so we'll generate a report for it
8463 // crashes are higher priority (in case there's a crash *and* an anr)
8464 ActivityManager.ProcessErrorStateInfo report = null;
8465 if (app.crashing) {
8466 report = app.crashingReport;
8467 } else if (app.notResponding) {
8468 report = app.notRespondingReport;
8469 }
8470
8471 if (report != null) {
8472 if (errList == null) {
8473 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8474 }
8475 errList.add(report);
8476 } else {
8477 Log.w(TAG, "Missing app error report, app = " + app.processName +
8478 " crashing = " + app.crashing +
8479 " notResponding = " + app.notResponding);
8480 }
8481 }
8482 }
8483 }
8484
8485 return errList;
8486 }
8487
8488 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8489 // Lazy instantiation of list
8490 List<ActivityManager.RunningAppProcessInfo> runList = null;
8491 synchronized (this) {
8492 // Iterate across all processes
8493 final int N = mLRUProcesses.size();
8494 for (int i = 0; i < N; i++) {
8495 ProcessRecord app = mLRUProcesses.get(i);
8496 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8497 // Generate process state info for running application
8498 ActivityManager.RunningAppProcessInfo currApp =
8499 new ActivityManager.RunningAppProcessInfo(app.processName,
8500 app.pid, app.getPackageList());
8501 int adj = app.curAdj;
8502 if (adj >= CONTENT_PROVIDER_ADJ) {
8503 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8504 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8505 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008506 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8507 } else if (adj >= HOME_APP_ADJ) {
8508 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8509 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008510 } else if (adj >= SECONDARY_SERVER_ADJ) {
8511 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8512 } else if (adj >= VISIBLE_APP_ADJ) {
8513 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8514 } else {
8515 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8516 }
8517 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8518 // + " lru=" + currApp.lru);
8519 if (runList == null) {
8520 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8521 }
8522 runList.add(currApp);
8523 }
8524 }
8525 }
8526 return runList;
8527 }
8528
8529 @Override
8530 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8531 synchronized (this) {
8532 if (checkCallingPermission(android.Manifest.permission.DUMP)
8533 != PackageManager.PERMISSION_GRANTED) {
8534 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8535 + Binder.getCallingPid()
8536 + ", uid=" + Binder.getCallingUid()
8537 + " without permission "
8538 + android.Manifest.permission.DUMP);
8539 return;
8540 }
8541 if (args.length != 0 && "service".equals(args[0])) {
8542 dumpService(fd, pw, args);
8543 return;
8544 }
8545 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008546 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008547 pw.println(" ");
8548 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008549 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008550 if (mWaitingVisibleActivities.size() > 0) {
8551 pw.println(" ");
8552 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008553 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008554 }
8555 if (mStoppingActivities.size() > 0) {
8556 pw.println(" ");
8557 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008558 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008559 }
8560 if (mFinishingActivities.size() > 0) {
8561 pw.println(" ");
8562 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008563 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008564 }
8565
8566 pw.println(" ");
8567 pw.println(" mPausingActivity: " + mPausingActivity);
8568 pw.println(" mResumedActivity: " + mResumedActivity);
8569 pw.println(" mFocusedActivity: " + mFocusedActivity);
8570 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8571
8572 if (mRecentTasks.size() > 0) {
8573 pw.println(" ");
8574 pw.println("Recent tasks in Current Activity Manager State:");
8575
8576 final int N = mRecentTasks.size();
8577 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008578 TaskRecord tr = mRecentTasks.get(i);
8579 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8580 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008581 mRecentTasks.get(i).dump(pw, " ");
8582 }
8583 }
8584
8585 pw.println(" ");
8586 pw.println(" mCurTask: " + mCurTask);
8587
8588 pw.println(" ");
8589 pw.println("Processes in Current Activity Manager State:");
8590
8591 boolean needSep = false;
8592 int numPers = 0;
8593
8594 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8595 final int NA = procs.size();
8596 for (int ia=0; ia<NA; ia++) {
8597 if (!needSep) {
8598 pw.println(" All known processes:");
8599 needSep = true;
8600 }
8601 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008602 pw.print(r.persistent ? " *PERS*" : " *APP*");
8603 pw.print(" UID "); pw.print(procs.keyAt(ia));
8604 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605 r.dump(pw, " ");
8606 if (r.persistent) {
8607 numPers++;
8608 }
8609 }
8610 }
8611
8612 if (mLRUProcesses.size() > 0) {
8613 if (needSep) pw.println(" ");
8614 needSep = true;
8615 pw.println(" Running processes (most recent first):");
8616 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008617 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008618 needSep = true;
8619 }
8620
8621 synchronized (mPidsSelfLocked) {
8622 if (mPidsSelfLocked.size() > 0) {
8623 if (needSep) pw.println(" ");
8624 needSep = true;
8625 pw.println(" PID mappings:");
8626 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008627 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8628 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008629 }
8630 }
8631 }
8632
8633 if (mForegroundProcesses.size() > 0) {
8634 if (needSep) pw.println(" ");
8635 needSep = true;
8636 pw.println(" Foreground Processes:");
8637 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008638 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8639 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008640 }
8641 }
8642
8643 if (mPersistentStartingProcesses.size() > 0) {
8644 if (needSep) pw.println(" ");
8645 needSep = true;
8646 pw.println(" Persisent processes that are starting:");
8647 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008648 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008649 }
8650
8651 if (mStartingProcesses.size() > 0) {
8652 if (needSep) pw.println(" ");
8653 needSep = true;
8654 pw.println(" Processes that are starting:");
8655 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008656 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008657 }
8658
8659 if (mRemovedProcesses.size() > 0) {
8660 if (needSep) pw.println(" ");
8661 needSep = true;
8662 pw.println(" Processes that are being removed:");
8663 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008664 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008665 }
8666
8667 if (mProcessesOnHold.size() > 0) {
8668 if (needSep) pw.println(" ");
8669 needSep = true;
8670 pw.println(" Processes that are on old until the system is ready:");
8671 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008672 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 }
8674
8675 if (mProcessCrashTimes.getMap().size() > 0) {
8676 if (needSep) pw.println(" ");
8677 needSep = true;
8678 pw.println(" Time since processes crashed:");
8679 long now = SystemClock.uptimeMillis();
8680 for (Map.Entry<String, SparseArray<Long>> procs
8681 : mProcessCrashTimes.getMap().entrySet()) {
8682 SparseArray<Long> uids = procs.getValue();
8683 final int N = uids.size();
8684 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008685 pw.print(" Process "); pw.print(procs.getKey());
8686 pw.print(" uid "); pw.print(uids.keyAt(i));
8687 pw.print(": last crashed ");
8688 pw.print((now-uids.valueAt(i)));
8689 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008690 }
8691 }
8692 }
8693
8694 if (mBadProcesses.getMap().size() > 0) {
8695 if (needSep) pw.println(" ");
8696 needSep = true;
8697 pw.println(" Bad processes:");
8698 for (Map.Entry<String, SparseArray<Long>> procs
8699 : mBadProcesses.getMap().entrySet()) {
8700 SparseArray<Long> uids = procs.getValue();
8701 final int N = uids.size();
8702 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008703 pw.print(" Bad process "); pw.print(procs.getKey());
8704 pw.print(" uid "); pw.print(uids.keyAt(i));
8705 pw.print(": crashed at time ");
8706 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008707 }
8708 }
8709 }
8710
8711 pw.println(" ");
8712 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008713 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 pw.println(" mConfiguration: " + mConfiguration);
8715 pw.println(" mStartRunning=" + mStartRunning
8716 + " mSystemReady=" + mSystemReady
8717 + " mBooting=" + mBooting
8718 + " mBooted=" + mBooted
8719 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008720 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008721 pw.println(" mGoingToSleep=" + mGoingToSleep);
8722 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8723 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8724 + " mDebugTransient=" + mDebugTransient
8725 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8726 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008727 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 }
8729 }
8730
8731 /**
8732 * There are three ways to call this:
8733 * - no service specified: dump all the services
8734 * - a flattened component name that matched an existing service was specified as the
8735 * first arg: dump that one service
8736 * - the first arg isn't the flattened component name of an existing service:
8737 * dump all services whose component contains the first arg as a substring
8738 */
8739 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8740 String[] newArgs;
8741 String componentNameString;
8742 ServiceRecord r;
8743 if (args.length == 1) {
8744 componentNameString = null;
8745 newArgs = EMPTY_STRING_ARRAY;
8746 r = null;
8747 } else {
8748 componentNameString = args[1];
8749 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8750 r = componentName != null ? mServices.get(componentName) : null;
8751 newArgs = new String[args.length - 2];
8752 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8753 }
8754
8755 if (r != null) {
8756 dumpService(fd, pw, r, newArgs);
8757 } else {
8758 for (ServiceRecord r1 : mServices.values()) {
8759 if (componentNameString == null
8760 || r1.name.flattenToString().contains(componentNameString)) {
8761 dumpService(fd, pw, r1, newArgs);
8762 }
8763 }
8764 }
8765 }
8766
8767 /**
8768 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8769 * there is a thread associated with the service.
8770 */
8771 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8772 pw.println(" Service " + r.name.flattenToString());
8773 if (r.app != null && r.app.thread != null) {
8774 try {
8775 // flush anything that is already in the PrintWriter since the thread is going
8776 // to write to the file descriptor directly
8777 pw.flush();
8778 r.app.thread.dumpService(fd, r, args);
8779 pw.print("\n");
8780 } catch (RemoteException e) {
8781 pw.println("got a RemoteException while dumping the service");
8782 }
8783 }
8784 }
8785
8786 void dumpBroadcasts(PrintWriter pw) {
8787 synchronized (this) {
8788 if (checkCallingPermission(android.Manifest.permission.DUMP)
8789 != PackageManager.PERMISSION_GRANTED) {
8790 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8791 + Binder.getCallingPid()
8792 + ", uid=" + Binder.getCallingUid()
8793 + " without permission "
8794 + android.Manifest.permission.DUMP);
8795 return;
8796 }
8797 pw.println("Broadcasts in Current Activity Manager State:");
8798
8799 if (mRegisteredReceivers.size() > 0) {
8800 pw.println(" ");
8801 pw.println(" Registered Receivers:");
8802 Iterator it = mRegisteredReceivers.values().iterator();
8803 while (it.hasNext()) {
8804 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008805 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008806 r.dump(pw, " ");
8807 }
8808 }
8809
8810 pw.println(" ");
8811 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008812 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008813
8814 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8815 || mPendingBroadcast != null) {
8816 if (mParallelBroadcasts.size() > 0) {
8817 pw.println(" ");
8818 pw.println(" Active broadcasts:");
8819 }
8820 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8821 pw.println(" Broadcast #" + i + ":");
8822 mParallelBroadcasts.get(i).dump(pw, " ");
8823 }
8824 if (mOrderedBroadcasts.size() > 0) {
8825 pw.println(" ");
8826 pw.println(" Active serialized broadcasts:");
8827 }
8828 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8829 pw.println(" Serialized Broadcast #" + i + ":");
8830 mOrderedBroadcasts.get(i).dump(pw, " ");
8831 }
8832 pw.println(" ");
8833 pw.println(" Pending broadcast:");
8834 if (mPendingBroadcast != null) {
8835 mPendingBroadcast.dump(pw, " ");
8836 } else {
8837 pw.println(" (null)");
8838 }
8839 }
8840
8841 pw.println(" ");
8842 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8843 if (mStickyBroadcasts != null) {
8844 pw.println(" ");
8845 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008846 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008847 for (Map.Entry<String, ArrayList<Intent>> ent
8848 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008849 pw.print(" * Sticky action "); pw.print(ent.getKey());
8850 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008851 ArrayList<Intent> intents = ent.getValue();
8852 final int N = intents.size();
8853 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008854 sb.setLength(0);
8855 sb.append(" Intent: ");
8856 intents.get(i).toShortString(sb, true, false);
8857 pw.println(sb.toString());
8858 Bundle bundle = intents.get(i).getExtras();
8859 if (bundle != null) {
8860 pw.print(" ");
8861 pw.println(bundle.toString());
8862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008863 }
8864 }
8865 }
8866
8867 pw.println(" ");
8868 pw.println(" mHandler:");
8869 mHandler.dump(new PrintWriterPrinter(pw), " ");
8870 }
8871 }
8872
8873 void dumpServices(PrintWriter pw) {
8874 synchronized (this) {
8875 if (checkCallingPermission(android.Manifest.permission.DUMP)
8876 != PackageManager.PERMISSION_GRANTED) {
8877 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8878 + Binder.getCallingPid()
8879 + ", uid=" + Binder.getCallingUid()
8880 + " without permission "
8881 + android.Manifest.permission.DUMP);
8882 return;
8883 }
8884 pw.println("Services in Current Activity Manager State:");
8885
8886 boolean needSep = false;
8887
8888 if (mServices.size() > 0) {
8889 pw.println(" Active services:");
8890 Iterator<ServiceRecord> it = mServices.values().iterator();
8891 while (it.hasNext()) {
8892 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008893 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008894 r.dump(pw, " ");
8895 }
8896 needSep = true;
8897 }
8898
8899 if (mPendingServices.size() > 0) {
8900 if (needSep) pw.println(" ");
8901 pw.println(" Pending services:");
8902 for (int i=0; i<mPendingServices.size(); i++) {
8903 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008904 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008905 r.dump(pw, " ");
8906 }
8907 needSep = true;
8908 }
8909
8910 if (mRestartingServices.size() > 0) {
8911 if (needSep) pw.println(" ");
8912 pw.println(" Restarting services:");
8913 for (int i=0; i<mRestartingServices.size(); i++) {
8914 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008915 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008916 r.dump(pw, " ");
8917 }
8918 needSep = true;
8919 }
8920
8921 if (mStoppingServices.size() > 0) {
8922 if (needSep) pw.println(" ");
8923 pw.println(" Stopping services:");
8924 for (int i=0; i<mStoppingServices.size(); i++) {
8925 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008926 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 r.dump(pw, " ");
8928 }
8929 needSep = true;
8930 }
8931
8932 if (mServiceConnections.size() > 0) {
8933 if (needSep) pw.println(" ");
8934 pw.println(" Connection bindings to services:");
8935 Iterator<ConnectionRecord> it
8936 = mServiceConnections.values().iterator();
8937 while (it.hasNext()) {
8938 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008939 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 r.dump(pw, " ");
8941 }
8942 }
8943 }
8944 }
8945
8946 void dumpProviders(PrintWriter pw) {
8947 synchronized (this) {
8948 if (checkCallingPermission(android.Manifest.permission.DUMP)
8949 != PackageManager.PERMISSION_GRANTED) {
8950 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8951 + Binder.getCallingPid()
8952 + ", uid=" + Binder.getCallingUid()
8953 + " without permission "
8954 + android.Manifest.permission.DUMP);
8955 return;
8956 }
8957
8958 pw.println("Content Providers in Current Activity Manager State:");
8959
8960 boolean needSep = false;
8961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008962 if (mProvidersByClass.size() > 0) {
8963 if (needSep) pw.println(" ");
8964 pw.println(" Published content providers (by class):");
8965 Iterator it = mProvidersByClass.entrySet().iterator();
8966 while (it.hasNext()) {
8967 Map.Entry e = (Map.Entry)it.next();
8968 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008969 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 r.dump(pw, " ");
8971 }
8972 needSep = true;
8973 }
8974
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008975 if (mProvidersByName.size() > 0) {
8976 pw.println(" ");
8977 pw.println(" Authority to provider mappings:");
8978 Iterator it = mProvidersByName.entrySet().iterator();
8979 while (it.hasNext()) {
8980 Map.Entry e = (Map.Entry)it.next();
8981 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8982 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8983 pw.println(r);
8984 }
8985 needSep = true;
8986 }
8987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 if (mLaunchingProviders.size() > 0) {
8989 if (needSep) pw.println(" ");
8990 pw.println(" Launching content providers:");
8991 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008992 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8993 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008994 }
8995 needSep = true;
8996 }
8997
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008998 if (mGrantedUriPermissions.size() > 0) {
8999 pw.println();
9000 pw.println("Granted Uri Permissions:");
9001 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9002 int uid = mGrantedUriPermissions.keyAt(i);
9003 HashMap<Uri, UriPermission> perms
9004 = mGrantedUriPermissions.valueAt(i);
9005 pw.print(" * UID "); pw.print(uid);
9006 pw.println(" holds:");
9007 for (UriPermission perm : perms.values()) {
9008 pw.print(" "); pw.println(perm);
9009 perm.dump(pw, " ");
9010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009011 }
9012 }
9013 }
9014 }
9015
9016 void dumpSenders(PrintWriter pw) {
9017 synchronized (this) {
9018 if (checkCallingPermission(android.Manifest.permission.DUMP)
9019 != PackageManager.PERMISSION_GRANTED) {
9020 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9021 + Binder.getCallingPid()
9022 + ", uid=" + Binder.getCallingUid()
9023 + " without permission "
9024 + android.Manifest.permission.DUMP);
9025 return;
9026 }
9027
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009028 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009029
9030 if (this.mIntentSenderRecords.size() > 0) {
9031 Iterator<WeakReference<PendingIntentRecord>> it
9032 = mIntentSenderRecords.values().iterator();
9033 while (it.hasNext()) {
9034 WeakReference<PendingIntentRecord> ref = it.next();
9035 PendingIntentRecord rec = ref != null ? ref.get(): null;
9036 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009037 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009038 rec.dump(pw, " ");
9039 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009040 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009041 }
9042 }
9043 }
9044 }
9045 }
9046
9047 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009048 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 TaskRecord lastTask = null;
9050 for (int i=list.size()-1; i>=0; i--) {
9051 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009052 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009053 if (lastTask != r.task) {
9054 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009055 pw.print(prefix);
9056 pw.print(full ? "* " : " ");
9057 pw.println(lastTask);
9058 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009059 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9063 pw.print(" #"); pw.print(i); pw.print(": ");
9064 pw.println(r);
9065 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009066 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 }
9069 }
9070
9071 private static final int dumpProcessList(PrintWriter pw, List list,
9072 String prefix, String normalLabel, String persistentLabel,
9073 boolean inclOomAdj) {
9074 int numPers = 0;
9075 for (int i=list.size()-1; i>=0; i--) {
9076 ProcessRecord r = (ProcessRecord)list.get(i);
9077 if (false) {
9078 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9079 + " #" + i + ":");
9080 r.dump(pw, prefix + " ");
9081 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009082 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009083 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009084 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 } else {
9086 pw.println(String.format("%s%s #%2d: %s",
9087 prefix, (r.persistent ? persistentLabel : normalLabel),
9088 i, r.toString()));
9089 }
9090 if (r.persistent) {
9091 numPers++;
9092 }
9093 }
9094 return numPers;
9095 }
9096
9097 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9098 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009099 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009100 long uptime = SystemClock.uptimeMillis();
9101 long realtime = SystemClock.elapsedRealtime();
9102
9103 if (isCheckinRequest) {
9104 // short checkin version
9105 pw.println(uptime + "," + realtime);
9106 pw.flush();
9107 } else {
9108 pw.println("Applications Memory Usage (kB):");
9109 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9110 }
9111 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9112 ProcessRecord r = (ProcessRecord)list.get(i);
9113 if (r.thread != null) {
9114 if (!isCheckinRequest) {
9115 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9116 pw.flush();
9117 }
9118 try {
9119 r.thread.asBinder().dump(fd, args);
9120 } catch (RemoteException e) {
9121 if (!isCheckinRequest) {
9122 pw.println("Got RemoteException!");
9123 pw.flush();
9124 }
9125 }
9126 }
9127 }
9128 }
9129
9130 /**
9131 * Searches array of arguments for the specified string
9132 * @param args array of argument strings
9133 * @param value value to search for
9134 * @return true if the value is contained in the array
9135 */
9136 private static boolean scanArgs(String[] args, String value) {
9137 if (args != null) {
9138 for (String arg : args) {
9139 if (value.equals(arg)) {
9140 return true;
9141 }
9142 }
9143 }
9144 return false;
9145 }
9146
Dianne Hackborn75b03852009-06-12 15:43:26 -07009147 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009148 int count = mHistory.size();
9149
9150 // convert the token to an entry in the history.
9151 HistoryRecord r = null;
9152 int index = -1;
9153 for (int i=count-1; i>=0; i--) {
9154 Object o = mHistory.get(i);
9155 if (o == token) {
9156 r = (HistoryRecord)o;
9157 index = i;
9158 break;
9159 }
9160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009161
9162 return index;
9163 }
9164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009165 private final void killServicesLocked(ProcessRecord app,
9166 boolean allowRestart) {
9167 // Report disconnected services.
9168 if (false) {
9169 // XXX we are letting the client link to the service for
9170 // death notifications.
9171 if (app.services.size() > 0) {
9172 Iterator it = app.services.iterator();
9173 while (it.hasNext()) {
9174 ServiceRecord r = (ServiceRecord)it.next();
9175 if (r.connections.size() > 0) {
9176 Iterator<ConnectionRecord> jt
9177 = r.connections.values().iterator();
9178 while (jt.hasNext()) {
9179 ConnectionRecord c = jt.next();
9180 if (c.binding.client != app) {
9181 try {
9182 //c.conn.connected(r.className, null);
9183 } catch (Exception e) {
9184 // todo: this should be asynchronous!
9185 Log.w(TAG, "Exception thrown disconnected servce "
9186 + r.shortName
9187 + " from app " + app.processName, e);
9188 }
9189 }
9190 }
9191 }
9192 }
9193 }
9194 }
9195
9196 // Clean up any connections this application has to other services.
9197 if (app.connections.size() > 0) {
9198 Iterator<ConnectionRecord> it = app.connections.iterator();
9199 while (it.hasNext()) {
9200 ConnectionRecord r = it.next();
9201 removeConnectionLocked(r, app, null);
9202 }
9203 }
9204 app.connections.clear();
9205
9206 if (app.services.size() != 0) {
9207 // Any services running in the application need to be placed
9208 // back in the pending list.
9209 Iterator it = app.services.iterator();
9210 while (it.hasNext()) {
9211 ServiceRecord sr = (ServiceRecord)it.next();
9212 synchronized (sr.stats.getBatteryStats()) {
9213 sr.stats.stopLaunchedLocked();
9214 }
9215 sr.app = null;
9216 sr.executeNesting = 0;
9217 mStoppingServices.remove(sr);
9218 if (sr.bindings.size() > 0) {
9219 Iterator<IntentBindRecord> bindings
9220 = sr.bindings.values().iterator();
9221 while (bindings.hasNext()) {
9222 IntentBindRecord b = bindings.next();
9223 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9224 + ": shouldUnbind=" + b.hasBound);
9225 b.binder = null;
9226 b.requested = b.received = b.hasBound = false;
9227 }
9228 }
9229
9230 if (sr.crashCount >= 2) {
9231 Log.w(TAG, "Service crashed " + sr.crashCount
9232 + " times, stopping: " + sr);
9233 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9234 sr.crashCount, sr.shortName, app.pid);
9235 bringDownServiceLocked(sr, true);
9236 } else if (!allowRestart) {
9237 bringDownServiceLocked(sr, true);
9238 } else {
9239 scheduleServiceRestartLocked(sr);
9240 }
9241 }
9242
9243 if (!allowRestart) {
9244 app.services.clear();
9245 }
9246 }
9247
9248 app.executingServices.clear();
9249 }
9250
9251 private final void removeDyingProviderLocked(ProcessRecord proc,
9252 ContentProviderRecord cpr) {
9253 synchronized (cpr) {
9254 cpr.launchingApp = null;
9255 cpr.notifyAll();
9256 }
9257
9258 mProvidersByClass.remove(cpr.info.name);
9259 String names[] = cpr.info.authority.split(";");
9260 for (int j = 0; j < names.length; j++) {
9261 mProvidersByName.remove(names[j]);
9262 }
9263
9264 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9265 while (cit.hasNext()) {
9266 ProcessRecord capp = cit.next();
9267 if (!capp.persistent && capp.thread != null
9268 && capp.pid != 0
9269 && capp.pid != MY_PID) {
9270 Log.i(TAG, "Killing app " + capp.processName
9271 + " (pid " + capp.pid
9272 + ") because provider " + cpr.info.name
9273 + " is in dying process " + proc.processName);
9274 Process.killProcess(capp.pid);
9275 }
9276 }
9277
9278 mLaunchingProviders.remove(cpr);
9279 }
9280
9281 /**
9282 * Main code for cleaning up a process when it has gone away. This is
9283 * called both as a result of the process dying, or directly when stopping
9284 * a process when running in single process mode.
9285 */
9286 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9287 boolean restarting, int index) {
9288 if (index >= 0) {
9289 mLRUProcesses.remove(index);
9290 }
9291
9292 // Dismiss any open dialogs.
9293 if (app.crashDialog != null) {
9294 app.crashDialog.dismiss();
9295 app.crashDialog = null;
9296 }
9297 if (app.anrDialog != null) {
9298 app.anrDialog.dismiss();
9299 app.anrDialog = null;
9300 }
9301 if (app.waitDialog != null) {
9302 app.waitDialog.dismiss();
9303 app.waitDialog = null;
9304 }
9305
9306 app.crashing = false;
9307 app.notResponding = false;
9308
9309 app.resetPackageList();
9310 app.thread = null;
9311 app.forcingToForeground = null;
9312 app.foregroundServices = false;
9313
9314 killServicesLocked(app, true);
9315
9316 boolean restart = false;
9317
9318 int NL = mLaunchingProviders.size();
9319
9320 // Remove published content providers.
9321 if (!app.pubProviders.isEmpty()) {
9322 Iterator it = app.pubProviders.values().iterator();
9323 while (it.hasNext()) {
9324 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9325 cpr.provider = null;
9326 cpr.app = null;
9327
9328 // See if someone is waiting for this provider... in which
9329 // case we don't remove it, but just let it restart.
9330 int i = 0;
9331 if (!app.bad) {
9332 for (; i<NL; i++) {
9333 if (mLaunchingProviders.get(i) == cpr) {
9334 restart = true;
9335 break;
9336 }
9337 }
9338 } else {
9339 i = NL;
9340 }
9341
9342 if (i >= NL) {
9343 removeDyingProviderLocked(app, cpr);
9344 NL = mLaunchingProviders.size();
9345 }
9346 }
9347 app.pubProviders.clear();
9348 }
9349
9350 // Look through the content providers we are waiting to have launched,
9351 // and if any run in this process then either schedule a restart of
9352 // the process or kill the client waiting for it if this process has
9353 // gone bad.
9354 for (int i=0; i<NL; i++) {
9355 ContentProviderRecord cpr = (ContentProviderRecord)
9356 mLaunchingProviders.get(i);
9357 if (cpr.launchingApp == app) {
9358 if (!app.bad) {
9359 restart = true;
9360 } else {
9361 removeDyingProviderLocked(app, cpr);
9362 NL = mLaunchingProviders.size();
9363 }
9364 }
9365 }
9366
9367 // Unregister from connected content providers.
9368 if (!app.conProviders.isEmpty()) {
9369 Iterator it = app.conProviders.iterator();
9370 while (it.hasNext()) {
9371 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9372 cpr.clients.remove(app);
9373 }
9374 app.conProviders.clear();
9375 }
9376
9377 skipCurrentReceiverLocked(app);
9378
9379 // Unregister any receivers.
9380 if (app.receivers.size() > 0) {
9381 Iterator<ReceiverList> it = app.receivers.iterator();
9382 while (it.hasNext()) {
9383 removeReceiverLocked(it.next());
9384 }
9385 app.receivers.clear();
9386 }
9387
Christopher Tate181fafa2009-05-14 11:12:14 -07009388 // If the app is undergoing backup, tell the backup manager about it
9389 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9390 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9391 try {
9392 IBackupManager bm = IBackupManager.Stub.asInterface(
9393 ServiceManager.getService(Context.BACKUP_SERVICE));
9394 bm.agentDisconnected(app.info.packageName);
9395 } catch (RemoteException e) {
9396 // can't happen; backup manager is local
9397 }
9398 }
9399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009400 // If the caller is restarting this app, then leave it in its
9401 // current lists and let the caller take care of it.
9402 if (restarting) {
9403 return;
9404 }
9405
9406 if (!app.persistent) {
9407 if (DEBUG_PROCESSES) Log.v(TAG,
9408 "Removing non-persistent process during cleanup: " + app);
9409 mProcessNames.remove(app.processName, app.info.uid);
9410 } else if (!app.removed) {
9411 // This app is persistent, so we need to keep its record around.
9412 // If it is not already on the pending app list, add it there
9413 // and start a new process for it.
9414 app.thread = null;
9415 app.forcingToForeground = null;
9416 app.foregroundServices = false;
9417 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9418 mPersistentStartingProcesses.add(app);
9419 restart = true;
9420 }
9421 }
9422 mProcessesOnHold.remove(app);
9423
The Android Open Source Project4df24232009-03-05 14:34:35 -08009424 if (app == mHomeProcess) {
9425 mHomeProcess = null;
9426 }
9427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009428 if (restart) {
9429 // We have components that still need to be running in the
9430 // process, so re-launch it.
9431 mProcessNames.put(app.processName, app.info.uid, app);
9432 startProcessLocked(app, "restart", app.processName);
9433 } else if (app.pid > 0 && app.pid != MY_PID) {
9434 // Goodbye!
9435 synchronized (mPidsSelfLocked) {
9436 mPidsSelfLocked.remove(app.pid);
9437 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9438 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009439 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009440 }
9441 }
9442
9443 // =========================================================
9444 // SERVICES
9445 // =========================================================
9446
9447 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9448 ActivityManager.RunningServiceInfo info =
9449 new ActivityManager.RunningServiceInfo();
9450 info.service = r.name;
9451 if (r.app != null) {
9452 info.pid = r.app.pid;
9453 }
9454 info.process = r.processName;
9455 info.foreground = r.isForeground;
9456 info.activeSince = r.createTime;
9457 info.started = r.startRequested;
9458 info.clientCount = r.connections.size();
9459 info.crashCount = r.crashCount;
9460 info.lastActivityTime = r.lastActivity;
9461 return info;
9462 }
9463
9464 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9465 int flags) {
9466 synchronized (this) {
9467 ArrayList<ActivityManager.RunningServiceInfo> res
9468 = new ArrayList<ActivityManager.RunningServiceInfo>();
9469
9470 if (mServices.size() > 0) {
9471 Iterator<ServiceRecord> it = mServices.values().iterator();
9472 while (it.hasNext() && res.size() < maxNum) {
9473 res.add(makeRunningServiceInfoLocked(it.next()));
9474 }
9475 }
9476
9477 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9478 ServiceRecord r = mRestartingServices.get(i);
9479 ActivityManager.RunningServiceInfo info =
9480 makeRunningServiceInfoLocked(r);
9481 info.restarting = r.nextRestartTime;
9482 res.add(info);
9483 }
9484
9485 return res;
9486 }
9487 }
9488
9489 private final ServiceRecord findServiceLocked(ComponentName name,
9490 IBinder token) {
9491 ServiceRecord r = mServices.get(name);
9492 return r == token ? r : null;
9493 }
9494
9495 private final class ServiceLookupResult {
9496 final ServiceRecord record;
9497 final String permission;
9498
9499 ServiceLookupResult(ServiceRecord _record, String _permission) {
9500 record = _record;
9501 permission = _permission;
9502 }
9503 };
9504
9505 private ServiceLookupResult findServiceLocked(Intent service,
9506 String resolvedType) {
9507 ServiceRecord r = null;
9508 if (service.getComponent() != null) {
9509 r = mServices.get(service.getComponent());
9510 }
9511 if (r == null) {
9512 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9513 r = mServicesByIntent.get(filter);
9514 }
9515
9516 if (r == null) {
9517 try {
9518 ResolveInfo rInfo =
9519 ActivityThread.getPackageManager().resolveService(
9520 service, resolvedType, 0);
9521 ServiceInfo sInfo =
9522 rInfo != null ? rInfo.serviceInfo : null;
9523 if (sInfo == null) {
9524 return null;
9525 }
9526
9527 ComponentName name = new ComponentName(
9528 sInfo.applicationInfo.packageName, sInfo.name);
9529 r = mServices.get(name);
9530 } catch (RemoteException ex) {
9531 // pm is in same process, this will never happen.
9532 }
9533 }
9534 if (r != null) {
9535 int callingPid = Binder.getCallingPid();
9536 int callingUid = Binder.getCallingUid();
9537 if (checkComponentPermission(r.permission,
9538 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9539 != PackageManager.PERMISSION_GRANTED) {
9540 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9541 + " from pid=" + callingPid
9542 + ", uid=" + callingUid
9543 + " requires " + r.permission);
9544 return new ServiceLookupResult(null, r.permission);
9545 }
9546 return new ServiceLookupResult(r, null);
9547 }
9548 return null;
9549 }
9550
9551 private class ServiceRestarter implements Runnable {
9552 private ServiceRecord mService;
9553
9554 void setService(ServiceRecord service) {
9555 mService = service;
9556 }
9557
9558 public void run() {
9559 synchronized(ActivityManagerService.this) {
9560 performServiceRestartLocked(mService);
9561 }
9562 }
9563 }
9564
9565 private ServiceLookupResult retrieveServiceLocked(Intent service,
9566 String resolvedType, int callingPid, int callingUid) {
9567 ServiceRecord r = null;
9568 if (service.getComponent() != null) {
9569 r = mServices.get(service.getComponent());
9570 }
9571 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9572 r = mServicesByIntent.get(filter);
9573 if (r == null) {
9574 try {
9575 ResolveInfo rInfo =
9576 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009577 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009578 ServiceInfo sInfo =
9579 rInfo != null ? rInfo.serviceInfo : null;
9580 if (sInfo == null) {
9581 Log.w(TAG, "Unable to start service " + service +
9582 ": not found");
9583 return null;
9584 }
9585
9586 ComponentName name = new ComponentName(
9587 sInfo.applicationInfo.packageName, sInfo.name);
9588 r = mServices.get(name);
9589 if (r == null) {
9590 filter = new Intent.FilterComparison(service.cloneFilter());
9591 ServiceRestarter res = new ServiceRestarter();
9592 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9593 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9594 synchronized (stats) {
9595 ss = stats.getServiceStatsLocked(
9596 sInfo.applicationInfo.uid, sInfo.packageName,
9597 sInfo.name);
9598 }
9599 r = new ServiceRecord(ss, name, filter, sInfo, res);
9600 res.setService(r);
9601 mServices.put(name, r);
9602 mServicesByIntent.put(filter, r);
9603
9604 // Make sure this component isn't in the pending list.
9605 int N = mPendingServices.size();
9606 for (int i=0; i<N; i++) {
9607 ServiceRecord pr = mPendingServices.get(i);
9608 if (pr.name.equals(name)) {
9609 mPendingServices.remove(i);
9610 i--;
9611 N--;
9612 }
9613 }
9614 }
9615 } catch (RemoteException ex) {
9616 // pm is in same process, this will never happen.
9617 }
9618 }
9619 if (r != null) {
9620 if (checkComponentPermission(r.permission,
9621 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9622 != PackageManager.PERMISSION_GRANTED) {
9623 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9624 + " from pid=" + Binder.getCallingPid()
9625 + ", uid=" + Binder.getCallingUid()
9626 + " requires " + r.permission);
9627 return new ServiceLookupResult(null, r.permission);
9628 }
9629 return new ServiceLookupResult(r, null);
9630 }
9631 return null;
9632 }
9633
9634 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9635 long now = SystemClock.uptimeMillis();
9636 if (r.executeNesting == 0 && r.app != null) {
9637 if (r.app.executingServices.size() == 0) {
9638 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9639 msg.obj = r.app;
9640 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9641 }
9642 r.app.executingServices.add(r);
9643 }
9644 r.executeNesting++;
9645 r.executingStart = now;
9646 }
9647
9648 private final void sendServiceArgsLocked(ServiceRecord r,
9649 boolean oomAdjusted) {
9650 final int N = r.startArgs.size();
9651 if (N == 0) {
9652 return;
9653 }
9654
9655 final int BASEID = r.lastStartId - N + 1;
9656 int i = 0;
9657 while (i < N) {
9658 try {
9659 Intent args = r.startArgs.get(i);
9660 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9661 + r.name + " " + r.intent + " args=" + args);
9662 bumpServiceExecutingLocked(r);
9663 if (!oomAdjusted) {
9664 oomAdjusted = true;
9665 updateOomAdjLocked(r.app);
9666 }
9667 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9668 i++;
9669 } catch (Exception e) {
9670 break;
9671 }
9672 }
9673 if (i == N) {
9674 r.startArgs.clear();
9675 } else {
9676 while (i > 0) {
9677 r.startArgs.remove(0);
9678 i--;
9679 }
9680 }
9681 }
9682
9683 private final boolean requestServiceBindingLocked(ServiceRecord r,
9684 IntentBindRecord i, boolean rebind) {
9685 if (r.app == null || r.app.thread == null) {
9686 // If service is not currently running, can't yet bind.
9687 return false;
9688 }
9689 if ((!i.requested || rebind) && i.apps.size() > 0) {
9690 try {
9691 bumpServiceExecutingLocked(r);
9692 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9693 + ": shouldUnbind=" + i.hasBound);
9694 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9695 if (!rebind) {
9696 i.requested = true;
9697 }
9698 i.hasBound = true;
9699 i.doRebind = false;
9700 } catch (RemoteException e) {
9701 return false;
9702 }
9703 }
9704 return true;
9705 }
9706
9707 private final void requestServiceBindingsLocked(ServiceRecord r) {
9708 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9709 while (bindings.hasNext()) {
9710 IntentBindRecord i = bindings.next();
9711 if (!requestServiceBindingLocked(r, i, false)) {
9712 break;
9713 }
9714 }
9715 }
9716
9717 private final void realStartServiceLocked(ServiceRecord r,
9718 ProcessRecord app) throws RemoteException {
9719 if (app.thread == null) {
9720 throw new RemoteException();
9721 }
9722
9723 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009724 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009725
9726 app.services.add(r);
9727 bumpServiceExecutingLocked(r);
9728 updateLRUListLocked(app, true);
9729
9730 boolean created = false;
9731 try {
9732 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9733 + r.name + " " + r.intent);
9734 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9735 System.identityHashCode(r), r.shortName,
9736 r.intent.getIntent().toString(), r.app.pid);
9737 synchronized (r.stats.getBatteryStats()) {
9738 r.stats.startLaunchedLocked();
9739 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009740 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009741 app.thread.scheduleCreateService(r, r.serviceInfo);
9742 created = true;
9743 } finally {
9744 if (!created) {
9745 app.services.remove(r);
9746 scheduleServiceRestartLocked(r);
9747 }
9748 }
9749
9750 requestServiceBindingsLocked(r);
9751 sendServiceArgsLocked(r, true);
9752 }
9753
9754 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9755 r.totalRestartCount++;
9756 if (r.restartDelay == 0) {
9757 r.restartCount++;
9758 r.restartDelay = SERVICE_RESTART_DURATION;
9759 } else {
9760 // If it has been a "reasonably long time" since the service
9761 // was started, then reset our restart duration back to
9762 // the beginning, so we don't infinitely increase the duration
9763 // on a service that just occasionally gets killed (which is
9764 // a normal case, due to process being killed to reclaim memory).
9765 long now = SystemClock.uptimeMillis();
9766 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9767 r.restartCount = 1;
9768 r.restartDelay = SERVICE_RESTART_DURATION;
9769 } else {
9770 r.restartDelay *= 2;
9771 }
9772 }
9773 if (!mRestartingServices.contains(r)) {
9774 mRestartingServices.add(r);
9775 }
9776 mHandler.removeCallbacks(r.restarter);
9777 mHandler.postDelayed(r.restarter, r.restartDelay);
9778 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9779 Log.w(TAG, "Scheduling restart of crashed service "
9780 + r.shortName + " in " + r.restartDelay + "ms");
9781 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9782 r.shortName, r.restartDelay);
9783
9784 Message msg = Message.obtain();
9785 msg.what = SERVICE_ERROR_MSG;
9786 msg.obj = r;
9787 mHandler.sendMessage(msg);
9788 }
9789
9790 final void performServiceRestartLocked(ServiceRecord r) {
9791 if (!mRestartingServices.contains(r)) {
9792 return;
9793 }
9794 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9795 }
9796
9797 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9798 if (r.restartDelay == 0) {
9799 return false;
9800 }
9801 r.resetRestartCounter();
9802 mRestartingServices.remove(r);
9803 mHandler.removeCallbacks(r.restarter);
9804 return true;
9805 }
9806
9807 private final boolean bringUpServiceLocked(ServiceRecord r,
9808 int intentFlags, boolean whileRestarting) {
9809 //Log.i(TAG, "Bring up service:");
9810 //r.dump(" ");
9811
9812 if (r.app != null) {
9813 sendServiceArgsLocked(r, false);
9814 return true;
9815 }
9816
9817 if (!whileRestarting && r.restartDelay > 0) {
9818 // If waiting for a restart, then do nothing.
9819 return true;
9820 }
9821
9822 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9823 + " " + r.intent);
9824
9825 final String appName = r.processName;
9826 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9827 if (app != null && app.thread != null) {
9828 try {
9829 realStartServiceLocked(r, app);
9830 return true;
9831 } catch (RemoteException e) {
9832 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9833 }
9834
9835 // If a dead object exception was thrown -- fall through to
9836 // restart the application.
9837 }
9838
9839 if (!mPendingServices.contains(r)) {
9840 // Not running -- get it started, and enqueue this service record
9841 // to be executed when the app comes up.
9842 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9843 "service", r.name) == null) {
9844 Log.w(TAG, "Unable to launch app "
9845 + r.appInfo.packageName + "/"
9846 + r.appInfo.uid + " for service "
9847 + r.intent.getIntent() + ": process is bad");
9848 bringDownServiceLocked(r, true);
9849 return false;
9850 }
9851 mPendingServices.add(r);
9852 }
9853 return true;
9854 }
9855
9856 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9857 //Log.i(TAG, "Bring down service:");
9858 //r.dump(" ");
9859
9860 // Does it still need to run?
9861 if (!force && r.startRequested) {
9862 return;
9863 }
9864 if (r.connections.size() > 0) {
9865 if (!force) {
9866 // XXX should probably keep a count of the number of auto-create
9867 // connections directly in the service.
9868 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9869 while (it.hasNext()) {
9870 ConnectionRecord cr = it.next();
9871 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9872 return;
9873 }
9874 }
9875 }
9876
9877 // Report to all of the connections that the service is no longer
9878 // available.
9879 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9880 while (it.hasNext()) {
9881 ConnectionRecord c = it.next();
9882 try {
9883 // todo: shouldn't be a synchronous call!
9884 c.conn.connected(r.name, null);
9885 } catch (Exception e) {
9886 Log.w(TAG, "Failure disconnecting service " + r.name +
9887 " to connection " + c.conn.asBinder() +
9888 " (in " + c.binding.client.processName + ")", e);
9889 }
9890 }
9891 }
9892
9893 // Tell the service that it has been unbound.
9894 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9895 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9896 while (it.hasNext()) {
9897 IntentBindRecord ibr = it.next();
9898 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9899 + ": hasBound=" + ibr.hasBound);
9900 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9901 try {
9902 bumpServiceExecutingLocked(r);
9903 updateOomAdjLocked(r.app);
9904 ibr.hasBound = false;
9905 r.app.thread.scheduleUnbindService(r,
9906 ibr.intent.getIntent());
9907 } catch (Exception e) {
9908 Log.w(TAG, "Exception when unbinding service "
9909 + r.shortName, e);
9910 serviceDoneExecutingLocked(r, true);
9911 }
9912 }
9913 }
9914 }
9915
9916 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9917 + " " + r.intent);
9918 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9919 System.identityHashCode(r), r.shortName,
9920 (r.app != null) ? r.app.pid : -1);
9921
9922 mServices.remove(r.name);
9923 mServicesByIntent.remove(r.intent);
9924 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9925 r.totalRestartCount = 0;
9926 unscheduleServiceRestartLocked(r);
9927
9928 // Also make sure it is not on the pending list.
9929 int N = mPendingServices.size();
9930 for (int i=0; i<N; i++) {
9931 if (mPendingServices.get(i) == r) {
9932 mPendingServices.remove(i);
9933 if (DEBUG_SERVICE) Log.v(
9934 TAG, "Removed pending service: " + r.shortName);
9935 i--;
9936 N--;
9937 }
9938 }
9939
9940 if (r.app != null) {
9941 synchronized (r.stats.getBatteryStats()) {
9942 r.stats.stopLaunchedLocked();
9943 }
9944 r.app.services.remove(r);
9945 if (r.app.thread != null) {
9946 updateServiceForegroundLocked(r.app, false);
9947 try {
9948 Log.i(TAG, "Stopping service: " + r.shortName);
9949 bumpServiceExecutingLocked(r);
9950 mStoppingServices.add(r);
9951 updateOomAdjLocked(r.app);
9952 r.app.thread.scheduleStopService(r);
9953 } catch (Exception e) {
9954 Log.w(TAG, "Exception when stopping service "
9955 + r.shortName, e);
9956 serviceDoneExecutingLocked(r, true);
9957 }
9958 } else {
9959 if (DEBUG_SERVICE) Log.v(
9960 TAG, "Removed service that has no process: " + r.shortName);
9961 }
9962 } else {
9963 if (DEBUG_SERVICE) Log.v(
9964 TAG, "Removed service that is not running: " + r.shortName);
9965 }
9966 }
9967
9968 ComponentName startServiceLocked(IApplicationThread caller,
9969 Intent service, String resolvedType,
9970 int callingPid, int callingUid) {
9971 synchronized(this) {
9972 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9973 + " type=" + resolvedType + " args=" + service.getExtras());
9974
9975 if (caller != null) {
9976 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9977 if (callerApp == null) {
9978 throw new SecurityException(
9979 "Unable to find app for caller " + caller
9980 + " (pid=" + Binder.getCallingPid()
9981 + ") when starting service " + service);
9982 }
9983 }
9984
9985 ServiceLookupResult res =
9986 retrieveServiceLocked(service, resolvedType,
9987 callingPid, callingUid);
9988 if (res == null) {
9989 return null;
9990 }
9991 if (res.record == null) {
9992 return new ComponentName("!", res.permission != null
9993 ? res.permission : "private to package");
9994 }
9995 ServiceRecord r = res.record;
9996 if (unscheduleServiceRestartLocked(r)) {
9997 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9998 + r.shortName);
9999 }
10000 r.startRequested = true;
10001 r.startArgs.add(service);
10002 r.lastStartId++;
10003 if (r.lastStartId < 1) {
10004 r.lastStartId = 1;
10005 }
10006 r.lastActivity = SystemClock.uptimeMillis();
10007 synchronized (r.stats.getBatteryStats()) {
10008 r.stats.startRunningLocked();
10009 }
10010 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10011 return new ComponentName("!", "Service process is bad");
10012 }
10013 return r.name;
10014 }
10015 }
10016
10017 public ComponentName startService(IApplicationThread caller, Intent service,
10018 String resolvedType) {
10019 // Refuse possible leaked file descriptors
10020 if (service != null && service.hasFileDescriptors() == true) {
10021 throw new IllegalArgumentException("File descriptors passed in Intent");
10022 }
10023
10024 synchronized(this) {
10025 final int callingPid = Binder.getCallingPid();
10026 final int callingUid = Binder.getCallingUid();
10027 final long origId = Binder.clearCallingIdentity();
10028 ComponentName res = startServiceLocked(caller, service,
10029 resolvedType, callingPid, callingUid);
10030 Binder.restoreCallingIdentity(origId);
10031 return res;
10032 }
10033 }
10034
10035 ComponentName startServiceInPackage(int uid,
10036 Intent service, String resolvedType) {
10037 synchronized(this) {
10038 final long origId = Binder.clearCallingIdentity();
10039 ComponentName res = startServiceLocked(null, service,
10040 resolvedType, -1, uid);
10041 Binder.restoreCallingIdentity(origId);
10042 return res;
10043 }
10044 }
10045
10046 public int stopService(IApplicationThread caller, Intent service,
10047 String resolvedType) {
10048 // Refuse possible leaked file descriptors
10049 if (service != null && service.hasFileDescriptors() == true) {
10050 throw new IllegalArgumentException("File descriptors passed in Intent");
10051 }
10052
10053 synchronized(this) {
10054 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10055 + " type=" + resolvedType);
10056
10057 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10058 if (caller != null && callerApp == null) {
10059 throw new SecurityException(
10060 "Unable to find app for caller " + caller
10061 + " (pid=" + Binder.getCallingPid()
10062 + ") when stopping service " + service);
10063 }
10064
10065 // If this service is active, make sure it is stopped.
10066 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10067 if (r != null) {
10068 if (r.record != null) {
10069 synchronized (r.record.stats.getBatteryStats()) {
10070 r.record.stats.stopRunningLocked();
10071 }
10072 r.record.startRequested = false;
10073 final long origId = Binder.clearCallingIdentity();
10074 bringDownServiceLocked(r.record, false);
10075 Binder.restoreCallingIdentity(origId);
10076 return 1;
10077 }
10078 return -1;
10079 }
10080 }
10081
10082 return 0;
10083 }
10084
10085 public IBinder peekService(Intent service, String resolvedType) {
10086 // Refuse possible leaked file descriptors
10087 if (service != null && service.hasFileDescriptors() == true) {
10088 throw new IllegalArgumentException("File descriptors passed in Intent");
10089 }
10090
10091 IBinder ret = null;
10092
10093 synchronized(this) {
10094 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10095
10096 if (r != null) {
10097 // r.record is null if findServiceLocked() failed the caller permission check
10098 if (r.record == null) {
10099 throw new SecurityException(
10100 "Permission Denial: Accessing service " + r.record.name
10101 + " from pid=" + Binder.getCallingPid()
10102 + ", uid=" + Binder.getCallingUid()
10103 + " requires " + r.permission);
10104 }
10105 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10106 if (ib != null) {
10107 ret = ib.binder;
10108 }
10109 }
10110 }
10111
10112 return ret;
10113 }
10114
10115 public boolean stopServiceToken(ComponentName className, IBinder token,
10116 int startId) {
10117 synchronized(this) {
10118 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10119 + " " + token + " startId=" + startId);
10120 ServiceRecord r = findServiceLocked(className, token);
10121 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10122 synchronized (r.stats.getBatteryStats()) {
10123 r.stats.stopRunningLocked();
10124 r.startRequested = false;
10125 }
10126 final long origId = Binder.clearCallingIdentity();
10127 bringDownServiceLocked(r, false);
10128 Binder.restoreCallingIdentity(origId);
10129 return true;
10130 }
10131 }
10132 return false;
10133 }
10134
10135 public void setServiceForeground(ComponentName className, IBinder token,
10136 boolean isForeground) {
10137 synchronized(this) {
10138 ServiceRecord r = findServiceLocked(className, token);
10139 if (r != null) {
10140 if (r.isForeground != isForeground) {
10141 final long origId = Binder.clearCallingIdentity();
10142 r.isForeground = isForeground;
10143 if (r.app != null) {
10144 updateServiceForegroundLocked(r.app, true);
10145 }
10146 Binder.restoreCallingIdentity(origId);
10147 }
10148 }
10149 }
10150 }
10151
10152 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10153 boolean anyForeground = false;
10154 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10155 if (sr.isForeground) {
10156 anyForeground = true;
10157 break;
10158 }
10159 }
10160 if (anyForeground != proc.foregroundServices) {
10161 proc.foregroundServices = anyForeground;
10162 if (oomAdj) {
10163 updateOomAdjLocked();
10164 }
10165 }
10166 }
10167
10168 public int bindService(IApplicationThread caller, IBinder token,
10169 Intent service, String resolvedType,
10170 IServiceConnection connection, int flags) {
10171 // Refuse possible leaked file descriptors
10172 if (service != null && service.hasFileDescriptors() == true) {
10173 throw new IllegalArgumentException("File descriptors passed in Intent");
10174 }
10175
10176 synchronized(this) {
10177 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10178 + " type=" + resolvedType + " conn=" + connection.asBinder()
10179 + " flags=0x" + Integer.toHexString(flags));
10180 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10181 if (callerApp == null) {
10182 throw new SecurityException(
10183 "Unable to find app for caller " + caller
10184 + " (pid=" + Binder.getCallingPid()
10185 + ") when binding service " + service);
10186 }
10187
10188 HistoryRecord activity = null;
10189 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010190 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010191 if (aindex < 0) {
10192 Log.w(TAG, "Binding with unknown activity: " + token);
10193 return 0;
10194 }
10195 activity = (HistoryRecord)mHistory.get(aindex);
10196 }
10197
10198 ServiceLookupResult res =
10199 retrieveServiceLocked(service, resolvedType,
10200 Binder.getCallingPid(), Binder.getCallingUid());
10201 if (res == null) {
10202 return 0;
10203 }
10204 if (res.record == null) {
10205 return -1;
10206 }
10207 ServiceRecord s = res.record;
10208
10209 final long origId = Binder.clearCallingIdentity();
10210
10211 if (unscheduleServiceRestartLocked(s)) {
10212 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10213 + s.shortName);
10214 }
10215
10216 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10217 ConnectionRecord c = new ConnectionRecord(b, activity,
10218 connection, flags);
10219
10220 IBinder binder = connection.asBinder();
10221 s.connections.put(binder, c);
10222 b.connections.add(c);
10223 if (activity != null) {
10224 if (activity.connections == null) {
10225 activity.connections = new HashSet<ConnectionRecord>();
10226 }
10227 activity.connections.add(c);
10228 }
10229 b.client.connections.add(c);
10230 mServiceConnections.put(binder, c);
10231
10232 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10233 s.lastActivity = SystemClock.uptimeMillis();
10234 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10235 return 0;
10236 }
10237 }
10238
10239 if (s.app != null) {
10240 // This could have made the service more important.
10241 updateOomAdjLocked(s.app);
10242 }
10243
10244 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10245 + ": received=" + b.intent.received
10246 + " apps=" + b.intent.apps.size()
10247 + " doRebind=" + b.intent.doRebind);
10248
10249 if (s.app != null && b.intent.received) {
10250 // Service is already running, so we can immediately
10251 // publish the connection.
10252 try {
10253 c.conn.connected(s.name, b.intent.binder);
10254 } catch (Exception e) {
10255 Log.w(TAG, "Failure sending service " + s.shortName
10256 + " to connection " + c.conn.asBinder()
10257 + " (in " + c.binding.client.processName + ")", e);
10258 }
10259
10260 // If this is the first app connected back to this binding,
10261 // and the service had previously asked to be told when
10262 // rebound, then do so.
10263 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10264 requestServiceBindingLocked(s, b.intent, true);
10265 }
10266 } else if (!b.intent.requested) {
10267 requestServiceBindingLocked(s, b.intent, false);
10268 }
10269
10270 Binder.restoreCallingIdentity(origId);
10271 }
10272
10273 return 1;
10274 }
10275
10276 private void removeConnectionLocked(
10277 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10278 IBinder binder = c.conn.asBinder();
10279 AppBindRecord b = c.binding;
10280 ServiceRecord s = b.service;
10281 s.connections.remove(binder);
10282 b.connections.remove(c);
10283 if (c.activity != null && c.activity != skipAct) {
10284 if (c.activity.connections != null) {
10285 c.activity.connections.remove(c);
10286 }
10287 }
10288 if (b.client != skipApp) {
10289 b.client.connections.remove(c);
10290 }
10291 mServiceConnections.remove(binder);
10292
10293 if (b.connections.size() == 0) {
10294 b.intent.apps.remove(b.client);
10295 }
10296
10297 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10298 + ": shouldUnbind=" + b.intent.hasBound);
10299 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10300 && b.intent.hasBound) {
10301 try {
10302 bumpServiceExecutingLocked(s);
10303 updateOomAdjLocked(s.app);
10304 b.intent.hasBound = false;
10305 // Assume the client doesn't want to know about a rebind;
10306 // we will deal with that later if it asks for one.
10307 b.intent.doRebind = false;
10308 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10309 } catch (Exception e) {
10310 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10311 serviceDoneExecutingLocked(s, true);
10312 }
10313 }
10314
10315 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10316 bringDownServiceLocked(s, false);
10317 }
10318 }
10319
10320 public boolean unbindService(IServiceConnection connection) {
10321 synchronized (this) {
10322 IBinder binder = connection.asBinder();
10323 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10324 ConnectionRecord r = mServiceConnections.get(binder);
10325 if (r == null) {
10326 Log.w(TAG, "Unbind failed: could not find connection for "
10327 + connection.asBinder());
10328 return false;
10329 }
10330
10331 final long origId = Binder.clearCallingIdentity();
10332
10333 removeConnectionLocked(r, null, null);
10334
10335 if (r.binding.service.app != null) {
10336 // This could have made the service less important.
10337 updateOomAdjLocked(r.binding.service.app);
10338 }
10339
10340 Binder.restoreCallingIdentity(origId);
10341 }
10342
10343 return true;
10344 }
10345
10346 public void publishService(IBinder token, Intent intent, IBinder service) {
10347 // Refuse possible leaked file descriptors
10348 if (intent != null && intent.hasFileDescriptors() == true) {
10349 throw new IllegalArgumentException("File descriptors passed in Intent");
10350 }
10351
10352 synchronized(this) {
10353 if (!(token instanceof ServiceRecord)) {
10354 throw new IllegalArgumentException("Invalid service token");
10355 }
10356 ServiceRecord r = (ServiceRecord)token;
10357
10358 final long origId = Binder.clearCallingIdentity();
10359
10360 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10361 + " " + intent + ": " + service);
10362 if (r != null) {
10363 Intent.FilterComparison filter
10364 = new Intent.FilterComparison(intent);
10365 IntentBindRecord b = r.bindings.get(filter);
10366 if (b != null && !b.received) {
10367 b.binder = service;
10368 b.requested = true;
10369 b.received = true;
10370 if (r.connections.size() > 0) {
10371 Iterator<ConnectionRecord> it
10372 = r.connections.values().iterator();
10373 while (it.hasNext()) {
10374 ConnectionRecord c = it.next();
10375 if (!filter.equals(c.binding.intent.intent)) {
10376 if (DEBUG_SERVICE) Log.v(
10377 TAG, "Not publishing to: " + c);
10378 if (DEBUG_SERVICE) Log.v(
10379 TAG, "Bound intent: " + c.binding.intent.intent);
10380 if (DEBUG_SERVICE) Log.v(
10381 TAG, "Published intent: " + intent);
10382 continue;
10383 }
10384 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10385 try {
10386 c.conn.connected(r.name, service);
10387 } catch (Exception e) {
10388 Log.w(TAG, "Failure sending service " + r.name +
10389 " to connection " + c.conn.asBinder() +
10390 " (in " + c.binding.client.processName + ")", e);
10391 }
10392 }
10393 }
10394 }
10395
10396 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10397
10398 Binder.restoreCallingIdentity(origId);
10399 }
10400 }
10401 }
10402
10403 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10404 // Refuse possible leaked file descriptors
10405 if (intent != null && intent.hasFileDescriptors() == true) {
10406 throw new IllegalArgumentException("File descriptors passed in Intent");
10407 }
10408
10409 synchronized(this) {
10410 if (!(token instanceof ServiceRecord)) {
10411 throw new IllegalArgumentException("Invalid service token");
10412 }
10413 ServiceRecord r = (ServiceRecord)token;
10414
10415 final long origId = Binder.clearCallingIdentity();
10416
10417 if (r != null) {
10418 Intent.FilterComparison filter
10419 = new Intent.FilterComparison(intent);
10420 IntentBindRecord b = r.bindings.get(filter);
10421 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10422 + " at " + b + ": apps="
10423 + (b != null ? b.apps.size() : 0));
10424 if (b != null) {
10425 if (b.apps.size() > 0) {
10426 // Applications have already bound since the last
10427 // unbind, so just rebind right here.
10428 requestServiceBindingLocked(r, b, true);
10429 } else {
10430 // Note to tell the service the next time there is
10431 // a new client.
10432 b.doRebind = true;
10433 }
10434 }
10435
10436 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10437
10438 Binder.restoreCallingIdentity(origId);
10439 }
10440 }
10441 }
10442
10443 public void serviceDoneExecuting(IBinder token) {
10444 synchronized(this) {
10445 if (!(token instanceof ServiceRecord)) {
10446 throw new IllegalArgumentException("Invalid service token");
10447 }
10448 ServiceRecord r = (ServiceRecord)token;
10449 boolean inStopping = mStoppingServices.contains(token);
10450 if (r != null) {
10451 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10452 + ": nesting=" + r.executeNesting
10453 + ", inStopping=" + inStopping);
10454 if (r != token) {
10455 Log.w(TAG, "Done executing service " + r.name
10456 + " with incorrect token: given " + token
10457 + ", expected " + r);
10458 return;
10459 }
10460
10461 final long origId = Binder.clearCallingIdentity();
10462 serviceDoneExecutingLocked(r, inStopping);
10463 Binder.restoreCallingIdentity(origId);
10464 } else {
10465 Log.w(TAG, "Done executing unknown service " + r.name
10466 + " with token " + token);
10467 }
10468 }
10469 }
10470
10471 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10472 r.executeNesting--;
10473 if (r.executeNesting <= 0 && r.app != null) {
10474 r.app.executingServices.remove(r);
10475 if (r.app.executingServices.size() == 0) {
10476 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10477 }
10478 if (inStopping) {
10479 mStoppingServices.remove(r);
10480 }
10481 updateOomAdjLocked(r.app);
10482 }
10483 }
10484
10485 void serviceTimeout(ProcessRecord proc) {
10486 synchronized(this) {
10487 if (proc.executingServices.size() == 0 || proc.thread == null) {
10488 return;
10489 }
10490 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10491 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10492 ServiceRecord timeout = null;
10493 long nextTime = 0;
10494 while (it.hasNext()) {
10495 ServiceRecord sr = it.next();
10496 if (sr.executingStart < maxTime) {
10497 timeout = sr;
10498 break;
10499 }
10500 if (sr.executingStart > nextTime) {
10501 nextTime = sr.executingStart;
10502 }
10503 }
10504 if (timeout != null && mLRUProcesses.contains(proc)) {
10505 Log.w(TAG, "Timeout executing service: " + timeout);
10506 appNotRespondingLocked(proc, null, "Executing service "
10507 + timeout.name);
10508 } else {
10509 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10510 msg.obj = proc;
10511 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10512 }
10513 }
10514 }
10515
10516 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010517 // BACKUP AND RESTORE
10518 // =========================================================
10519
10520 // Cause the target app to be launched if necessary and its backup agent
10521 // instantiated. The backup agent will invoke backupAgentCreated() on the
10522 // activity manager to announce its creation.
10523 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10524 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10525 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10526
10527 synchronized(this) {
10528 // !!! TODO: currently no check here that we're already bound
10529 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10530 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10531 synchronized (stats) {
10532 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10533 }
10534
10535 BackupRecord r = new BackupRecord(ss, app, backupMode);
10536 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10537 // startProcessLocked() returns existing proc's record if it's already running
10538 ProcessRecord proc = startProcessLocked(app.processName, app,
10539 false, 0, "backup", hostingName);
10540 if (proc == null) {
10541 Log.e(TAG, "Unable to start backup agent process " + r);
10542 return false;
10543 }
10544
10545 r.app = proc;
10546 mBackupTarget = r;
10547 mBackupAppName = app.packageName;
10548
Christopher Tate6fa95972009-06-05 18:43:55 -070010549 // Try not to kill the process during backup
10550 updateOomAdjLocked(proc);
10551
Christopher Tate181fafa2009-05-14 11:12:14 -070010552 // If the process is already attached, schedule the creation of the backup agent now.
10553 // If it is not yet live, this will be done when it attaches to the framework.
10554 if (proc.thread != null) {
10555 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10556 try {
10557 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10558 } catch (RemoteException e) {
10559 // !!! TODO: notify the backup manager that we crashed, or rely on
10560 // death notices, or...?
10561 }
10562 } else {
10563 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10564 }
10565 // Invariants: at this point, the target app process exists and the application
10566 // is either already running or in the process of coming up. mBackupTarget and
10567 // mBackupAppName describe the app, so that when it binds back to the AM we
10568 // know that it's scheduled for a backup-agent operation.
10569 }
10570
10571 return true;
10572 }
10573
10574 // A backup agent has just come up
10575 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10576 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10577 + " = " + agent);
10578
10579 synchronized(this) {
10580 if (!agentPackageName.equals(mBackupAppName)) {
10581 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10582 return;
10583 }
10584
Christopher Tate043dadc2009-06-02 16:11:00 -070010585 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010586 try {
10587 IBackupManager bm = IBackupManager.Stub.asInterface(
10588 ServiceManager.getService(Context.BACKUP_SERVICE));
10589 bm.agentConnected(agentPackageName, agent);
10590 } catch (RemoteException e) {
10591 // can't happen; the backup manager service is local
10592 } catch (Exception e) {
10593 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10594 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010595 } finally {
10596 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010597 }
10598 }
10599 }
10600
10601 // done with this agent
10602 public void unbindBackupAgent(ApplicationInfo appInfo) {
10603 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010604 if (appInfo == null) {
10605 Log.w(TAG, "unbind backup agent for null app");
10606 return;
10607 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010608
10609 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010610 if (mBackupAppName == null) {
10611 Log.w(TAG, "Unbinding backup agent with no active backup");
10612 return;
10613 }
10614
Christopher Tate181fafa2009-05-14 11:12:14 -070010615 if (!mBackupAppName.equals(appInfo.packageName)) {
10616 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10617 return;
10618 }
10619
Christopher Tate6fa95972009-06-05 18:43:55 -070010620 ProcessRecord proc = mBackupTarget.app;
10621 mBackupTarget = null;
10622 mBackupAppName = null;
10623
10624 // Not backing this app up any more; reset its OOM adjustment
10625 updateOomAdjLocked(proc);
10626
Christopher Tatec7b31e32009-06-10 15:49:30 -070010627 // If the app crashed during backup, 'thread' will be null here
10628 if (proc.thread != null) {
10629 try {
10630 proc.thread.scheduleDestroyBackupAgent(appInfo);
10631 } catch (Exception e) {
10632 Log.e(TAG, "Exception when unbinding backup agent:");
10633 e.printStackTrace();
10634 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010635 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010636 }
10637 }
10638 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010639 // BROADCASTS
10640 // =========================================================
10641
10642 private final List getStickies(String action, IntentFilter filter,
10643 List cur) {
10644 final ContentResolver resolver = mContext.getContentResolver();
10645 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10646 if (list == null) {
10647 return cur;
10648 }
10649 int N = list.size();
10650 for (int i=0; i<N; i++) {
10651 Intent intent = list.get(i);
10652 if (filter.match(resolver, intent, true, TAG) >= 0) {
10653 if (cur == null) {
10654 cur = new ArrayList<Intent>();
10655 }
10656 cur.add(intent);
10657 }
10658 }
10659 return cur;
10660 }
10661
10662 private final void scheduleBroadcastsLocked() {
10663 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10664 + mBroadcastsScheduled);
10665
10666 if (mBroadcastsScheduled) {
10667 return;
10668 }
10669 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10670 mBroadcastsScheduled = true;
10671 }
10672
10673 public Intent registerReceiver(IApplicationThread caller,
10674 IIntentReceiver receiver, IntentFilter filter, String permission) {
10675 synchronized(this) {
10676 ProcessRecord callerApp = null;
10677 if (caller != null) {
10678 callerApp = getRecordForAppLocked(caller);
10679 if (callerApp == null) {
10680 throw new SecurityException(
10681 "Unable to find app for caller " + caller
10682 + " (pid=" + Binder.getCallingPid()
10683 + ") when registering receiver " + receiver);
10684 }
10685 }
10686
10687 List allSticky = null;
10688
10689 // Look for any matching sticky broadcasts...
10690 Iterator actions = filter.actionsIterator();
10691 if (actions != null) {
10692 while (actions.hasNext()) {
10693 String action = (String)actions.next();
10694 allSticky = getStickies(action, filter, allSticky);
10695 }
10696 } else {
10697 allSticky = getStickies(null, filter, allSticky);
10698 }
10699
10700 // The first sticky in the list is returned directly back to
10701 // the client.
10702 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10703
10704 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10705 + ": " + sticky);
10706
10707 if (receiver == null) {
10708 return sticky;
10709 }
10710
10711 ReceiverList rl
10712 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10713 if (rl == null) {
10714 rl = new ReceiverList(this, callerApp,
10715 Binder.getCallingPid(),
10716 Binder.getCallingUid(), receiver);
10717 if (rl.app != null) {
10718 rl.app.receivers.add(rl);
10719 } else {
10720 try {
10721 receiver.asBinder().linkToDeath(rl, 0);
10722 } catch (RemoteException e) {
10723 return sticky;
10724 }
10725 rl.linkedToDeath = true;
10726 }
10727 mRegisteredReceivers.put(receiver.asBinder(), rl);
10728 }
10729 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10730 rl.add(bf);
10731 if (!bf.debugCheck()) {
10732 Log.w(TAG, "==> For Dynamic broadast");
10733 }
10734 mReceiverResolver.addFilter(bf);
10735
10736 // Enqueue broadcasts for all existing stickies that match
10737 // this filter.
10738 if (allSticky != null) {
10739 ArrayList receivers = new ArrayList();
10740 receivers.add(bf);
10741
10742 int N = allSticky.size();
10743 for (int i=0; i<N; i++) {
10744 Intent intent = (Intent)allSticky.get(i);
10745 BroadcastRecord r = new BroadcastRecord(intent, null,
10746 null, -1, -1, null, receivers, null, 0, null, null,
10747 false);
10748 if (mParallelBroadcasts.size() == 0) {
10749 scheduleBroadcastsLocked();
10750 }
10751 mParallelBroadcasts.add(r);
10752 }
10753 }
10754
10755 return sticky;
10756 }
10757 }
10758
10759 public void unregisterReceiver(IIntentReceiver receiver) {
10760 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10761
10762 boolean doNext = false;
10763
10764 synchronized(this) {
10765 ReceiverList rl
10766 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10767 if (rl != null) {
10768 if (rl.curBroadcast != null) {
10769 BroadcastRecord r = rl.curBroadcast;
10770 doNext = finishReceiverLocked(
10771 receiver.asBinder(), r.resultCode, r.resultData,
10772 r.resultExtras, r.resultAbort, true);
10773 }
10774
10775 if (rl.app != null) {
10776 rl.app.receivers.remove(rl);
10777 }
10778 removeReceiverLocked(rl);
10779 if (rl.linkedToDeath) {
10780 rl.linkedToDeath = false;
10781 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10782 }
10783 }
10784 }
10785
10786 if (!doNext) {
10787 return;
10788 }
10789
10790 final long origId = Binder.clearCallingIdentity();
10791 processNextBroadcast(false);
10792 trimApplications();
10793 Binder.restoreCallingIdentity(origId);
10794 }
10795
10796 void removeReceiverLocked(ReceiverList rl) {
10797 mRegisteredReceivers.remove(rl.receiver.asBinder());
10798 int N = rl.size();
10799 for (int i=0; i<N; i++) {
10800 mReceiverResolver.removeFilter(rl.get(i));
10801 }
10802 }
10803
10804 private final int broadcastIntentLocked(ProcessRecord callerApp,
10805 String callerPackage, Intent intent, String resolvedType,
10806 IIntentReceiver resultTo, int resultCode, String resultData,
10807 Bundle map, String requiredPermission,
10808 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10809 intent = new Intent(intent);
10810
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010811 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010812 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10813 + " ordered=" + ordered);
10814 if ((resultTo != null) && !ordered) {
10815 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10816 }
10817
10818 // Handle special intents: if this broadcast is from the package
10819 // manager about a package being removed, we need to remove all of
10820 // its activities from the history stack.
10821 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10822 intent.getAction());
10823 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10824 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10825 || uidRemoved) {
10826 if (checkComponentPermission(
10827 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10828 callingPid, callingUid, -1)
10829 == PackageManager.PERMISSION_GRANTED) {
10830 if (uidRemoved) {
10831 final Bundle intentExtras = intent.getExtras();
10832 final int uid = intentExtras != null
10833 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10834 if (uid >= 0) {
10835 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10836 synchronized (bs) {
10837 bs.removeUidStatsLocked(uid);
10838 }
10839 }
10840 } else {
10841 Uri data = intent.getData();
10842 String ssp;
10843 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10844 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10845 uninstallPackageLocked(ssp,
10846 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010847 AttributeCache ac = AttributeCache.instance();
10848 if (ac != null) {
10849 ac.removePackage(ssp);
10850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010851 }
10852 }
10853 }
10854 } else {
10855 String msg = "Permission Denial: " + intent.getAction()
10856 + " broadcast from " + callerPackage + " (pid=" + callingPid
10857 + ", uid=" + callingUid + ")"
10858 + " requires "
10859 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10860 Log.w(TAG, msg);
10861 throw new SecurityException(msg);
10862 }
10863 }
10864
10865 /*
10866 * If this is the time zone changed action, queue up a message that will reset the timezone
10867 * of all currently running processes. This message will get queued up before the broadcast
10868 * happens.
10869 */
10870 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10871 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10872 }
10873
Dianne Hackborn854060af2009-07-09 18:14:31 -070010874 /*
10875 * Prevent non-system code (defined here to be non-persistent
10876 * processes) from sending protected broadcasts.
10877 */
10878 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10879 || callingUid == Process.SHELL_UID || callingUid == 0) {
10880 // Always okay.
10881 } else if (callerApp == null || !callerApp.persistent) {
10882 try {
10883 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10884 intent.getAction())) {
10885 String msg = "Permission Denial: not allowed to send broadcast "
10886 + intent.getAction() + " from pid="
10887 + callingPid + ", uid=" + callingUid;
10888 Log.w(TAG, msg);
10889 throw new SecurityException(msg);
10890 }
10891 } catch (RemoteException e) {
10892 Log.w(TAG, "Remote exception", e);
10893 return BROADCAST_SUCCESS;
10894 }
10895 }
10896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010897 // Add to the sticky list if requested.
10898 if (sticky) {
10899 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10900 callingPid, callingUid)
10901 != PackageManager.PERMISSION_GRANTED) {
10902 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10903 + callingPid + ", uid=" + callingUid
10904 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10905 Log.w(TAG, msg);
10906 throw new SecurityException(msg);
10907 }
10908 if (requiredPermission != null) {
10909 Log.w(TAG, "Can't broadcast sticky intent " + intent
10910 + " and enforce permission " + requiredPermission);
10911 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10912 }
10913 if (intent.getComponent() != null) {
10914 throw new SecurityException(
10915 "Sticky broadcasts can't target a specific component");
10916 }
10917 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10918 if (list == null) {
10919 list = new ArrayList<Intent>();
10920 mStickyBroadcasts.put(intent.getAction(), list);
10921 }
10922 int N = list.size();
10923 int i;
10924 for (i=0; i<N; i++) {
10925 if (intent.filterEquals(list.get(i))) {
10926 // This sticky already exists, replace it.
10927 list.set(i, new Intent(intent));
10928 break;
10929 }
10930 }
10931 if (i >= N) {
10932 list.add(new Intent(intent));
10933 }
10934 }
10935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010936 // Figure out who all will receive this broadcast.
10937 List receivers = null;
10938 List<BroadcastFilter> registeredReceivers = null;
10939 try {
10940 if (intent.getComponent() != null) {
10941 // Broadcast is going to one specific receiver class...
10942 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010943 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010944 if (ai != null) {
10945 receivers = new ArrayList();
10946 ResolveInfo ri = new ResolveInfo();
10947 ri.activityInfo = ai;
10948 receivers.add(ri);
10949 }
10950 } else {
10951 // Need to resolve the intent to interested receivers...
10952 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10953 == 0) {
10954 receivers =
10955 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010956 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010957 }
Mihai Preda074edef2009-05-18 17:13:31 +020010958 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010959 }
10960 } catch (RemoteException ex) {
10961 // pm is in same process, this will never happen.
10962 }
10963
10964 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10965 if (!ordered && NR > 0) {
10966 // If we are not serializing this broadcast, then send the
10967 // registered receivers separately so they don't wait for the
10968 // components to be launched.
10969 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10970 callerPackage, callingPid, callingUid, requiredPermission,
10971 registeredReceivers, resultTo, resultCode, resultData, map,
10972 ordered);
10973 if (DEBUG_BROADCAST) Log.v(
10974 TAG, "Enqueueing parallel broadcast " + r
10975 + ": prev had " + mParallelBroadcasts.size());
10976 mParallelBroadcasts.add(r);
10977 scheduleBroadcastsLocked();
10978 registeredReceivers = null;
10979 NR = 0;
10980 }
10981
10982 // Merge into one list.
10983 int ir = 0;
10984 if (receivers != null) {
10985 // A special case for PACKAGE_ADDED: do not allow the package
10986 // being added to see this broadcast. This prevents them from
10987 // using this as a back door to get run as soon as they are
10988 // installed. Maybe in the future we want to have a special install
10989 // broadcast or such for apps, but we'd like to deliberately make
10990 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010991 boolean skip = false;
10992 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010993 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010994 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10995 skip = true;
10996 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10997 skip = true;
10998 }
10999 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011000 ? intent.getData().getSchemeSpecificPart()
11001 : null;
11002 if (skipPackage != null && receivers != null) {
11003 int NT = receivers.size();
11004 for (int it=0; it<NT; it++) {
11005 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11006 if (curt.activityInfo.packageName.equals(skipPackage)) {
11007 receivers.remove(it);
11008 it--;
11009 NT--;
11010 }
11011 }
11012 }
11013
11014 int NT = receivers != null ? receivers.size() : 0;
11015 int it = 0;
11016 ResolveInfo curt = null;
11017 BroadcastFilter curr = null;
11018 while (it < NT && ir < NR) {
11019 if (curt == null) {
11020 curt = (ResolveInfo)receivers.get(it);
11021 }
11022 if (curr == null) {
11023 curr = registeredReceivers.get(ir);
11024 }
11025 if (curr.getPriority() >= curt.priority) {
11026 // Insert this broadcast record into the final list.
11027 receivers.add(it, curr);
11028 ir++;
11029 curr = null;
11030 it++;
11031 NT++;
11032 } else {
11033 // Skip to the next ResolveInfo in the final list.
11034 it++;
11035 curt = null;
11036 }
11037 }
11038 }
11039 while (ir < NR) {
11040 if (receivers == null) {
11041 receivers = new ArrayList();
11042 }
11043 receivers.add(registeredReceivers.get(ir));
11044 ir++;
11045 }
11046
11047 if ((receivers != null && receivers.size() > 0)
11048 || resultTo != null) {
11049 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11050 callerPackage, callingPid, callingUid, requiredPermission,
11051 receivers, resultTo, resultCode, resultData, map, ordered);
11052 if (DEBUG_BROADCAST) Log.v(
11053 TAG, "Enqueueing ordered broadcast " + r
11054 + ": prev had " + mOrderedBroadcasts.size());
11055 if (DEBUG_BROADCAST) {
11056 int seq = r.intent.getIntExtra("seq", -1);
11057 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11058 }
11059 mOrderedBroadcasts.add(r);
11060 scheduleBroadcastsLocked();
11061 }
11062
11063 return BROADCAST_SUCCESS;
11064 }
11065
11066 public final int broadcastIntent(IApplicationThread caller,
11067 Intent intent, String resolvedType, IIntentReceiver resultTo,
11068 int resultCode, String resultData, Bundle map,
11069 String requiredPermission, boolean serialized, boolean sticky) {
11070 // Refuse possible leaked file descriptors
11071 if (intent != null && intent.hasFileDescriptors() == true) {
11072 throw new IllegalArgumentException("File descriptors passed in Intent");
11073 }
11074
11075 synchronized(this) {
11076 if (!mSystemReady) {
11077 // if the caller really truly claims to know what they're doing, go
11078 // ahead and allow the broadcast without launching any receivers
11079 int flags = intent.getFlags();
11080 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11081 intent = new Intent(intent);
11082 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11083 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11084 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11085 + " before boot completion");
11086 throw new IllegalStateException("Cannot broadcast before boot completed");
11087 }
11088 }
11089
11090 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11091 final int callingPid = Binder.getCallingPid();
11092 final int callingUid = Binder.getCallingUid();
11093 final long origId = Binder.clearCallingIdentity();
11094 int res = broadcastIntentLocked(callerApp,
11095 callerApp != null ? callerApp.info.packageName : null,
11096 intent, resolvedType, resultTo,
11097 resultCode, resultData, map, requiredPermission, serialized,
11098 sticky, callingPid, callingUid);
11099 Binder.restoreCallingIdentity(origId);
11100 return res;
11101 }
11102 }
11103
11104 int broadcastIntentInPackage(String packageName, int uid,
11105 Intent intent, String resolvedType, IIntentReceiver resultTo,
11106 int resultCode, String resultData, Bundle map,
11107 String requiredPermission, boolean serialized, boolean sticky) {
11108 synchronized(this) {
11109 final long origId = Binder.clearCallingIdentity();
11110 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11111 resultTo, resultCode, resultData, map, requiredPermission,
11112 serialized, sticky, -1, uid);
11113 Binder.restoreCallingIdentity(origId);
11114 return res;
11115 }
11116 }
11117
11118 public final void unbroadcastIntent(IApplicationThread caller,
11119 Intent intent) {
11120 // Refuse possible leaked file descriptors
11121 if (intent != null && intent.hasFileDescriptors() == true) {
11122 throw new IllegalArgumentException("File descriptors passed in Intent");
11123 }
11124
11125 synchronized(this) {
11126 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11127 != PackageManager.PERMISSION_GRANTED) {
11128 String msg = "Permission Denial: unbroadcastIntent() from pid="
11129 + Binder.getCallingPid()
11130 + ", uid=" + Binder.getCallingUid()
11131 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11132 Log.w(TAG, msg);
11133 throw new SecurityException(msg);
11134 }
11135 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11136 if (list != null) {
11137 int N = list.size();
11138 int i;
11139 for (i=0; i<N; i++) {
11140 if (intent.filterEquals(list.get(i))) {
11141 list.remove(i);
11142 break;
11143 }
11144 }
11145 }
11146 }
11147 }
11148
11149 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11150 String resultData, Bundle resultExtras, boolean resultAbort,
11151 boolean explicit) {
11152 if (mOrderedBroadcasts.size() == 0) {
11153 if (explicit) {
11154 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11155 }
11156 return false;
11157 }
11158 BroadcastRecord r = mOrderedBroadcasts.get(0);
11159 if (r.receiver == null) {
11160 if (explicit) {
11161 Log.w(TAG, "finishReceiver called but none active");
11162 }
11163 return false;
11164 }
11165 if (r.receiver != receiver) {
11166 Log.w(TAG, "finishReceiver called but active receiver is different");
11167 return false;
11168 }
11169 int state = r.state;
11170 r.state = r.IDLE;
11171 if (state == r.IDLE) {
11172 if (explicit) {
11173 Log.w(TAG, "finishReceiver called but state is IDLE");
11174 }
11175 }
11176 r.receiver = null;
11177 r.intent.setComponent(null);
11178 if (r.curApp != null) {
11179 r.curApp.curReceiver = null;
11180 }
11181 if (r.curFilter != null) {
11182 r.curFilter.receiverList.curBroadcast = null;
11183 }
11184 r.curFilter = null;
11185 r.curApp = null;
11186 r.curComponent = null;
11187 r.curReceiver = null;
11188 mPendingBroadcast = null;
11189
11190 r.resultCode = resultCode;
11191 r.resultData = resultData;
11192 r.resultExtras = resultExtras;
11193 r.resultAbort = resultAbort;
11194
11195 // We will process the next receiver right now if this is finishing
11196 // an app receiver (which is always asynchronous) or after we have
11197 // come back from calling a receiver.
11198 return state == BroadcastRecord.APP_RECEIVE
11199 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11200 }
11201
11202 public void finishReceiver(IBinder who, int resultCode, String resultData,
11203 Bundle resultExtras, boolean resultAbort) {
11204 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11205
11206 // Refuse possible leaked file descriptors
11207 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11208 throw new IllegalArgumentException("File descriptors passed in Bundle");
11209 }
11210
11211 boolean doNext;
11212
11213 final long origId = Binder.clearCallingIdentity();
11214
11215 synchronized(this) {
11216 doNext = finishReceiverLocked(
11217 who, resultCode, resultData, resultExtras, resultAbort, true);
11218 }
11219
11220 if (doNext) {
11221 processNextBroadcast(false);
11222 }
11223 trimApplications();
11224
11225 Binder.restoreCallingIdentity(origId);
11226 }
11227
11228 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11229 if (r.nextReceiver > 0) {
11230 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11231 if (curReceiver instanceof BroadcastFilter) {
11232 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11233 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11234 System.identityHashCode(r),
11235 r.intent.getAction(),
11236 r.nextReceiver - 1,
11237 System.identityHashCode(bf));
11238 } else {
11239 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11240 System.identityHashCode(r),
11241 r.intent.getAction(),
11242 r.nextReceiver - 1,
11243 ((ResolveInfo)curReceiver).toString());
11244 }
11245 } else {
11246 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11247 + r);
11248 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11249 System.identityHashCode(r),
11250 r.intent.getAction(),
11251 r.nextReceiver,
11252 "NONE");
11253 }
11254 }
11255
11256 private final void broadcastTimeout() {
11257 synchronized (this) {
11258 if (mOrderedBroadcasts.size() == 0) {
11259 return;
11260 }
11261 long now = SystemClock.uptimeMillis();
11262 BroadcastRecord r = mOrderedBroadcasts.get(0);
11263 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11264 if (DEBUG_BROADCAST) Log.v(TAG,
11265 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11266 + (r.startTime + BROADCAST_TIMEOUT));
11267 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11268 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11269 return;
11270 }
11271
11272 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11273 r.startTime = now;
11274 r.anrCount++;
11275
11276 // Current receiver has passed its expiration date.
11277 if (r.nextReceiver <= 0) {
11278 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11279 return;
11280 }
11281
11282 ProcessRecord app = null;
11283
11284 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11285 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11286 logBroadcastReceiverDiscard(r);
11287 if (curReceiver instanceof BroadcastFilter) {
11288 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11289 if (bf.receiverList.pid != 0
11290 && bf.receiverList.pid != MY_PID) {
11291 synchronized (this.mPidsSelfLocked) {
11292 app = this.mPidsSelfLocked.get(
11293 bf.receiverList.pid);
11294 }
11295 }
11296 } else {
11297 app = r.curApp;
11298 }
11299
11300 if (app != null) {
11301 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11302 }
11303
11304 if (mPendingBroadcast == r) {
11305 mPendingBroadcast = null;
11306 }
11307
11308 // Move on to the next receiver.
11309 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11310 r.resultExtras, r.resultAbort, true);
11311 scheduleBroadcastsLocked();
11312 }
11313 }
11314
11315 private final void processCurBroadcastLocked(BroadcastRecord r,
11316 ProcessRecord app) throws RemoteException {
11317 if (app.thread == null) {
11318 throw new RemoteException();
11319 }
11320 r.receiver = app.thread.asBinder();
11321 r.curApp = app;
11322 app.curReceiver = r;
11323 updateLRUListLocked(app, true);
11324
11325 // Tell the application to launch this receiver.
11326 r.intent.setComponent(r.curComponent);
11327
11328 boolean started = false;
11329 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011330 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011331 "Delivering to component " + r.curComponent
11332 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011333 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011334 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11335 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11336 started = true;
11337 } finally {
11338 if (!started) {
11339 r.receiver = null;
11340 r.curApp = null;
11341 app.curReceiver = null;
11342 }
11343 }
11344
11345 }
11346
11347 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11348 Intent intent, int resultCode, String data,
11349 Bundle extras, boolean ordered) throws RemoteException {
11350 if (app != null && app.thread != null) {
11351 // If we have an app thread, do the call through that so it is
11352 // correctly ordered with other one-way calls.
11353 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11354 data, extras, ordered);
11355 } else {
11356 receiver.performReceive(intent, resultCode, data, extras, ordered);
11357 }
11358 }
11359
11360 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11361 BroadcastFilter filter, boolean ordered) {
11362 boolean skip = false;
11363 if (filter.requiredPermission != null) {
11364 int perm = checkComponentPermission(filter.requiredPermission,
11365 r.callingPid, r.callingUid, -1);
11366 if (perm != PackageManager.PERMISSION_GRANTED) {
11367 Log.w(TAG, "Permission Denial: broadcasting "
11368 + r.intent.toString()
11369 + " from " + r.callerPackage + " (pid="
11370 + r.callingPid + ", uid=" + r.callingUid + ")"
11371 + " requires " + filter.requiredPermission
11372 + " due to registered receiver " + filter);
11373 skip = true;
11374 }
11375 }
11376 if (r.requiredPermission != null) {
11377 int perm = checkComponentPermission(r.requiredPermission,
11378 filter.receiverList.pid, filter.receiverList.uid, -1);
11379 if (perm != PackageManager.PERMISSION_GRANTED) {
11380 Log.w(TAG, "Permission Denial: receiving "
11381 + r.intent.toString()
11382 + " to " + filter.receiverList.app
11383 + " (pid=" + filter.receiverList.pid
11384 + ", uid=" + filter.receiverList.uid + ")"
11385 + " requires " + r.requiredPermission
11386 + " due to sender " + r.callerPackage
11387 + " (uid " + r.callingUid + ")");
11388 skip = true;
11389 }
11390 }
11391
11392 if (!skip) {
11393 // If this is not being sent as an ordered broadcast, then we
11394 // don't want to touch the fields that keep track of the current
11395 // state of ordered broadcasts.
11396 if (ordered) {
11397 r.receiver = filter.receiverList.receiver.asBinder();
11398 r.curFilter = filter;
11399 filter.receiverList.curBroadcast = r;
11400 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011401 if (filter.receiverList.app != null) {
11402 // Bump hosting application to no longer be in background
11403 // scheduling class. Note that we can't do that if there
11404 // isn't an app... but we can only be in that case for
11405 // things that directly call the IActivityManager API, which
11406 // are already core system stuff so don't matter for this.
11407 r.curApp = filter.receiverList.app;
11408 filter.receiverList.app.curReceiver = r;
11409 updateOomAdjLocked();
11410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011411 }
11412 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011413 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011414 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011415 Log.i(TAG, "Delivering to " + filter.receiverList.app
11416 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011417 }
11418 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11419 new Intent(r.intent), r.resultCode,
11420 r.resultData, r.resultExtras, r.ordered);
11421 if (ordered) {
11422 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11423 }
11424 } catch (RemoteException e) {
11425 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11426 if (ordered) {
11427 r.receiver = null;
11428 r.curFilter = null;
11429 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011430 if (filter.receiverList.app != null) {
11431 filter.receiverList.app.curReceiver = null;
11432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011433 }
11434 }
11435 }
11436 }
11437
11438 private final void processNextBroadcast(boolean fromMsg) {
11439 synchronized(this) {
11440 BroadcastRecord r;
11441
11442 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11443 + mParallelBroadcasts.size() + " broadcasts, "
11444 + mOrderedBroadcasts.size() + " serialized broadcasts");
11445
11446 updateCpuStats();
11447
11448 if (fromMsg) {
11449 mBroadcastsScheduled = false;
11450 }
11451
11452 // First, deliver any non-serialized broadcasts right away.
11453 while (mParallelBroadcasts.size() > 0) {
11454 r = mParallelBroadcasts.remove(0);
11455 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011456 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11457 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011458 for (int i=0; i<N; i++) {
11459 Object target = r.receivers.get(i);
11460 if (DEBUG_BROADCAST) Log.v(TAG,
11461 "Delivering non-serialized to registered "
11462 + target + ": " + r);
11463 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11464 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011465 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11466 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011467 }
11468
11469 // Now take care of the next serialized one...
11470
11471 // If we are waiting for a process to come up to handle the next
11472 // broadcast, then do nothing at this point. Just in case, we
11473 // check that the process we're waiting for still exists.
11474 if (mPendingBroadcast != null) {
11475 Log.i(TAG, "processNextBroadcast: waiting for "
11476 + mPendingBroadcast.curApp);
11477
11478 boolean isDead;
11479 synchronized (mPidsSelfLocked) {
11480 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11481 }
11482 if (!isDead) {
11483 // It's still alive, so keep waiting
11484 return;
11485 } else {
11486 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11487 + " died before responding to broadcast");
11488 mPendingBroadcast = null;
11489 }
11490 }
11491
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011492 boolean looped = false;
11493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011494 do {
11495 if (mOrderedBroadcasts.size() == 0) {
11496 // No more broadcasts pending, so all done!
11497 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011498 if (looped) {
11499 // If we had finished the last ordered broadcast, then
11500 // make sure all processes have correct oom and sched
11501 // adjustments.
11502 updateOomAdjLocked();
11503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011504 return;
11505 }
11506 r = mOrderedBroadcasts.get(0);
11507 boolean forceReceive = false;
11508
11509 // Ensure that even if something goes awry with the timeout
11510 // detection, we catch "hung" broadcasts here, discard them,
11511 // and continue to make progress.
11512 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11513 long now = SystemClock.uptimeMillis();
11514 if (r.dispatchTime > 0) {
11515 if ((numReceivers > 0) &&
11516 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11517 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11518 + " now=" + now
11519 + " dispatchTime=" + r.dispatchTime
11520 + " startTime=" + r.startTime
11521 + " intent=" + r.intent
11522 + " numReceivers=" + numReceivers
11523 + " nextReceiver=" + r.nextReceiver
11524 + " state=" + r.state);
11525 broadcastTimeout(); // forcibly finish this broadcast
11526 forceReceive = true;
11527 r.state = BroadcastRecord.IDLE;
11528 }
11529 }
11530
11531 if (r.state != BroadcastRecord.IDLE) {
11532 if (DEBUG_BROADCAST) Log.d(TAG,
11533 "processNextBroadcast() called when not idle (state="
11534 + r.state + ")");
11535 return;
11536 }
11537
11538 if (r.receivers == null || r.nextReceiver >= numReceivers
11539 || r.resultAbort || forceReceive) {
11540 // No more receivers for this broadcast! Send the final
11541 // result if requested...
11542 if (r.resultTo != null) {
11543 try {
11544 if (DEBUG_BROADCAST) {
11545 int seq = r.intent.getIntExtra("seq", -1);
11546 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11547 + " seq=" + seq + " app=" + r.callerApp);
11548 }
11549 performReceive(r.callerApp, r.resultTo,
11550 new Intent(r.intent), r.resultCode,
11551 r.resultData, r.resultExtras, false);
11552 } catch (RemoteException e) {
11553 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11554 }
11555 }
11556
11557 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11558 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11559
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011560 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11561 + r);
11562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011563 // ... and on to the next...
11564 mOrderedBroadcasts.remove(0);
11565 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011566 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011567 continue;
11568 }
11569 } while (r == null);
11570
11571 // Get the next receiver...
11572 int recIdx = r.nextReceiver++;
11573
11574 // Keep track of when this receiver started, and make sure there
11575 // is a timeout message pending to kill it if need be.
11576 r.startTime = SystemClock.uptimeMillis();
11577 if (recIdx == 0) {
11578 r.dispatchTime = r.startTime;
11579
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011580 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11581 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011582 if (DEBUG_BROADCAST) Log.v(TAG,
11583 "Submitting BROADCAST_TIMEOUT_MSG for "
11584 + (r.startTime + BROADCAST_TIMEOUT));
11585 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11586 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11587 }
11588
11589 Object nextReceiver = r.receivers.get(recIdx);
11590 if (nextReceiver instanceof BroadcastFilter) {
11591 // Simple case: this is a registered receiver who gets
11592 // a direct call.
11593 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11594 if (DEBUG_BROADCAST) Log.v(TAG,
11595 "Delivering serialized to registered "
11596 + filter + ": " + r);
11597 deliverToRegisteredReceiver(r, filter, r.ordered);
11598 if (r.receiver == null || !r.ordered) {
11599 // The receiver has already finished, so schedule to
11600 // process the next one.
11601 r.state = BroadcastRecord.IDLE;
11602 scheduleBroadcastsLocked();
11603 }
11604 return;
11605 }
11606
11607 // Hard case: need to instantiate the receiver, possibly
11608 // starting its application process to host it.
11609
11610 ResolveInfo info =
11611 (ResolveInfo)nextReceiver;
11612
11613 boolean skip = false;
11614 int perm = checkComponentPermission(info.activityInfo.permission,
11615 r.callingPid, r.callingUid,
11616 info.activityInfo.exported
11617 ? -1 : info.activityInfo.applicationInfo.uid);
11618 if (perm != PackageManager.PERMISSION_GRANTED) {
11619 Log.w(TAG, "Permission Denial: broadcasting "
11620 + r.intent.toString()
11621 + " from " + r.callerPackage + " (pid=" + r.callingPid
11622 + ", uid=" + r.callingUid + ")"
11623 + " requires " + info.activityInfo.permission
11624 + " due to receiver " + info.activityInfo.packageName
11625 + "/" + info.activityInfo.name);
11626 skip = true;
11627 }
11628 if (r.callingUid != Process.SYSTEM_UID &&
11629 r.requiredPermission != null) {
11630 try {
11631 perm = ActivityThread.getPackageManager().
11632 checkPermission(r.requiredPermission,
11633 info.activityInfo.applicationInfo.packageName);
11634 } catch (RemoteException e) {
11635 perm = PackageManager.PERMISSION_DENIED;
11636 }
11637 if (perm != PackageManager.PERMISSION_GRANTED) {
11638 Log.w(TAG, "Permission Denial: receiving "
11639 + r.intent + " to "
11640 + info.activityInfo.applicationInfo.packageName
11641 + " requires " + r.requiredPermission
11642 + " due to sender " + r.callerPackage
11643 + " (uid " + r.callingUid + ")");
11644 skip = true;
11645 }
11646 }
11647 if (r.curApp != null && r.curApp.crashing) {
11648 // If the target process is crashing, just skip it.
11649 skip = true;
11650 }
11651
11652 if (skip) {
11653 r.receiver = null;
11654 r.curFilter = null;
11655 r.state = BroadcastRecord.IDLE;
11656 scheduleBroadcastsLocked();
11657 return;
11658 }
11659
11660 r.state = BroadcastRecord.APP_RECEIVE;
11661 String targetProcess = info.activityInfo.processName;
11662 r.curComponent = new ComponentName(
11663 info.activityInfo.applicationInfo.packageName,
11664 info.activityInfo.name);
11665 r.curReceiver = info.activityInfo;
11666
11667 // Is this receiver's application already running?
11668 ProcessRecord app = getProcessRecordLocked(targetProcess,
11669 info.activityInfo.applicationInfo.uid);
11670 if (app != null && app.thread != null) {
11671 try {
11672 processCurBroadcastLocked(r, app);
11673 return;
11674 } catch (RemoteException e) {
11675 Log.w(TAG, "Exception when sending broadcast to "
11676 + r.curComponent, e);
11677 }
11678
11679 // If a dead object exception was thrown -- fall through to
11680 // restart the application.
11681 }
11682
11683 // Not running -- get it started, and enqueue this history record
11684 // to be executed when the app comes up.
11685 if ((r.curApp=startProcessLocked(targetProcess,
11686 info.activityInfo.applicationInfo, true,
11687 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11688 "broadcast", r.curComponent)) == null) {
11689 // Ah, this recipient is unavailable. Finish it if necessary,
11690 // and mark the broadcast record as ready for the next.
11691 Log.w(TAG, "Unable to launch app "
11692 + info.activityInfo.applicationInfo.packageName + "/"
11693 + info.activityInfo.applicationInfo.uid + " for broadcast "
11694 + r.intent + ": process is bad");
11695 logBroadcastReceiverDiscard(r);
11696 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11697 r.resultExtras, r.resultAbort, true);
11698 scheduleBroadcastsLocked();
11699 r.state = BroadcastRecord.IDLE;
11700 return;
11701 }
11702
11703 mPendingBroadcast = r;
11704 }
11705 }
11706
11707 // =========================================================
11708 // INSTRUMENTATION
11709 // =========================================================
11710
11711 public boolean startInstrumentation(ComponentName className,
11712 String profileFile, int flags, Bundle arguments,
11713 IInstrumentationWatcher watcher) {
11714 // Refuse possible leaked file descriptors
11715 if (arguments != null && arguments.hasFileDescriptors()) {
11716 throw new IllegalArgumentException("File descriptors passed in Bundle");
11717 }
11718
11719 synchronized(this) {
11720 InstrumentationInfo ii = null;
11721 ApplicationInfo ai = null;
11722 try {
11723 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011724 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011725 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011726 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011727 } catch (PackageManager.NameNotFoundException e) {
11728 }
11729 if (ii == null) {
11730 reportStartInstrumentationFailure(watcher, className,
11731 "Unable to find instrumentation info for: " + className);
11732 return false;
11733 }
11734 if (ai == null) {
11735 reportStartInstrumentationFailure(watcher, className,
11736 "Unable to find instrumentation target package: " + ii.targetPackage);
11737 return false;
11738 }
11739
11740 int match = mContext.getPackageManager().checkSignatures(
11741 ii.targetPackage, ii.packageName);
11742 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11743 String msg = "Permission Denial: starting instrumentation "
11744 + className + " from pid="
11745 + Binder.getCallingPid()
11746 + ", uid=" + Binder.getCallingPid()
11747 + " not allowed because package " + ii.packageName
11748 + " does not have a signature matching the target "
11749 + ii.targetPackage;
11750 reportStartInstrumentationFailure(watcher, className, msg);
11751 throw new SecurityException(msg);
11752 }
11753
11754 final long origId = Binder.clearCallingIdentity();
11755 uninstallPackageLocked(ii.targetPackage, -1, true);
11756 ProcessRecord app = addAppLocked(ai);
11757 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011758 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011759 app.instrumentationProfileFile = profileFile;
11760 app.instrumentationArguments = arguments;
11761 app.instrumentationWatcher = watcher;
11762 app.instrumentationResultClass = className;
11763 Binder.restoreCallingIdentity(origId);
11764 }
11765
11766 return true;
11767 }
11768
11769 /**
11770 * Report errors that occur while attempting to start Instrumentation. Always writes the
11771 * error to the logs, but if somebody is watching, send the report there too. This enables
11772 * the "am" command to report errors with more information.
11773 *
11774 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11775 * @param cn The component name of the instrumentation.
11776 * @param report The error report.
11777 */
11778 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11779 ComponentName cn, String report) {
11780 Log.w(TAG, report);
11781 try {
11782 if (watcher != null) {
11783 Bundle results = new Bundle();
11784 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11785 results.putString("Error", report);
11786 watcher.instrumentationStatus(cn, -1, results);
11787 }
11788 } catch (RemoteException e) {
11789 Log.w(TAG, e);
11790 }
11791 }
11792
11793 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11794 if (app.instrumentationWatcher != null) {
11795 try {
11796 // NOTE: IInstrumentationWatcher *must* be oneway here
11797 app.instrumentationWatcher.instrumentationFinished(
11798 app.instrumentationClass,
11799 resultCode,
11800 results);
11801 } catch (RemoteException e) {
11802 }
11803 }
11804 app.instrumentationWatcher = null;
11805 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011806 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011807 app.instrumentationProfileFile = null;
11808 app.instrumentationArguments = null;
11809
11810 uninstallPackageLocked(app.processName, -1, false);
11811 }
11812
11813 public void finishInstrumentation(IApplicationThread target,
11814 int resultCode, Bundle results) {
11815 // Refuse possible leaked file descriptors
11816 if (results != null && results.hasFileDescriptors()) {
11817 throw new IllegalArgumentException("File descriptors passed in Intent");
11818 }
11819
11820 synchronized(this) {
11821 ProcessRecord app = getRecordForAppLocked(target);
11822 if (app == null) {
11823 Log.w(TAG, "finishInstrumentation: no app for " + target);
11824 return;
11825 }
11826 final long origId = Binder.clearCallingIdentity();
11827 finishInstrumentationLocked(app, resultCode, results);
11828 Binder.restoreCallingIdentity(origId);
11829 }
11830 }
11831
11832 // =========================================================
11833 // CONFIGURATION
11834 // =========================================================
11835
11836 public ConfigurationInfo getDeviceConfigurationInfo() {
11837 ConfigurationInfo config = new ConfigurationInfo();
11838 synchronized (this) {
11839 config.reqTouchScreen = mConfiguration.touchscreen;
11840 config.reqKeyboardType = mConfiguration.keyboard;
11841 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011842 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11843 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011844 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11845 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011846 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11847 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011848 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11849 }
11850 }
11851 return config;
11852 }
11853
11854 public Configuration getConfiguration() {
11855 Configuration ci;
11856 synchronized(this) {
11857 ci = new Configuration(mConfiguration);
11858 }
11859 return ci;
11860 }
11861
11862 public void updateConfiguration(Configuration values) {
11863 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11864 "updateConfiguration()");
11865
11866 synchronized(this) {
11867 if (values == null && mWindowManager != null) {
11868 // sentinel: fetch the current configuration from the window manager
11869 values = mWindowManager.computeNewConfiguration();
11870 }
11871
11872 final long origId = Binder.clearCallingIdentity();
11873 updateConfigurationLocked(values, null);
11874 Binder.restoreCallingIdentity(origId);
11875 }
11876 }
11877
11878 /**
11879 * Do either or both things: (1) change the current configuration, and (2)
11880 * make sure the given activity is running with the (now) current
11881 * configuration. Returns true if the activity has been left running, or
11882 * false if <var>starting</var> is being destroyed to match the new
11883 * configuration.
11884 */
11885 public boolean updateConfigurationLocked(Configuration values,
11886 HistoryRecord starting) {
11887 int changes = 0;
11888
11889 boolean kept = true;
11890
11891 if (values != null) {
11892 Configuration newConfig = new Configuration(mConfiguration);
11893 changes = newConfig.updateFrom(values);
11894 if (changes != 0) {
11895 if (DEBUG_SWITCH) {
11896 Log.i(TAG, "Updating configuration to: " + values);
11897 }
11898
11899 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11900
11901 if (values.locale != null) {
11902 saveLocaleLocked(values.locale,
11903 !values.locale.equals(mConfiguration.locale),
11904 values.userSetLocale);
11905 }
11906
11907 mConfiguration = newConfig;
11908
11909 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11910 msg.obj = new Configuration(mConfiguration);
11911 mHandler.sendMessage(msg);
11912
11913 final int N = mLRUProcesses.size();
11914 for (int i=0; i<N; i++) {
11915 ProcessRecord app = mLRUProcesses.get(i);
11916 try {
11917 if (app.thread != null) {
11918 app.thread.scheduleConfigurationChanged(mConfiguration);
11919 }
11920 } catch (Exception e) {
11921 }
11922 }
11923 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11924 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11925 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011926
11927 AttributeCache ac = AttributeCache.instance();
11928 if (ac != null) {
11929 ac.updateConfiguration(mConfiguration);
11930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011931 }
11932 }
11933
11934 if (changes != 0 && starting == null) {
11935 // If the configuration changed, and the caller is not already
11936 // in the process of starting an activity, then find the top
11937 // activity to check if its configuration needs to change.
11938 starting = topRunningActivityLocked(null);
11939 }
11940
11941 if (starting != null) {
11942 kept = ensureActivityConfigurationLocked(starting, changes);
11943 if (kept) {
11944 // If this didn't result in the starting activity being
11945 // destroyed, then we need to make sure at this point that all
11946 // other activities are made visible.
11947 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11948 + ", ensuring others are correct.");
11949 ensureActivitiesVisibleLocked(starting, changes);
11950 }
11951 }
11952
11953 return kept;
11954 }
11955
11956 private final boolean relaunchActivityLocked(HistoryRecord r,
11957 int changes, boolean andResume) {
11958 List<ResultInfo> results = null;
11959 List<Intent> newIntents = null;
11960 if (andResume) {
11961 results = r.results;
11962 newIntents = r.newIntents;
11963 }
11964 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11965 + " with results=" + results + " newIntents=" + newIntents
11966 + " andResume=" + andResume);
11967 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11968 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11969 r.task.taskId, r.shortComponentName);
11970
11971 r.startFreezingScreenLocked(r.app, 0);
11972
11973 try {
11974 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11975 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11976 changes, !andResume);
11977 // Note: don't need to call pauseIfSleepingLocked() here, because
11978 // the caller will only pass in 'andResume' if this activity is
11979 // currently resumed, which implies we aren't sleeping.
11980 } catch (RemoteException e) {
11981 return false;
11982 }
11983
11984 if (andResume) {
11985 r.results = null;
11986 r.newIntents = null;
11987 }
11988
11989 return true;
11990 }
11991
11992 /**
11993 * Make sure the given activity matches the current configuration. Returns
11994 * false if the activity had to be destroyed. Returns true if the
11995 * configuration is the same, or the activity will remain running as-is
11996 * for whatever reason. Ensures the HistoryRecord is updated with the
11997 * correct configuration and all other bookkeeping is handled.
11998 */
11999 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12000 int globalChanges) {
12001 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12002
12003 // Short circuit: if the two configurations are the exact same
12004 // object (the common case), then there is nothing to do.
12005 Configuration newConfig = mConfiguration;
12006 if (r.configuration == newConfig) {
12007 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12008 return true;
12009 }
12010
12011 // We don't worry about activities that are finishing.
12012 if (r.finishing) {
12013 if (DEBUG_SWITCH) Log.i(TAG,
12014 "Configuration doesn't matter in finishing " + r);
12015 r.stopFreezingScreenLocked(false);
12016 return true;
12017 }
12018
12019 // Okay we now are going to make this activity have the new config.
12020 // But then we need to figure out how it needs to deal with that.
12021 Configuration oldConfig = r.configuration;
12022 r.configuration = newConfig;
12023
12024 // If the activity isn't currently running, just leave the new
12025 // configuration and it will pick that up next time it starts.
12026 if (r.app == null || r.app.thread == null) {
12027 if (DEBUG_SWITCH) Log.i(TAG,
12028 "Configuration doesn't matter not running " + r);
12029 r.stopFreezingScreenLocked(false);
12030 return true;
12031 }
12032
12033 // If the activity isn't persistent, there is a chance we will
12034 // need to restart it.
12035 if (!r.persistent) {
12036
12037 // Figure out what has changed between the two configurations.
12038 int changes = oldConfig.diff(newConfig);
12039 if (DEBUG_SWITCH) {
12040 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12041 + Integer.toHexString(changes) + ", handles=0x"
12042 + Integer.toHexString(r.info.configChanges));
12043 }
12044 if ((changes&(~r.info.configChanges)) != 0) {
12045 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12046 r.configChangeFlags |= changes;
12047 r.startFreezingScreenLocked(r.app, globalChanges);
12048 if (r.app == null || r.app.thread == null) {
12049 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12050 destroyActivityLocked(r, true);
12051 } else if (r.state == ActivityState.PAUSING) {
12052 // A little annoying: we are waiting for this activity to
12053 // finish pausing. Let's not do anything now, but just
12054 // flag that it needs to be restarted when done pausing.
12055 r.configDestroy = true;
12056 return true;
12057 } else if (r.state == ActivityState.RESUMED) {
12058 // Try to optimize this case: the configuration is changing
12059 // and we need to restart the top, resumed activity.
12060 // Instead of doing the normal handshaking, just say
12061 // "restart!".
12062 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12063 relaunchActivityLocked(r, r.configChangeFlags, true);
12064 r.configChangeFlags = 0;
12065 } else {
12066 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12067 relaunchActivityLocked(r, r.configChangeFlags, false);
12068 r.configChangeFlags = 0;
12069 }
12070
12071 // All done... tell the caller we weren't able to keep this
12072 // activity around.
12073 return false;
12074 }
12075 }
12076
12077 // Default case: the activity can handle this new configuration, so
12078 // hand it over. Note that we don't need to give it the new
12079 // configuration, since we always send configuration changes to all
12080 // process when they happen so it can just use whatever configuration
12081 // it last got.
12082 if (r.app != null && r.app.thread != null) {
12083 try {
12084 r.app.thread.scheduleActivityConfigurationChanged(r);
12085 } catch (RemoteException e) {
12086 // If process died, whatever.
12087 }
12088 }
12089 r.stopFreezingScreenLocked(false);
12090
12091 return true;
12092 }
12093
12094 /**
12095 * Save the locale. You must be inside a synchronized (this) block.
12096 */
12097 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12098 if(isDiff) {
12099 SystemProperties.set("user.language", l.getLanguage());
12100 SystemProperties.set("user.region", l.getCountry());
12101 }
12102
12103 if(isPersist) {
12104 SystemProperties.set("persist.sys.language", l.getLanguage());
12105 SystemProperties.set("persist.sys.country", l.getCountry());
12106 SystemProperties.set("persist.sys.localevar", l.getVariant());
12107 }
12108 }
12109
12110 // =========================================================
12111 // LIFETIME MANAGEMENT
12112 // =========================================================
12113
12114 private final int computeOomAdjLocked(
12115 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12116 if (mAdjSeq == app.adjSeq) {
12117 // This adjustment has already been computed.
12118 return app.curAdj;
12119 }
12120
12121 if (app.thread == null) {
12122 app.adjSeq = mAdjSeq;
12123 return (app.curAdj=EMPTY_APP_ADJ);
12124 }
12125
12126 app.isForeground = false;
12127
The Android Open Source Project4df24232009-03-05 14:34:35 -080012128 // Determine the importance of the process, starting with most
12129 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012130 int adj;
12131 int N;
12132 if (app == TOP_APP || app.instrumentationClass != null
12133 || app.persistentActivities > 0) {
12134 // The last app on the list is the foreground app.
12135 adj = FOREGROUND_APP_ADJ;
12136 app.isForeground = true;
12137 } else if (app.curReceiver != null ||
12138 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12139 // An app that is currently receiving a broadcast also
12140 // counts as being in the foreground.
12141 adj = FOREGROUND_APP_ADJ;
12142 } else if (app.executingServices.size() > 0) {
12143 // An app that is currently executing a service callback also
12144 // counts as being in the foreground.
12145 adj = FOREGROUND_APP_ADJ;
12146 } else if (app.foregroundServices || app.forcingToForeground != null) {
12147 // The user is aware of this app, so make it visible.
12148 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012149 } else if (app == mHomeProcess) {
12150 // This process is hosting what we currently consider to be the
12151 // home app, so we don't want to let it go into the background.
12152 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012153 } else if ((N=app.activities.size()) != 0) {
12154 // This app is in the background with paused activities.
12155 adj = hiddenAdj;
12156 for (int j=0; j<N; j++) {
12157 if (((HistoryRecord)app.activities.get(j)).visible) {
12158 // This app has a visible activity!
12159 adj = VISIBLE_APP_ADJ;
12160 break;
12161 }
12162 }
12163 } else {
12164 // A very not-needed process.
12165 adj = EMPTY_APP_ADJ;
12166 }
12167
The Android Open Source Project4df24232009-03-05 14:34:35 -080012168 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012169 // there are applications dependent on our services or providers, but
12170 // this gives us a baseline and makes sure we don't get into an
12171 // infinite recursion.
12172 app.adjSeq = mAdjSeq;
12173 app.curRawAdj = adj;
12174 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12175
Christopher Tate6fa95972009-06-05 18:43:55 -070012176 if (mBackupTarget != null && app == mBackupTarget.app) {
12177 // If possible we want to avoid killing apps while they're being backed up
12178 if (adj > BACKUP_APP_ADJ) {
12179 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12180 adj = BACKUP_APP_ADJ;
12181 }
12182 }
12183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012184 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12185 // If this process has active services running in it, we would
12186 // like to avoid killing it unless it would prevent the current
12187 // application from running.
12188 if (adj > hiddenAdj) {
12189 adj = hiddenAdj;
12190 }
12191 final long now = SystemClock.uptimeMillis();
12192 // This process is more important if the top activity is
12193 // bound to the service.
12194 Iterator jt = app.services.iterator();
12195 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12196 ServiceRecord s = (ServiceRecord)jt.next();
12197 if (s.startRequested) {
12198 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12199 // This service has seen some activity within
12200 // recent memory, so we will keep its process ahead
12201 // of the background processes.
12202 if (adj > SECONDARY_SERVER_ADJ) {
12203 adj = SECONDARY_SERVER_ADJ;
12204 }
12205 } else {
12206 // This service has been inactive for too long, just
12207 // put it with the rest of the background processes.
12208 if (adj > hiddenAdj) {
12209 adj = hiddenAdj;
12210 }
12211 }
12212 }
12213 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12214 Iterator<ConnectionRecord> kt
12215 = s.connections.values().iterator();
12216 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12217 // XXX should compute this based on the max of
12218 // all connected clients.
12219 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012220 if (cr.binding.client == app) {
12221 // Binding to ourself is not interesting.
12222 continue;
12223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012224 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12225 ProcessRecord client = cr.binding.client;
12226 int myHiddenAdj = hiddenAdj;
12227 if (myHiddenAdj > client.hiddenAdj) {
12228 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12229 myHiddenAdj = client.hiddenAdj;
12230 } else {
12231 myHiddenAdj = VISIBLE_APP_ADJ;
12232 }
12233 }
12234 int clientAdj = computeOomAdjLocked(
12235 client, myHiddenAdj, TOP_APP);
12236 if (adj > clientAdj) {
12237 adj = clientAdj > VISIBLE_APP_ADJ
12238 ? clientAdj : VISIBLE_APP_ADJ;
12239 }
12240 }
12241 HistoryRecord a = cr.activity;
12242 //if (a != null) {
12243 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12244 //}
12245 if (a != null && adj > FOREGROUND_APP_ADJ &&
12246 (a.state == ActivityState.RESUMED
12247 || a.state == ActivityState.PAUSING)) {
12248 adj = FOREGROUND_APP_ADJ;
12249 }
12250 }
12251 }
12252 }
12253 }
12254
12255 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12256 // If this process has published any content providers, then
12257 // its adjustment makes it at least as important as any of the
12258 // processes using those providers, and no less important than
12259 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12260 if (adj > CONTENT_PROVIDER_ADJ) {
12261 adj = CONTENT_PROVIDER_ADJ;
12262 }
12263 Iterator jt = app.pubProviders.values().iterator();
12264 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12265 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12266 if (cpr.clients.size() != 0) {
12267 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12268 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12269 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012270 if (client == app) {
12271 // Being our own client is not interesting.
12272 continue;
12273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012274 int myHiddenAdj = hiddenAdj;
12275 if (myHiddenAdj > client.hiddenAdj) {
12276 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12277 myHiddenAdj = client.hiddenAdj;
12278 } else {
12279 myHiddenAdj = FOREGROUND_APP_ADJ;
12280 }
12281 }
12282 int clientAdj = computeOomAdjLocked(
12283 client, myHiddenAdj, TOP_APP);
12284 if (adj > clientAdj) {
12285 adj = clientAdj > FOREGROUND_APP_ADJ
12286 ? clientAdj : FOREGROUND_APP_ADJ;
12287 }
12288 }
12289 }
12290 // If the provider has external (non-framework) process
12291 // dependencies, ensure that its adjustment is at least
12292 // FOREGROUND_APP_ADJ.
12293 if (cpr.externals != 0) {
12294 if (adj > FOREGROUND_APP_ADJ) {
12295 adj = FOREGROUND_APP_ADJ;
12296 }
12297 }
12298 }
12299 }
12300
12301 app.curRawAdj = adj;
12302
12303 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12304 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12305 if (adj > app.maxAdj) {
12306 adj = app.maxAdj;
12307 }
12308
12309 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012310 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12311 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12312 : Process.THREAD_GROUP_DEFAULT;
12313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012314 return adj;
12315 }
12316
12317 /**
12318 * Ask a given process to GC right now.
12319 */
12320 final void performAppGcLocked(ProcessRecord app) {
12321 try {
12322 app.lastRequestedGc = SystemClock.uptimeMillis();
12323 if (app.thread != null) {
12324 app.thread.processInBackground();
12325 }
12326 } catch (Exception e) {
12327 // whatever.
12328 }
12329 }
12330
12331 /**
12332 * Returns true if things are idle enough to perform GCs.
12333 */
12334 private final boolean canGcNow() {
12335 return mParallelBroadcasts.size() == 0
12336 && mOrderedBroadcasts.size() == 0
12337 && (mSleeping || (mResumedActivity != null &&
12338 mResumedActivity.idle));
12339 }
12340
12341 /**
12342 * Perform GCs on all processes that are waiting for it, but only
12343 * if things are idle.
12344 */
12345 final void performAppGcsLocked() {
12346 final int N = mProcessesToGc.size();
12347 if (N <= 0) {
12348 return;
12349 }
12350 if (canGcNow()) {
12351 while (mProcessesToGc.size() > 0) {
12352 ProcessRecord proc = mProcessesToGc.remove(0);
12353 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12354 // To avoid spamming the system, we will GC processes one
12355 // at a time, waiting a few seconds between each.
12356 performAppGcLocked(proc);
12357 scheduleAppGcsLocked();
12358 return;
12359 }
12360 }
12361 }
12362 }
12363
12364 /**
12365 * If all looks good, perform GCs on all processes waiting for them.
12366 */
12367 final void performAppGcsIfAppropriateLocked() {
12368 if (canGcNow()) {
12369 performAppGcsLocked();
12370 return;
12371 }
12372 // Still not idle, wait some more.
12373 scheduleAppGcsLocked();
12374 }
12375
12376 /**
12377 * Schedule the execution of all pending app GCs.
12378 */
12379 final void scheduleAppGcsLocked() {
12380 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12381 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12382 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12383 }
12384
12385 /**
12386 * Set up to ask a process to GC itself. This will either do it
12387 * immediately, or put it on the list of processes to gc the next
12388 * time things are idle.
12389 */
12390 final void scheduleAppGcLocked(ProcessRecord app) {
12391 long now = SystemClock.uptimeMillis();
12392 if ((app.lastRequestedGc+5000) > now) {
12393 return;
12394 }
12395 if (!mProcessesToGc.contains(app)) {
12396 mProcessesToGc.add(app);
12397 scheduleAppGcsLocked();
12398 }
12399 }
12400
12401 private final boolean updateOomAdjLocked(
12402 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12403 app.hiddenAdj = hiddenAdj;
12404
12405 if (app.thread == null) {
12406 return true;
12407 }
12408
12409 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12410
12411 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12412 //Thread priority adjustment is disabled out to see
12413 //how the kernel scheduler performs.
12414 if (false) {
12415 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12416 app.setIsForeground = app.isForeground;
12417 if (app.pid != MY_PID) {
12418 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12419 + " to " + (app.isForeground
12420 ? Process.THREAD_PRIORITY_FOREGROUND
12421 : Process.THREAD_PRIORITY_DEFAULT));
12422 try {
12423 Process.setThreadPriority(app.pid, app.isForeground
12424 ? Process.THREAD_PRIORITY_FOREGROUND
12425 : Process.THREAD_PRIORITY_DEFAULT);
12426 } catch (RuntimeException e) {
12427 Log.w(TAG, "Exception trying to set priority of application thread "
12428 + app.pid, e);
12429 }
12430 }
12431 }
12432 }
12433 if (app.pid != 0 && app.pid != MY_PID) {
12434 if (app.curRawAdj != app.setRawAdj) {
12435 if (app.curRawAdj > FOREGROUND_APP_ADJ
12436 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12437 // If this app is transitioning from foreground to
12438 // non-foreground, have it do a gc.
12439 scheduleAppGcLocked(app);
12440 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12441 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12442 // Likewise do a gc when an app is moving in to the
12443 // background (such as a service stopping).
12444 scheduleAppGcLocked(app);
12445 }
12446 app.setRawAdj = app.curRawAdj;
12447 }
12448 if (adj != app.setAdj) {
12449 if (Process.setOomAdj(app.pid, adj)) {
12450 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12451 TAG, "Set app " + app.processName +
12452 " oom adj to " + adj);
12453 app.setAdj = adj;
12454 } else {
12455 return false;
12456 }
12457 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012458 if (app.setSchedGroup != app.curSchedGroup) {
12459 app.setSchedGroup = app.curSchedGroup;
12460 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12461 "Setting process group of " + app.processName
12462 + " to " + app.curSchedGroup);
12463 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012464 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012465 try {
12466 Process.setProcessGroup(app.pid, app.curSchedGroup);
12467 } catch (Exception e) {
12468 Log.w(TAG, "Failed setting process group of " + app.pid
12469 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012470 e.printStackTrace();
12471 } finally {
12472 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012473 }
12474 }
12475 if (false) {
12476 if (app.thread != null) {
12477 try {
12478 app.thread.setSchedulingGroup(app.curSchedGroup);
12479 } catch (RemoteException e) {
12480 }
12481 }
12482 }
12483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012484 }
12485
12486 return true;
12487 }
12488
12489 private final HistoryRecord resumedAppLocked() {
12490 HistoryRecord resumedActivity = mResumedActivity;
12491 if (resumedActivity == null || resumedActivity.app == null) {
12492 resumedActivity = mPausingActivity;
12493 if (resumedActivity == null || resumedActivity.app == null) {
12494 resumedActivity = topRunningActivityLocked(null);
12495 }
12496 }
12497 return resumedActivity;
12498 }
12499
12500 private final boolean updateOomAdjLocked(ProcessRecord app) {
12501 final HistoryRecord TOP_ACT = resumedAppLocked();
12502 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12503 int curAdj = app.curAdj;
12504 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12505 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12506
12507 mAdjSeq++;
12508
12509 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12510 if (res) {
12511 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12512 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12513 if (nowHidden != wasHidden) {
12514 // Changed to/from hidden state, so apps after it in the LRU
12515 // list may also be changed.
12516 updateOomAdjLocked();
12517 }
12518 }
12519 return res;
12520 }
12521
12522 private final boolean updateOomAdjLocked() {
12523 boolean didOomAdj = true;
12524 final HistoryRecord TOP_ACT = resumedAppLocked();
12525 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12526
12527 if (false) {
12528 RuntimeException e = new RuntimeException();
12529 e.fillInStackTrace();
12530 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12531 }
12532
12533 mAdjSeq++;
12534
12535 // First try updating the OOM adjustment for each of the
12536 // application processes based on their current state.
12537 int i = mLRUProcesses.size();
12538 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12539 while (i > 0) {
12540 i--;
12541 ProcessRecord app = mLRUProcesses.get(i);
12542 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12543 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12544 && app.curAdj == curHiddenAdj) {
12545 curHiddenAdj++;
12546 }
12547 } else {
12548 didOomAdj = false;
12549 }
12550 }
12551
12552 // todo: for now pretend like OOM ADJ didn't work, because things
12553 // aren't behaving as expected on Linux -- it's not killing processes.
12554 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12555 }
12556
12557 private final void trimApplications() {
12558 synchronized (this) {
12559 int i;
12560
12561 // First remove any unused application processes whose package
12562 // has been removed.
12563 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12564 final ProcessRecord app = mRemovedProcesses.get(i);
12565 if (app.activities.size() == 0
12566 && app.curReceiver == null && app.services.size() == 0) {
12567 Log.i(
12568 TAG, "Exiting empty application process "
12569 + app.processName + " ("
12570 + (app.thread != null ? app.thread.asBinder() : null)
12571 + ")\n");
12572 if (app.pid > 0 && app.pid != MY_PID) {
12573 Process.killProcess(app.pid);
12574 } else {
12575 try {
12576 app.thread.scheduleExit();
12577 } catch (Exception e) {
12578 // Ignore exceptions.
12579 }
12580 }
12581 cleanUpApplicationRecordLocked(app, false, -1);
12582 mRemovedProcesses.remove(i);
12583
12584 if (app.persistent) {
12585 if (app.persistent) {
12586 addAppLocked(app.info);
12587 }
12588 }
12589 }
12590 }
12591
12592 // Now try updating the OOM adjustment for each of the
12593 // application processes based on their current state.
12594 // If the setOomAdj() API is not supported, then go with our
12595 // back-up plan...
12596 if (!updateOomAdjLocked()) {
12597
12598 // Count how many processes are running services.
12599 int numServiceProcs = 0;
12600 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12601 final ProcessRecord app = mLRUProcesses.get(i);
12602
12603 if (app.persistent || app.services.size() != 0
12604 || app.curReceiver != null
12605 || app.persistentActivities > 0) {
12606 // Don't count processes holding services against our
12607 // maximum process count.
12608 if (localLOGV) Log.v(
12609 TAG, "Not trimming app " + app + " with services: "
12610 + app.services);
12611 numServiceProcs++;
12612 }
12613 }
12614
12615 int curMaxProcs = mProcessLimit;
12616 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12617 if (mAlwaysFinishActivities) {
12618 curMaxProcs = 1;
12619 }
12620 curMaxProcs += numServiceProcs;
12621
12622 // Quit as many processes as we can to get down to the desired
12623 // process count. First remove any processes that no longer
12624 // have activites running in them.
12625 for ( i=0;
12626 i<mLRUProcesses.size()
12627 && mLRUProcesses.size() > curMaxProcs;
12628 i++) {
12629 final ProcessRecord app = mLRUProcesses.get(i);
12630 // Quit an application only if it is not currently
12631 // running any activities.
12632 if (!app.persistent && app.activities.size() == 0
12633 && app.curReceiver == null && app.services.size() == 0) {
12634 Log.i(
12635 TAG, "Exiting empty application process "
12636 + app.processName + " ("
12637 + (app.thread != null ? app.thread.asBinder() : null)
12638 + ")\n");
12639 if (app.pid > 0 && app.pid != MY_PID) {
12640 Process.killProcess(app.pid);
12641 } else {
12642 try {
12643 app.thread.scheduleExit();
12644 } catch (Exception e) {
12645 // Ignore exceptions.
12646 }
12647 }
12648 // todo: For now we assume the application is not buggy
12649 // or evil, and will quit as a result of our request.
12650 // Eventually we need to drive this off of the death
12651 // notification, and kill the process if it takes too long.
12652 cleanUpApplicationRecordLocked(app, false, i);
12653 i--;
12654 }
12655 }
12656
12657 // If we still have too many processes, now from the least
12658 // recently used process we start finishing activities.
12659 if (Config.LOGV) Log.v(
12660 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12661 " of " + curMaxProcs + " processes");
12662 for ( i=0;
12663 i<mLRUProcesses.size()
12664 && mLRUProcesses.size() > curMaxProcs;
12665 i++) {
12666 final ProcessRecord app = mLRUProcesses.get(i);
12667 // Quit the application only if we have a state saved for
12668 // all of its activities.
12669 boolean canQuit = !app.persistent && app.curReceiver == null
12670 && app.services.size() == 0
12671 && app.persistentActivities == 0;
12672 int NUMA = app.activities.size();
12673 int j;
12674 if (Config.LOGV) Log.v(
12675 TAG, "Looking to quit " + app.processName);
12676 for (j=0; j<NUMA && canQuit; j++) {
12677 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12678 if (Config.LOGV) Log.v(
12679 TAG, " " + r.intent.getComponent().flattenToShortString()
12680 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12681 canQuit = (r.haveState || !r.stateNotNeeded)
12682 && !r.visible && r.stopped;
12683 }
12684 if (canQuit) {
12685 // Finish all of the activities, and then the app itself.
12686 for (j=0; j<NUMA; j++) {
12687 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12688 if (!r.finishing) {
12689 destroyActivityLocked(r, false);
12690 }
12691 r.resultTo = null;
12692 }
12693 Log.i(TAG, "Exiting application process "
12694 + app.processName + " ("
12695 + (app.thread != null ? app.thread.asBinder() : null)
12696 + ")\n");
12697 if (app.pid > 0 && app.pid != MY_PID) {
12698 Process.killProcess(app.pid);
12699 } else {
12700 try {
12701 app.thread.scheduleExit();
12702 } catch (Exception e) {
12703 // Ignore exceptions.
12704 }
12705 }
12706 // todo: For now we assume the application is not buggy
12707 // or evil, and will quit as a result of our request.
12708 // Eventually we need to drive this off of the death
12709 // notification, and kill the process if it takes too long.
12710 cleanUpApplicationRecordLocked(app, false, i);
12711 i--;
12712 //dump();
12713 }
12714 }
12715
12716 }
12717
12718 int curMaxActivities = MAX_ACTIVITIES;
12719 if (mAlwaysFinishActivities) {
12720 curMaxActivities = 1;
12721 }
12722
12723 // Finally, if there are too many activities now running, try to
12724 // finish as many as we can to get back down to the limit.
12725 for ( i=0;
12726 i<mLRUActivities.size()
12727 && mLRUActivities.size() > curMaxActivities;
12728 i++) {
12729 final HistoryRecord r
12730 = (HistoryRecord)mLRUActivities.get(i);
12731
12732 // We can finish this one if we have its icicle saved and
12733 // it is not persistent.
12734 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12735 && r.stopped && !r.persistent && !r.finishing) {
12736 final int origSize = mLRUActivities.size();
12737 destroyActivityLocked(r, true);
12738
12739 // This will remove it from the LRU list, so keep
12740 // our index at the same value. Note that this check to
12741 // see if the size changes is just paranoia -- if
12742 // something unexpected happens, we don't want to end up
12743 // in an infinite loop.
12744 if (origSize > mLRUActivities.size()) {
12745 i--;
12746 }
12747 }
12748 }
12749 }
12750 }
12751
12752 /** This method sends the specified signal to each of the persistent apps */
12753 public void signalPersistentProcesses(int sig) throws RemoteException {
12754 if (sig != Process.SIGNAL_USR1) {
12755 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12756 }
12757
12758 synchronized (this) {
12759 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12760 != PackageManager.PERMISSION_GRANTED) {
12761 throw new SecurityException("Requires permission "
12762 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12763 }
12764
12765 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12766 ProcessRecord r = mLRUProcesses.get(i);
12767 if (r.thread != null && r.persistent) {
12768 Process.sendSignal(r.pid, sig);
12769 }
12770 }
12771 }
12772 }
12773
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012774 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012775 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012776
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012777 try {
12778 synchronized (this) {
12779 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12780 // its own permission.
12781 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12782 != PackageManager.PERMISSION_GRANTED) {
12783 throw new SecurityException("Requires permission "
12784 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012785 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012786
12787 if (start && fd == null) {
12788 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012789 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012790
12791 ProcessRecord proc = null;
12792 try {
12793 int pid = Integer.parseInt(process);
12794 synchronized (mPidsSelfLocked) {
12795 proc = mPidsSelfLocked.get(pid);
12796 }
12797 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012798 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012799
12800 if (proc == null) {
12801 HashMap<String, SparseArray<ProcessRecord>> all
12802 = mProcessNames.getMap();
12803 SparseArray<ProcessRecord> procs = all.get(process);
12804 if (procs != null && procs.size() > 0) {
12805 proc = procs.valueAt(0);
12806 }
12807 }
12808
12809 if (proc == null || proc.thread == null) {
12810 throw new IllegalArgumentException("Unknown process: " + process);
12811 }
12812
12813 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12814 if (isSecure) {
12815 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12816 throw new SecurityException("Process not debuggable: " + proc);
12817 }
12818 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012819
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012820 proc.thread.profilerControl(start, path, fd);
12821 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012822 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012823 }
12824 } catch (RemoteException e) {
12825 throw new IllegalStateException("Process disappeared");
12826 } finally {
12827 if (fd != null) {
12828 try {
12829 fd.close();
12830 } catch (IOException e) {
12831 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012832 }
12833 }
12834 }
12835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012836 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12837 public void monitor() {
12838 synchronized (this) { }
12839 }
12840}