package com.android.server.am;
-import com.android.internal.telephony.TelephonyIntents;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.AssistUtils;
-import com.android.internal.app.DumpHeapActivity;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.app.ProcessMap;
-import com.android.internal.app.SystemUserHomeActivity;
-import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.IResultReceiver;
-import com.android.internal.os.ProcessCpuTracker;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.os.Zygote;
-import com.android.internal.os.InstallerConnection.InstallerException;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.MemInfoReader;
-import com.android.internal.util.Preconditions;
-import com.android.server.AppOpsService;
-import com.android.server.AttributeCache;
-import com.android.server.DeviceIdleController;
-import com.android.server.IntentResolver;
-import com.android.server.LocalServices;
-import com.android.server.LockGuard;
-import com.android.server.ServiceThread;
-import com.android.server.SystemService;
-import com.android.server.SystemServiceManager;
-import com.android.server.Watchdog;
-import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.firewall.IntentFirewall;
-import com.android.server.pm.Installer;
-import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.vr.VrManagerInternal;
-import com.android.server.wm.WindowManagerService;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import static android.Manifest.permission.BIND_VOICE_INTERACTION;
+import static android.Manifest.permission.CHANGE_CONFIGURATION;
+import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static android.Manifest.permission.REMOVE_TASKS;
+import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.STOP_APP_SWITCHES;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManagerInternal.ASSIST_KEY_CONTENT;
+import static android.app.ActivityManagerInternal.ASSIST_KEY_DATA;
+import static android.app.ActivityManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
+import static android.app.ActivityManagerInternal.ASSIST_KEY_STRUCTURE;
+import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
+import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
+import static android.os.Build.VERSION_CODES.N;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.os.Process.BLUETOOTH_UID;
+import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.FIRST_ISOLATED_UID;
+import static android.os.Process.LAST_ISOLATED_UID;
+import static android.os.Process.NFC_UID;
+import static android.os.Process.PHONE_UID;
+import static android.os.Process.PROC_CHAR;
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_PARENS;
+import static android.os.Process.PROC_SPACE_TERM;
+import static android.os.Process.ProcessStartResult;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SCHED_FIFO;
+import static android.os.Process.SCHED_OTHER;
+import static android.os.Process.SCHED_RESET_ON_FORK;
+import static android.os.Process.SE_UID;
+import static android.os.Process.SHELL_UID;
+import static android.os.Process.SIGNAL_QUIT;
+import static android.os.Process.SIGNAL_USR1;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
+import static android.os.Process.THREAD_GROUP_DEFAULT;
+import static android.os.Process.THREAD_GROUP_RESTRICTED;
+import static android.os.Process.THREAD_GROUP_TOP_APP;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static android.os.Process.getFreeMemory;
+import static android.os.Process.getTotalMemory;
+import static android.os.Process.isThreadInProcess;
+import static android.os.Process.killProcess;
+import static android.os.Process.killProcessQuiet;
+import static android.os.Process.myPid;
+import static android.os.Process.myUid;
+import static android.os.Process.readProcFile;
+import static android.os.Process.removeAllProcessGroups;
+import static android.os.Process.sendSignal;
+import static android.os.Process.setProcessGroup;
+import static android.os.Process.setThreadPriority;
+import static android.os.Process.setThreadScheduler;
+import static android.os.Process.startWebView;
+import static android.os.Process.zygoteProcess;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
+import static android.provider.Settings.Global.DEBUG_APP;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
+import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
+import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
+import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
+import static android.provider.Settings.System.FONT_SCALE;
+import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ_REASON;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_NETWORK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
+import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY;
+import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.am.MemoryStatUtil.hasMemcg;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.Manifest.permission;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskThumbnailInfo;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerInternal.ScreenObserver;
import android.app.ActivityManagerInternal.SleepToken;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManagerProto;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.ApplicationErrorReport;
-import android.app.ApplicationThreadNative;
+import android.app.ApplicationThreadConstants;
import android.app.BroadcastOptions;
+import android.app.ContentProviderHolder;
import android.app.Dialog;
-import android.app.IActivityContainer;
-import android.app.IActivityContainerCallback;
+import android.app.GrantedUriPermission;
import android.app.IActivityController;
-import android.app.IAppTask;
+import android.app.IActivityManager;
import android.app.IApplicationThread;
+import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.INotificationManager;
import android.app.IProcessObserver;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.PictureInPictureParams;
+import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
-import android.app.admin.DevicePolicyManager;
+import android.app.RemoteAction;
+import android.app.WaitResult;
+import android.app.WindowConfiguration.ActivityType;
+import android.app.WindowConfiguration.WindowingMode;
+import android.app.admin.DevicePolicyCache;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.IBackupManager;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.display.DisplayManagerInternal;
import android.location.LocationManager;
+import android.media.audiofx.AudioEffect;
+import android.metrics.LogMaker;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IDeviceIdentifiersPolicyService;
import android.os.IPermissionController;
import android.os.IProcessInfoService;
import android.os.IProgressListener;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.provider.Downloads;
-import android.os.storage.IMountService;
-import android.os.storage.MountServiceInternal;
+import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
+import android.provider.Downloads;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
-import android.service.voice.VoiceInteractionSession;
import android.telecom.TelecomManager;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.text.style.SuggestionSpan;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DebugUtils;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.StatsLog;
import android.util.TimeUtils;
+import android.util.TimingsTraceLog;
import android.util.Xml;
-import android.view.Display;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
import android.view.Gravity;
+import android.view.IRecentsAnimationRunner;
import android.view.LayoutInflater;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
import android.view.View;
import android.view.WindowManager;
+import android.view.autofill.AutofillManagerInternal;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AssistUtils;
+import com.android.internal.app.DumpHeapActivity;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ProcessMap;
+import com.android.internal.app.SystemUserHomeActivity;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.BinderInternal;
+import com.android.internal.os.logging.MetricsLoggerWrapper;
+import com.android.internal.os.ByteTransferPipe;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.os.Zygote;
+import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.KeyguardDismissCallback;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.MemInfoReader;
+import com.android.internal.util.Preconditions;
+import com.android.server.AlarmManagerInternal;
+import com.android.server.AppOpsService;
+import com.android.server.AttributeCache;
+import com.android.server.BinderCallsStatsService;
+import com.android.server.DeviceIdleController;
+import com.android.server.IntentResolver;
+import com.android.server.IoThread;
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
+import com.android.server.NetworkManagementInternal;
+import com.android.server.RescueParty;
+import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
+import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
+import com.android.server.ThreadPriorityBooster;
+import com.android.server.Watchdog;
+import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.am.ActivityManagerServiceProto;
+import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
+import com.android.server.am.ActivityManagerServiceDumpBroadcastsProto;
+import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
+import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
+import com.android.server.am.ActivityManagerServiceDumpServicesProto;
+import com.android.server.am.GrantUriProto;
+import com.android.server.am.ImportanceTokenProto;
+import com.android.server.am.MemInfoDumpProto;
+import com.android.server.am.NeededUriGrantsProto;
+import com.android.server.am.ProcessOomProto;
+import com.android.server.am.ProcessToGcProto;
+import com.android.server.am.StickyBroadcastProto;
+import com.android.server.firewall.IntentFirewall;
+import com.android.server.job.JobSchedulerInternal;
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.utils.PriorityDump;
+import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.PinnedStackWindowController;
+import com.android.server.wm.WindowManagerService;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
-import dalvik.system.VMRuntime;
+public class ActivityManagerService extends IActivityManager.Stub
+ implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
-import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-import static android.content.pm.PackageManager.GET_PROVIDERS;
-import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
-import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
-import static android.os.Process.PROC_CHAR;
-import static android.os.Process.PROC_OUT_LONG;
-import static android.os.Process.PROC_PARENS;
-import static android.os.Process.PROC_SPACE_TERM;
-import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
-import static android.provider.Settings.Global.DEBUG_APP;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
-import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK;
-import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
-import static android.provider.Settings.System.FONT_SCALE;
-import static com.android.internal.util.XmlUtils.readBooleanAttribute;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
-import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
-import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
-import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
-import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.ActivityStackSupervisor.RESTORE_FROM_RECENTS;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
-import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
-import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
-import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
-import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
-
-public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
+ /**
+ * Priority we boost main thread and RT of top app to.
+ */
+ public static final int TOP_APP_PRIORITY_BOOST = -10;
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
- private static final String TAG_LOCKSCREEN = TAG + POSTFIX_LOCKSCREEN;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_LRU = TAG + POSTFIX_LRU;
private static final String TAG_MU = TAG + POSTFIX_MU;
+ private static final String TAG_NETWORK = TAG + POSTFIX_NETWORK;
private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
private static final String TAG_POWER = TAG + POSTFIX_POWER;
private static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
- private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
// Mock "pretend we're idle now" broadcast action to the job scheduler; declared
// here so that while the job scheduler can depend on AMS, the other way around
static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
+ // Maximum number of receivers an app can register.
+ private static final int MAX_RECEIVERS_ALLOWED_PER_APP = 1000;
// Amount of time after a call to stopAppSwitches() during which we will
// prevent further untrusted switches from happening.
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
- // How long we will retain processes hosting content providers in the "last activity"
- // state before allowing them to drop down to the regular cached LRU list. This is
- // to avoid thrashing of provider processes under low memory situations.
- static final int CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
+ /**
+ * How long we wait for an provider to be published. Should be longer than
+ * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
+ */
+ static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
// could take much longer than usual.
static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
- // How long to wait after going idle before forcing apps to GC.
- static final int GC_TIMEOUT = 5*1000;
-
- // The minimum amount of time between successive GC requests for a process.
- static final int GC_MIN_INTERVAL = 60*1000;
-
- // The minimum amount of time between successive PSS requests for a process.
- static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
-
- // The minimum amount of time between successive PSS requests for a process
- // when the request is due to the memory state being lowered.
- static final int FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
-
- // The rate at which we check for apps using excessive power -- 15 mins.
- static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
-
- // The minimum sample duration we will allow before deciding we have
- // enough data on wake locks to start killing things.
- static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
-
- // The minimum sample duration we will allow before deciding we have
- // enough data on CPU usage to start killing things.
- static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
-
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
// How long we wait until we timeout on key dispatching during instrumentation.
static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
- // This is the amount of time an app needs to be running a foreground service before
- // we will consider it to be doing interaction for usage stats.
- static final int SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
-
- // Maximum amount of time we will allow to elapse before re-reporting usage stats
- // interaction with foreground processes.
- static final long USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
-
- // This is the amount of time we allow an app to settle after it goes into the background,
- // before we start restricting what it can do.
- static final int BACKGROUND_SETTLE_TIME = 1*60*1000;
+ // Disable hidden API checks for the newly started instrumentation.
+ // Must be kept in sync with Am.
+ private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
// How long to wait in getAssistContextExtras for the activity and foreground services
// to respond with the result.
// on getting this result before starting to launch its UI).
static final int PENDING_ASSIST_EXTRAS_LONG_TIMEOUT = 2000;
+ // How long to wait in getAutofillAssistStructure() for the activity to respond with the result.
+ static final int PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT = 2000;
+
// Maximum number of persisted Uri grants a package is allowed
static final int MAX_PERSISTED_URI_GRANTS = 128;
- static final int MY_PID = Process.myPid();
+ static final int MY_PID = myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
// as one line, but close enough for now.
static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100;
+ /** If a UID observer takes more than this long, send a WTF. */
+ private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
+
// Access modes for handleIncomingUser.
static final int ALLOW_NON_FULL = 0;
static final int ALLOW_NON_FULL_IN_PROFILE = 1;
static final int ALLOW_FULL_ONLY = 2;
- // Delay in notifying task stack change listeners (in millis)
- static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
-
// Necessary ApplicationInfo flags to mark an app as persistent
private static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
// Intent sent when remote bugreport collection has been completed
private static final String INTENT_REMOTE_BUGREPORT_FINISHED =
- "android.intent.action.REMOTE_BUGREPORT_FINISHED";
+ "com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED";
- // Delay to disable app launch boost
- static final int APP_BOOST_MESSAGE_DELAY = 3000;
- // Lower delay than APP_BOOST_MESSAGE_DELAY to disable the boost
- static final int APP_BOOST_TIMEOUT = 2500;
-
- // Used to indicate that a task is removed it should also be removed from recents.
- private static final boolean REMOVE_FROM_RECENTS = true;
// Used to indicate that an app transition should be animated.
static final boolean ANIMATE = true;
// Determines whether to take full screen screenshots
static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
- public static final float FULLSCREEN_SCREENSHOT_SCALE = 0.6f;
- private static native int nativeMigrateToBoost();
- private static native int nativeMigrateFromBoost();
- private boolean mIsBoosted = false;
- private long mBoostStartTime = 0;
+ /**
+ * Default value for {@link Settings.Global#NETWORK_ACCESS_TIMEOUT_MS}.
+ */
+ private static final long NETWORK_ACCESS_TIMEOUT_DEFAULT_MS = 200; // 0.2 sec
+
+ /**
+ * State indicating that there is no need for any blocking for network.
+ */
+ @VisibleForTesting
+ static final int NETWORK_STATE_NO_CHANGE = 0;
+
+ /**
+ * State indicating that the main thread needs to be informed about the network wait.
+ */
+ @VisibleForTesting
+ static final int NETWORK_STATE_BLOCK = 1;
+
+ /**
+ * State indicating that any threads waiting for network state to get updated can be unblocked.
+ */
+ @VisibleForTesting
+ static final int NETWORK_STATE_UNBLOCK = 2;
+
+ // Max character limit for a notification title. If the notification title is larger than this
+ // the notification will not be legible to the user.
+ private static final int MAX_BUGREPORT_TITLE_SIZE = 50;
+
+ private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
/** All system services */
SystemServiceManager mSystemServiceManager;
+ // Wrapper around VoiceInteractionServiceManager
+ private AssistUtils mAssistUtils;
+
+ // Keeps track of the active voice interaction service component, notified from
+ // VoiceInteractionManagerService
+ ComponentName mActiveVoiceInteractionServiceComponent;
+
private Installer mInstaller;
/** Run all ActivityStacks through this */
final ActivityStackSupervisor mStackSupervisor;
+ private final KeyguardController mKeyguardController;
- final ActivityStarter mActivityStarter;
+ private final ActivityStartController mActivityStartController;
- /** Task stack change listeners. */
- private final RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
- new RemoteCallbackList<ITaskStackListener>();
+ private final ClientLifecycleManager mLifecycleManager;
+
+ final TaskChangeNotificationController mTaskChangeNotificationController;
final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
- public IntentFirewall mIntentFirewall;
+ final ArrayList<ActiveInstrumentation> mActiveInstrumentation = new ArrayList<>();
+
+ public final IntentFirewall mIntentFirewall;
// Whether we should show our dialogs (ANR, crash, etc) or just perform their
- // default actuion automatically. Important for devices without direct input
+ // default action automatically. Important for devices without direct input
// devices.
private boolean mShowDialogs = true;
- private boolean mInVrMode = false;
+
+ private final VrController mVrController;
+
+ // VR Vr2d Display Id.
+ int mVr2dDisplayId = INVALID_DISPLAY;
// Whether we should use SCHED_FIFO for UI and RenderThreads.
private boolean mUseFifoUiScheduling = false;
+ private static final String SYSUI_COMPONENT_NAME = "com.android.systemui/.SystemUIService";
+
BroadcastQueue mFgBroadcastQueue;
BroadcastQueue mBgBroadcastQueue;
// Convenient for easy iteration over the queues. Foreground is first
}
/**
- * Activity we have told the window manager to have key focus.
+ * The last resumed activity. This is identical to the current resumed activity most
+ * of the time but could be different when we're pausing one activity before we resume
+ * another activity.
*/
- ActivityRecord mFocusedActivity = null;
+ private ActivityRecord mLastResumedActivity;
/**
- * User id of the last activity mFocusedActivity was set to.
+ * The activity that is currently being traced as the active resumed activity.
+ *
+ * @see #updateResumedAppTrace
*/
- private int mLastFocusedUserId;
+ private @Nullable ActivityRecord mTracedResumedActivity;
/**
* If non-null, we are tracking the time the user spends in the currently focused app.
/**
* List of intents that were used to start the most recent tasks.
*/
- final RecentTasks mRecentTasks;
+ private final RecentTasks mRecentTasks;
/**
- * For addAppTask: cached of the last activity component that was added.
+ * The package name of the DeviceOwner. This package is not permitted to have its data cleared.
*/
- ComponentName mLastAddedTaskComponent;
+ String mDeviceOwnerName;
/**
- * For addAppTask: cached of the last activity uid that was added.
+ * The controller for all operations related to locktask.
*/
- int mLastAddedTaskUid;
+ private final LockTaskController mLockTaskController;
+
+ final UserController mUserController;
/**
- * For addAppTask: cached of the last ActivityInfo that was added.
+ * Packages that are being allowed to perform unrestricted app switches. Mapping is
+ * User -> Type -> uid.
*/
- ActivityInfo mLastAddedTaskActivity;
+ final SparseArray<ArrayMap<String, Integer>> mAllowAppSwitchUids = new SparseArray<>();
+
+ final AppErrors mAppErrors;
+
+ final AppWarnings mAppWarnings;
/**
- * List of packages whitelisted by DevicePolicyManager for locktask. Indexed by userId.
+ * Dump of the activity state at the time of the last ANR. Cleared after
+ * {@link WindowManagerService#LAST_ANR_LIFETIME_DURATION_MSECS}
*/
- SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
+ String mLastANRState;
/**
- * The package name of the DeviceOwner. This package is not permitted to have its data cleared.
+ * Indicates the maximum time spent waiting for the network rules to get updated.
*/
- String mDeviceOwnerName;
+ @VisibleForTesting
+ long mWaitForNetworkTimeoutMs;
- final UserController mUserController;
+ /** Total # of UID change events dispatched, shown in dumpsys. */
+ int mUidChangeDispatchCount;
- final AppErrors mAppErrors;
+ /**
+ * Helper class which strips out priority and proto arguments then calls the dump function with
+ * the appropriate arguments. If priority arguments are omitted, function calls the legacy
+ * dump command.
+ * If priority arguments are omitted all sections are dumped, otherwise sections are dumped
+ * according to their priority.
+ */
+ private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args,
+ boolean asProto) {
+ if (asProto) return;
+ doDump(fd, pw, new String[]{"activities"}, asProto);
+ doDump(fd, pw, new String[]{"service", SYSUI_COMPONENT_NAME}, asProto);
+ }
+
+ @Override
+ public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+ doDump(fd, pw, new String[]{"-a", "--normal-priority"}, asProto);
+ }
- boolean mDoingSetFocusedActivity;
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+ doDump(fd, pw, args, asProto);
+ }
+ };
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown
- && mLockScreenShown != LOCK_SCREEN_SHOWN;
- }
-
- private static final class PriorityState {
- // Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
- // the current thread is currently in. When it drops down to zero, we will no longer boost
- // the thread's priority.
- private int regionCounter = 0;
-
- // The thread's previous priority before boosting.
- private int prevPriority = Integer.MIN_VALUE;
+ && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY)
+ && !mUserController.hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
+ mUserController.getCurrentUserId())
+ && !(UserManager.isDeviceInDemoMode(mContext)
+ && mUserController.getCurrentUser().isDemo());
}
- static ThreadLocal<PriorityState> sThreadPriorityState = new ThreadLocal<PriorityState>() {
- @Override protected PriorityState initialValue() {
- return new PriorityState();
- }
- };
+ private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster(
+ THREAD_PRIORITY_FOREGROUND, LockGuard.INDEX_ACTIVITY);
static void boostPriorityForLockedSection() {
- int tid = Process.myTid();
- int prevPriority = Process.getThreadPriority(tid);
- PriorityState state = sThreadPriorityState.get();
- if (state.regionCounter == 0 && prevPriority > -2) {
- state.prevPriority = prevPriority;
- Process.setThreadPriority(tid, -2);
- }
- state.regionCounter++;
+ sThreadPriorityBooster.boost();
}
static void resetPriorityAfterLockedSection() {
- PriorityState state = sThreadPriorityState.get();
- state.regionCounter--;
- if (state.regionCounter == 0 && state.prevPriority > -2) {
- Process.setThreadPriority(Process.myTid(), state.prevPriority);
- }
+ sThreadPriorityBooster.reset();
}
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
+ public boolean isHome;
public final Bundle extras;
public final Intent intent;
public final String hint;
- public final IResultReceiver receiver;
+ public final IAssistDataReceiver receiver;
public final int userHandle;
public boolean haveResult = false;
public Bundle result = null;
public Bundle receiverExtras;
public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
- String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
+ String _hint, IAssistDataReceiver _receiver, Bundle _receiverExtras,
+ int _userHandle) {
activity = _activity;
extras = _extras;
intent = _intent;
receiverExtras = _receiverExtras;
userHandle = _userHandle;
}
+
@Override
public void run() {
Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity);
}
}
- final ArrayList<PendingAssistExtras> mPendingAssistExtras
- = new ArrayList<PendingAssistExtras>();
+ final ArrayList<PendingAssistExtras> mPendingAssistExtras = new ArrayList<>();
/**
* Process management.
ProcessRecord mHeavyWeightProcess = null;
/**
+ * Non-persistent appId whitelist for background restrictions
+ */
+ int[] mBackgroundAppIdWhitelist = new int[] {
+ BLUETOOTH_UID
+ };
+
+ /**
+ * Broadcast actions that will always be deliverable to unlaunched/background apps
+ */
+ ArraySet<String> mBackgroundLaunchBroadcasts;
+
+ /**
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
/**
- * All of the processes that have been forced to be foreground. The key
+ * All of the processes that have been forced to be important. The key
* is the pid of the caller who requested it (we hold a death
* link on it).
*/
- abstract class ForegroundToken implements IBinder.DeathRecipient {
- int pid;
- IBinder token;
+ abstract class ImportanceToken implements IBinder.DeathRecipient {
+ final int pid;
+ final IBinder token;
+ final String reason;
+
+ ImportanceToken(int _pid, IBinder _token, String _reason) {
+ pid = _pid;
+ token = _token;
+ reason = _reason;
+ }
+
+ @Override
+ public String toString() {
+ return "ImportanceToken { " + Integer.toHexString(System.identityHashCode(this))
+ + " " + reason + " " + pid + " " + token + " }";
+ }
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long pToken = proto.start(fieldId);
+ proto.write(ImportanceTokenProto.PID, pid);
+ if (token != null) {
+ proto.write(ImportanceTokenProto.TOKEN, token.toString());
+ }
+ proto.write(ImportanceTokenProto.REASON, reason);
+ proto.end(pToken);
+ }
}
- final SparseArray<ForegroundToken> mForegroundProcesses = new SparseArray<ForegroundToken>();
+ final SparseArray<ImportanceToken> mImportantProcesses = new SparseArray<ImportanceToken>();
/**
* List of records for processes that someone had tried to start before the
private static final int MAX_DUP_SUPPRESSED_STACKS = 5000;
/**
- * Strict Mode background batched logging state.
- *
- * The string buffer is guarded by itself, and its lock is also
- * used to determine if another batched write is already
- * in-flight.
- */
- private final StringBuilder mStrictModeBuffer = new StringBuilder();
-
- /**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
@Override
public String toString() {
- String result = Integer.toString(sourceUserId) + " @ " + uri.toString();
+ String result = uri.toString() + " [user " + sourceUserId + "]";
if (prefix) result += " [prefix]";
return result;
}
public String toSafeString() {
- String result = Integer.toString(sourceUserId) + " @ " + uri.toSafeString();
+ String result = uri.toSafeString() + " [user " + sourceUserId + "]";
if (prefix) result += " [prefix]";
return result;
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(GrantUriProto.URI, uri.toString());
+ proto.write(GrantUriProto.SOURCE_USER_ID, sourceUserId);
+ proto.end(token);
+ }
+
public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) {
- return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
- ContentProvider.getUriWithoutUserId(uri), false);
+ if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
+ ContentProvider.getUriWithoutUserId(uri), false);
+ } else {
+ return new GrantUri(defaultSourceUserHandle, uri, false);
+ }
}
}
+ boolean mSystemProvidersInstalled;
+
CoreSettingsObserver mCoreSettingsObserver;
FontScaleSettingObserver mFontScaleSettingObserver;
private final class FontScaleSettingObserver extends ContentObserver {
private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
+ private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS);
public FontScaleSettingObserver() {
super(mHandler);
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(mFontScaleUri, false, this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(mHideErrorDialogsUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
if (mFontScaleUri.equals(uri)) {
updateFontScaleIfNeeded(userId);
+ } else if (mHideErrorDialogsUri.equals(uri)) {
+ synchronized (ActivityManagerService.this) {
+ updateShouldShowDialogsLocked(getGlobalConfiguration());
+ }
+ }
+ }
+ }
+
+ DevelopmentSettingsObserver mDevelopmentSettingsObserver;
+
+ private final class DevelopmentSettingsObserver extends ContentObserver {
+ private final Uri mUri = Settings.Global
+ .getUriFor(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
+
+ private final ComponentName mBugreportStorageProvider = new ComponentName(
+ "com.android.shell", "com.android.shell.BugreportStorageProvider");
+
+ public DevelopmentSettingsObserver() {
+ super(mHandler);
+ mContext.getContentResolver().registerContentObserver(mUri, false, this,
+ UserHandle.USER_ALL);
+ // Always kick once to ensure that we match current state
+ onChange();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
+ if (mUri.equals(uri)) {
+ onChange();
}
}
+
+ public void onChange() {
+ final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, Build.IS_ENG ? 1 : 0) != 0;
+ mContext.getPackageManager().setComponentEnabledSetting(mBugreportStorageProvider,
+ enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ 0);
+ }
}
/**
DeviceIdleController.LocalService mLocalDeviceIdleController;
/**
- * Information about and control over application operations
+ * Power-save whitelisted app-ids (not including except-idle-whitelisted ones).
*/
- final AppOpsService mAppOpsService;
+ int[] mDeviceIdleWhitelist = new int[0];
+
+ /**
+ * Power-save whitelisted app-ids (including except-idle-whitelisted ones).
+ */
+ int[] mDeviceIdleExceptIdleWhitelist = new int[0];
+
+ /**
+ * Set of app ids that are temporarily allowed to escape bg check due to high-pri message
+ */
+ int[] mDeviceIdleTempWhitelist = new int[0];
+
+ static final class PendingTempWhitelist {
+ final int targetUid;
+ final long duration;
+ final String tag;
+
+ PendingTempWhitelist(int _targetUid, long _duration, String _tag) {
+ targetUid = _targetUid;
+ duration = _duration;
+ tag = _tag;
+ }
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TAG, tag);
+ proto.end(token);
+ }
+ }
+
+ final SparseArray<PendingTempWhitelist> mPendingTempWhitelist = new SparseArray<>();
/**
- * Current configuration information. HistoryRecord objects are given
- * a reference to this object to indicate which configuration they are
- * currently running in, so this object must be kept immutable.
+ * Information about and control over application operations
*/
- Configuration mConfiguration = new Configuration();
+ final AppOpsService mAppOpsService;
+
+ /** Current sequencing integer of the configuration, for skipping old configurations. */
+ private int mConfigurationSeq;
/**
- * Current sequencing integer of the configuration, for skipping old
- * configurations.
+ * Temp object used when global and/or display override configuration is updated. It is also
+ * sent to outer world instead of {@link #getGlobalConfiguration} because we don't trust
+ * anyone...
*/
- int mConfigurationSeq = 0;
+ private Configuration mTempConfig = new Configuration();
+
+ private final UpdateConfigurationResult mTmpUpdateConfigurationResult =
+ new UpdateConfigurationResult();
+ private static final class UpdateConfigurationResult {
+ // Configuration changes that were updated.
+ int changes;
+ // If the activity was relaunched to match the new configuration.
+ boolean activityRelaunched;
+
+ void reset() {
+ changes = 0;
+ activityRelaunched = false;
+ }
+ }
- boolean mSuppressResizeConfigChanges = false;
+ boolean mSuppressResizeConfigChanges;
/**
* Hardware-reported OpenGLES version.
* List of initialization arguments to pass to all processes when binding applications to them.
* For example, references to the commonly used services.
*/
- HashMap<String, IBinder> mAppBindArgs;
- HashMap<String, IBinder> mIsolatedAppBindArgs;
+ ArrayMap<String, IBinder> mAppBindArgs;
+ ArrayMap<String, IBinder> mIsolatedAppBindArgs;
/**
* Temporary to avoid allocations. Protected by main lock.
@GuardedBy("this") boolean mCallFinishBooting = false;
@GuardedBy("this") boolean mBootAnimationComplete = false;
@GuardedBy("this") boolean mLaunchWarningShown = false;
- @GuardedBy("this") boolean mCheckedForSetup = false;
+ private @GuardedBy("this") boolean mCheckedForSetup = false;
+
+ final Context mContext;
- Context mContext;
+ /**
+ * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
+ * change at runtime. Use mContext for non-UI purposes.
+ */
+ final Context mUiContext;
/**
* The time at which we will allow normal application switches again,
boolean mDidAppSwitch;
/**
- * Last time (in realtime) at which we checked for power usage.
- */
- long mLastPowerCheckRealtime;
-
- /**
* Last time (in uptime) at which we checked for power usage.
*/
long mLastPowerCheckUptime;
* Set while we are running a voice interaction. This overrides
* sleeping while it is active.
*/
- private IVoiceInteractionSession mRunningVoice;
+ IVoiceInteractionSession mRunningVoice;
/**
* For some direct access we need to power manager.
private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
/**
- * A list of tokens that cause the top activity to be put to sleep.
- * They are used by components that may hide and block interaction with underlying
- * activities.
- */
- final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
-
- static final int LOCK_SCREEN_HIDDEN = 0;
- static final int LOCK_SCREEN_LEAVING = 1;
- static final int LOCK_SCREEN_SHOWN = 2;
- /**
- * State of external call telling us if the lock screen is shown.
+ * State of external calls telling us if the device is awake or asleep.
*/
- int mLockScreenShown = LOCK_SCREEN_HIDDEN;
+ private boolean mKeyguardShown = false;
/**
* Set if we are shutting down the system, similar to sleeping.
= new ProcessMap<ArrayList<ProcessRecord>>();
/**
- * This is set if we had to do a delayed dexopt of an app before launching
- * it, to increase the ANR timeouts in that case.
- */
- boolean mDidDexOpt;
-
- /**
* Set if the systemServer made a call to enterSafeMode.
*/
boolean mSafeMode;
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
- boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
+ /**
+ * Flag that indicates if multi-window is enabled.
+ *
+ * For any particular form of multi-window to be enabled, generic multi-window must be enabled
+ * in {@link com.android.internal.R.bool#config_supportsMultiWindow} config or
+ * {@link Settings.Global#DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES} development option set.
+ * At least one of the forms of multi-window must be enabled in order for this flag to be
+ * initialized to 'true'.
+ *
+ * @see #mSupportsSplitScreenMultiWindow
+ * @see #mSupportsFreeformWindowManagement
+ * @see #mSupportsPictureInPicture
+ * @see #mSupportsMultiDisplay
+ */
boolean mSupportsMultiWindow;
+ boolean mSupportsSplitScreenMultiWindow;
boolean mSupportsFreeformWindowManagement;
boolean mSupportsPictureInPicture;
+ boolean mSupportsMultiDisplay;
boolean mSupportsLeanbackOnly;
- Rect mDefaultPinnedStackBounds;
IActivityController mController = null;
boolean mControllerIsAMonkey = false;
String mProfileApp = null;
ProcessRecord mProfileProc = null;
- String mProfileFile;
- ParcelFileDescriptor mProfileFd;
- int mSamplingInterval = 0;
- boolean mAutoStopProfiler = false;
+ ProfilerInfo mProfilerInfo = null;
+
+ /**
+ * Stores a map of process name -> agent string. When a process is started and mAgentAppMap
+ * is not null, this map is checked and the mapped agent installed during bind-time. Note:
+ * A non-null agent in mProfileInfo overrides this.
+ */
+ private @Nullable Map<String, String> mAppAgentMap = null;
+
int mProfileType = 0;
final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
String mMemWatchDumpProcName;
String mTrackAllocationApp = null;
String mNativeDebuggingApp = null;
- final long[] mTmpLong = new long[2];
+ final long[] mTmpLong = new long[3];
+
+ private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
+
+ /**
+ * A global counter for generating sequence numbers.
+ * This value will be used when incrementing sequence numbers in individual uidRecords.
+ *
+ * Having a global counter ensures that seq numbers are monotonically increasing for a
+ * particular uid even when the uidRecord is re-created.
+ */
+ @GuardedBy("this")
+ @VisibleForTesting
+ long mProcStateSeqCounter = 0;
+
+ /**
+ * A global counter for generating sequence numbers to uniquely identify pending process starts.
+ */
+ @GuardedBy("this")
+ private long mProcStartSeqCounter = 0;
+
+ /**
+ * Contains {@link ProcessRecord} objects for pending process starts.
+ *
+ * Mapping: {@link #mProcStartSeqCounter} -> {@link ProcessRecord}
+ */
+ @GuardedBy("this")
+ private final LongSparseArray<ProcessRecord> mPendingStarts = new LongSparseArray<>();
+
+ private final Injector mInjector;
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
- static final int CHANGE_PROCESS_STATE = 1<<1;
int changes;
int uid;
int pid;
boolean foregroundActivities;
}
+ static final class UidObserverRegistration {
+ final int uid;
+ final String pkg;
+ final int which;
+ final int cutpoint;
+
+ /**
+ * Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}.
+ * We show it in dumpsys.
+ */
+ int mSlowDispatchCount;
+
+ /** Max time it took for each dispatch. */
+ int mMaxDispatchTime;
+
+ final SparseIntArray lastProcStates;
+
+ // Please keep the enum lists in sync
+ private static int[] ORIG_ENUMS = new int[]{
+ ActivityManager.UID_OBSERVER_IDLE,
+ ActivityManager.UID_OBSERVER_ACTIVE,
+ ActivityManager.UID_OBSERVER_GONE,
+ ActivityManager.UID_OBSERVER_PROCSTATE,
+ };
+ private static int[] PROTO_ENUMS = new int[]{
+ ActivityManagerProto.UID_OBSERVER_FLAG_IDLE,
+ ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE,
+ ActivityManagerProto.UID_OBSERVER_FLAG_GONE,
+ ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE,
+ };
+
+ UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) {
+ uid = _uid;
+ pkg = _pkg;
+ which = _which;
+ cutpoint = _cutpoint;
+ if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
+ lastProcStates = new SparseIntArray();
+ } else {
+ lastProcStates = null;
+ }
+ }
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(UidObserverRegistrationProto.UID, uid);
+ proto.write(UidObserverRegistrationProto.PACKAGE, pkg);
+ ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS,
+ which, ORIG_ENUMS, PROTO_ENUMS);
+ proto.write(UidObserverRegistrationProto.CUT_POINT, cutpoint);
+ if (lastProcStates != null) {
+ final int NI = lastProcStates.size();
+ for (int i=0; i<NI; i++) {
+ final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES);
+ proto.write(UidObserverRegistrationProto.ProcState.UID, lastProcStates.keyAt(i));
+ proto.write(UidObserverRegistrationProto.ProcState.STATE, lastProcStates.valueAt(i));
+ proto.end(pToken);
+ }
+ }
+ proto.end(token);
+ }
+ }
+
+ final List<ScreenObserver> mScreenObservers = new ArrayList<>();
+
final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>();
final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>();
+ OomAdjObserver mCurOomAdjObserver;
+ int mCurOomAdjUid;
+
+ interface OomAdjObserver {
+ void onOomAdjMessage(String msg);
+ }
+
/**
* Runtime CPU use collection thread. This object's lock is used to
* perform synchronization with the thread (notifying it to run).
MONITOR_THREAD_CPU_USAGE);
final AtomicLong mLastCpuTime = new AtomicLong(0);
final AtomicBoolean mProcessCpuMutexFree = new AtomicBoolean(true);
+ final CountDownLatch mProcessCpuInitLatch = new CountDownLatch(1);
long mLastWriteTime = 0;
*/
boolean mBooted = false;
- int mProcessLimit = ProcessList.MAX_CACHED_APPS;
- int mProcessLimitOverride = -1;
+ /**
+ * Current boot phase.
+ */
+ int mBootPhase;
WindowManagerService mWindowManager;
final ActivityThread mSystemThread;
static final int SHOW_UID_ERROR_UI_MSG = 14;
static final int SHOW_FINGERPRINT_ERROR_UI_MSG = 15;
static final int PROC_START_TIMEOUT_MSG = 20;
- static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
static final int FINALIZE_PENDING_INTENT_MSG = 23;
static final int POST_HEAVY_NOTIFICATION_MSG = 24;
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26;
- static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
+ static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27;
static final int CLEAR_DNS_CACHE_MSG = 28;
static final int UPDATE_HTTP_PROXY_MSG = 29;
static final int SHOW_COMPAT_MODE_DIALOG_UI_MSG = 30;
static final int DISPATCH_PROCESSES_CHANGED_UI_MSG = 31;
static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
static final int REPORT_MEM_USAGE_MSG = 33;
- static final int REPORT_USER_SWITCH_MSG = 34;
- static final int CONTINUE_USER_SWITCH_MSG = 35;
- static final int USER_SWITCH_TIMEOUT_MSG = 36;
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
static final int PERSIST_URI_GRANTS_MSG = 38;
- static final int REQUEST_ALL_PSS_MSG = 39;
- static final int START_PROFILES_MSG = 40;
- static final int UPDATE_TIME = 41;
- static final int SYSTEM_USER_START_MSG = 42;
- static final int SYSTEM_USER_CURRENT_MSG = 43;
+ static final int UPDATE_TIME_PREFERENCE_MSG = 41;
static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
static final int FINISH_BOOTING_MSG = 45;
- static final int START_USER_SWITCH_UI_MSG = 46;
static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
static final int DISMISS_DIALOG_UI_MSG = 48;
- static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;
- static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;
- static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
- static final int DELETE_DUMPHEAP_MSG = 52;
- static final int FOREGROUND_PROFILE_CHANGED_MSG = 53;
- static final int DISPATCH_UIDS_CHANGED_UI_MSG = 54;
- static final int REPORT_TIME_TRACKER_MSG = 55;
- static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
- static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
- static final int APP_BOOST_DEACTIVATE_MSG = 58;
- static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
- static final int IDLE_UIDS_MSG = 60;
- static final int SYSTEM_USER_UNLOCK_MSG = 61;
- static final int LOG_STACK_STATE = 62;
- static final int VR_MODE_CHANGE_MSG = 63;
- static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
- static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 65;
- static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
- static final int NOTIFY_FORCED_RESIZABLE_MSG = 67;
- static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68;
- static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 69;
- static final int NOTIFY_VR_SLEEPING_MSG = 70;
+ static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49;
+ static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50;
+ static final int DELETE_DUMPHEAP_MSG = 51;
+ static final int DISPATCH_UIDS_CHANGED_UI_MSG = 53;
+ static final int REPORT_TIME_TRACKER_MSG = 54;
+ static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 56;
+ static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 57;
+ static final int IDLE_UIDS_MSG = 58;
+ static final int LOG_STACK_STATE = 60;
+ static final int VR_MODE_CHANGE_MSG = 61;
+ static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63;
+ static final int DISPATCH_SCREEN_AWAKE_MSG = 64;
+ static final int DISPATCH_SCREEN_KEYGUARD_MSG = 65;
+ static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
+ static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
+ static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
+ static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
+ static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
static final int FIRST_COMPAT_MODE_MSG = 300;
static final int FIRST_SUPERVISOR_STACK_MSG = 100;
+ static final String SERVICE_RECORD_KEY = "servicerecord";
+
static ServiceThread sKillThread = null;
static KillHandler sKillHandler = null;
CompatModeDialog mCompatModeDialog;
- UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog;
long mLastMemUsageReportTime = 0;
/**
*/
private boolean mUserIsMonkey;
- /** Flag whether the device has a Recents UI */
- boolean mHasRecents;
-
/** The dimensions of the thumbnails in the Recents UI. */
int mThumbnailWidth;
int mThumbnailHeight;
final ServiceThread mHandlerThread;
final MainHandler mHandler;
- final UiHandler mUiHandler;
+ final Handler mUiHandler;
+ final ServiceThread mProcStartHandlerThread;
+ final Handler mProcStartHandler;
+
+ final ActivityManagerConstants mConstants;
+
+ // Encapsulates the global setting "hidden_api_blacklist_exemptions"
+ final HiddenApiSettings mHiddenApiBlacklist;
PackageManagerInternal mPackageManagerInt;
final boolean mPermissionReviewRequired;
+ boolean mHasHeavyWeightFeature;
+
+ /**
+ * Whether to force background check on all apps (for battery saver) or not.
+ */
+ boolean mForceBackgroundCheck;
+
+ private static String sTheRealBuildSerial = Build.UNKNOWN;
+
+ /**
+ * Current global configuration information. Contains general settings for the entire system,
+ * also corresponds to the merged configuration of the default display.
+ */
+ Configuration getGlobalConfiguration() {
+ return mStackSupervisor.getConfiguration();
+ }
+
final class KillHandler extends Handler {
static final int KILL_PROCESS_GROUP_MSG = 4000;
}
AppErrorResult res = (AppErrorResult) data.get("result");
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new StrictModeViolationDialog(mContext,
+ Dialog d = new StrictModeViolationDialog(mUiContext,
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
} break;
case SHOW_FACTORY_ERROR_UI_MSG: {
Dialog d = new FactoryErrorDialog(
- mContext, msg.getData().getCharSequence("msg"));
+ mUiContext, msg.getData().getCharSequence("msg"));
d.show();
ensureBootCompleted();
} break;
if (!app.waitedForDebugger) {
Dialog d = new AppWaitingForDebuggerDialog(
ActivityManagerService.this,
- mContext, app);
+ mUiContext, app);
app.waitDialog = d;
app.waitedForDebugger = true;
d.show();
} break;
case SHOW_UID_ERROR_UI_MSG: {
if (mShowDialogs) {
- AlertDialog d = new BaseErrorDialog(mContext);
+ AlertDialog d = new BaseErrorDialog(mUiContext);
d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
d.setCancelable(false);
- d.setTitle(mContext.getText(R.string.android_system_label));
- d.setMessage(mContext.getText(R.string.system_error_wipe_data));
- d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+ d.setTitle(mUiContext.getText(R.string.android_system_label));
+ d.setMessage(mUiContext.getText(R.string.system_error_wipe_data));
+ d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok),
obtainMessage(DISMISS_DIALOG_UI_MSG, d));
d.show();
}
} break;
case SHOW_FINGERPRINT_ERROR_UI_MSG: {
if (mShowDialogs) {
- AlertDialog d = new BaseErrorDialog(mContext);
+ AlertDialog d = new BaseErrorDialog(mUiContext);
d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
d.setCancelable(false);
- d.setTitle(mContext.getText(R.string.android_system_label));
- d.setMessage(mContext.getText(R.string.system_error_manufacturer));
- d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+ d.setTitle(mUiContext.getText(R.string.android_system_label));
+ d.setMessage(mUiContext.getText(R.string.system_error_manufacturer));
+ d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.ok),
obtainMessage(DISMISS_DIALOG_UI_MSG, d));
d.show();
}
if (mode == ActivityManager.COMPAT_MODE_DISABLED
|| mode == ActivityManager.COMPAT_MODE_ENABLED) {
mCompatModeDialog = new CompatModeDialog(
- ActivityManagerService.this, mContext,
+ ActivityManagerService.this, mUiContext,
ar.info.applicationInfo);
mCompatModeDialog.show();
}
}
break;
}
- case SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG: {
- synchronized (ActivityManagerService.this) {
- final ActivityRecord ar = (ActivityRecord) msg.obj;
- if (mUnsupportedDisplaySizeDialog != null) {
- mUnsupportedDisplaySizeDialog.dismiss();
- mUnsupportedDisplaySizeDialog = null;
- }
- if (ar != null && mCompatModePackages.getPackageNotifyUnsupportedZoomLocked(
- ar.packageName)) {
- mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog(
- ActivityManagerService.this, mContext, ar.info.applicationInfo);
- mUnsupportedDisplaySizeDialog.show();
- }
- }
- break;
- }
- case START_USER_SWITCH_UI_MSG: {
- mUserController.showUserSwitchDialog((Pair<UserInfo, UserInfo>) msg.obj);
- break;
- }
case DISMISS_DIALOG_UI_MSG: {
final Dialog d = (Dialog) msg.obj;
d.dismiss();
case DISPATCH_UIDS_CHANGED_UI_MSG: {
dispatchUidsChanged();
} break;
+ case DISPATCH_OOM_ADJ_OBSERVER_MSG: {
+ dispatchOomAdjObserver((String)msg.obj);
+ } break;
+ case PUSH_TEMP_WHITELIST_UI_MSG: {
+ pushTempWhitelist();
+ } break;
}
}
}
}
} break;
case SERVICE_TIMEOUT_MSG: {
- if (mDidDexOpt) {
- mDidDexOpt = false;
- Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
- nmsg.obj = msg.obj;
- mHandler.sendMessageDelayed(nmsg, ActiveServices.SERVICE_TIMEOUT);
- return;
- }
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
- case UPDATE_TIME_ZONE: {
+ case SERVICE_FOREGROUND_TIMEOUT_MSG: {
+ mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
+ } break;
+ case SERVICE_FOREGROUND_CRASH_MSG: {
+ mServices.serviceForegroundCrash(
+ (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
+ } break;
+ case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
+ RemoteCallbackList<IResultReceiver> callbacks
+ = (RemoteCallbackList<IResultReceiver>)msg.obj;
+ int N = callbacks.beginBroadcast();
+ for (int i = 0; i < N; i++) {
+ try {
+ callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
+ } catch (RemoteException e) {
+ }
+ }
+ callbacks.finishBroadcast();
+ // We have to clean up the RemoteCallbackList here, because otherwise it will
+ // needlessly hold the enclosed callbacks until the remote process dies.
+ callbacks.kill();
+ } break;
+ case UPDATE_TIME_ZONE: {
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
- if (r.thread != null) {
+ // Don't dispatch to isolated processes as they can't access
+ // ConnectivityManager and don't have network privileges anyway.
+ if (r.thread != null && !r.isolated) {
try {
r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
} catch (RemoteException ex) {
}
} break;
case PROC_START_TIMEOUT_MSG: {
- if (mDidDexOpt) {
- mDidDexOpt = false;
- Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- nmsg.obj = msg.obj;
- mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
- return;
- }
ProcessRecord app = (ProcessRecord)msg.obj;
synchronized (ActivityManagerService.this) {
processStartTimedOutLocked(app);
processContentProviderPublishTimedOutLocked(app);
}
} break;
- case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
- synchronized (ActivityManagerService.this) {
- mActivityStarter.doPendingActivityLaunchesLocked(true);
- }
- } break;
case KILL_APPLICATION_MSG: {
synchronized (ActivityManagerService.this) {
final int appId = msg.arg1;
Context context = mContext.createPackageContext(process.info.packageName, 0);
String text = mContext.getString(R.string.heavy_weight_notification,
context.getApplicationInfo().loadLabel(context.getPackageManager()));
- Notification notification = new Notification.Builder(context)
+ Notification notification =
+ new Notification.Builder(context,
+ SystemNotificationChannels.HEAVY_WEIGHT_APP)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
new UserHandle(root.userId)))
.build();
try {
- int[] outId = new int[1];
inm.enqueueNotificationWithTag("android", "android", null,
- R.string.heavy_weight_notification,
- notification, outId, root.userId);
+ SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION,
+ notification, root.userId);
} catch (RuntimeException e) {
Slog.w(ActivityManagerService.TAG,
"Error showing notification for heavy-weight app", e);
}
try {
inm.cancelNotificationWithTag("android", null,
- R.string.heavy_weight_notification, msg.arg1);
+ SystemMessage.NOTE_HEAVY_WEIGHT_NOTIFICATION, msg.arg1);
} catch (RuntimeException e) {
Slog.w(ActivityManagerService.TAG,
"Error canceling notification for service", e);
} catch (RemoteException e) {
}
} break;
- case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: {
+ case CHECK_EXCESSIVE_POWER_USE_MSG: {
synchronized (ActivityManagerService.this) {
- checkExcessivePowerUsageLocked(true);
- removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+ checkExcessivePowerUsageLocked();
+ removeMessages(CHECK_EXCESSIVE_POWER_USE_MSG);
+ Message nmsg = obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
+ sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
}
} break;
case REPORT_MEM_USAGE_MSG: {
thread.start();
break;
}
- case REPORT_USER_SWITCH_MSG: {
- mUserController.dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
- break;
- }
- case CONTINUE_USER_SWITCH_MSG: {
- mUserController.continueUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
- break;
- }
- case USER_SWITCH_TIMEOUT_MSG: {
- mUserController.timeoutUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
- break;
- }
case IMMERSIVE_MODE_LOCK_MSG: {
final boolean nextState = (msg.arg1 != 0);
if (mUpdateLock.isHeld() != nextState) {
writeGrantedUriPermissions();
break;
}
- case REQUEST_ALL_PSS_MSG: {
- synchronized (ActivityManagerService.this) {
- requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
- }
- break;
- }
- case START_PROFILES_MSG: {
- synchronized (ActivityManagerService.this) {
- mUserController.startProfilesLocked();
- }
- break;
- }
- case UPDATE_TIME: {
+ case UPDATE_TIME_PREFERENCE_MSG: {
+ // The user's time format preference might have changed.
+ // For convenience we re-use the Intent extra values.
synchronized (ActivityManagerService.this) {
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r.thread != null) {
try {
- r.thread.updateTimePrefs(msg.arg1 == 0 ? false : true);
+ r.thread.updateTimePrefs(msg.arg1);
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed to update preferences for: " + r.info.processName);
+ Slog.w(TAG, "Failed to update preferences for: "
+ + r.info.processName);
}
}
}
}
break;
}
- case SYSTEM_USER_START_MSG: {
- mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
- Integer.toString(msg.arg1), msg.arg1);
- mSystemServiceManager.startUser(msg.arg1);
- break;
- }
- case SYSTEM_USER_UNLOCK_MSG: {
- final int userId = msg.arg1;
- mSystemServiceManager.unlockUser(userId);
- synchronized (ActivityManagerService.this) {
- mRecentTasks.loadUserRecentsLocked(userId);
- }
- if (userId == UserHandle.USER_SYSTEM) {
- startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- }
- installEncryptionUnawareProviders(userId);
- mUserController.finishUserUnlocked((UserState) msg.obj);
- break;
- }
- case SYSTEM_USER_CURRENT_MSG: {
- mBatteryStatsService.noteEvent(
- BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH,
- Integer.toString(msg.arg2), msg.arg2);
- mBatteryStatsService.noteEvent(
- BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
- Integer.toString(msg.arg1), msg.arg1);
- mSystemServiceManager.switchUser(msg.arg1);
- break;
- }
case ENTER_ANIMATION_COMPLETE_MSG: {
synchronized (ActivityManagerService.this) {
ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
try {
Locale l = (Locale) msg.obj;
IBinder service = ServiceManager.getService("mount");
- IMountService mountService = IMountService.Stub.asInterface(service);
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
- mountService.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
+ storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
} catch (RemoteException e) {
Log.e(TAG, "Error storing locale for decryption UI", e);
}
break;
}
- case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
- synchronized (ActivityManagerService.this) {
- for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
- try {
- // Make a one-way callback to the listener
- mTaskStackListeners.getBroadcastItem(i).onTaskStackChanged();
- } catch (RemoteException e){
- // Handled by the RemoteCallbackList
- }
- }
- mTaskStackListeners.finishBroadcast();
- }
- break;
- }
- case NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG: {
- synchronized (ActivityManagerService.this) {
- for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
- try {
- // Make a one-way callback to the listener
- mTaskStackListeners.getBroadcastItem(i).onActivityPinned();
- } catch (RemoteException e){
- // Handled by the RemoteCallbackList
- }
- }
- mTaskStackListeners.finishBroadcast();
- }
- break;
- }
- case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG: {
- synchronized (ActivityManagerService.this) {
- for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
- try {
- // Make a one-way callback to the listener
- mTaskStackListeners.getBroadcastItem(i).onPinnedActivityRestartAttempt();
- } catch (RemoteException e){
- // Handled by the RemoteCallbackList
- }
- }
- mTaskStackListeners.finishBroadcast();
- }
- break;
- }
- case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG: {
- synchronized (ActivityManagerService.this) {
- for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
- try {
- // Make a one-way callback to the listener
- mTaskStackListeners.getBroadcastItem(i).onPinnedStackAnimationEnded();
- } catch (RemoteException e){
- // Handled by the RemoteCallbackList
- }
- }
- mTaskStackListeners.finishBroadcast();
- }
- break;
- }
- case NOTIFY_FORCED_RESIZABLE_MSG: {
- synchronized (ActivityManagerService.this) {
- for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
- try {
- // Make a one-way callback to the listener
- mTaskStackListeners.getBroadcastItem(i).onActivityForcedResizable(
- (String) msg.obj, msg.arg1);
- } catch (RemoteException e){
- // Handled by the RemoteCallbackList
- }
- }
- mTaskStackListeners.finishBroadcast();
- }
- break;
- }
- case NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG: {
- synchronized (ActivityManagerService.this) {
- for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
- try {
- // Make a one-way callback to the listener
- mTaskStackListeners.getBroadcastItem(i)
- .onActivityDismissingDockedStack();
- } catch (RemoteException e){
- // Handled by the RemoteCallbackList
- }
- }
- mTaskStackListeners.finishBroadcast();
- }
- break;
- }
case NOTIFY_CLEARTEXT_NETWORK_MSG: {
final int uid = msg.arg1;
final byte[] firstPacket = (byte[]) msg.obj;
intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
}
int userId = UserHandle.getUserId(uid);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.build();
try {
- int[] outId = new int[1];
inm.enqueueNotificationWithTag("android", "android", null,
- R.string.dump_heap_notification,
- notification, outId, userId);
+ SystemMessage.NOTE_DUMP_HEAP_NOTIFICATION,
+ notification, userId);
} catch (RuntimeException e) {
Slog.w(ActivityManagerService.TAG,
"Error showing notification for dump heap", e);
} break;
case DELETE_DUMPHEAP_MSG: {
revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(),
- DumpHeapActivity.JAVA_URI,
+ null, DumpHeapActivity.JAVA_URI,
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
UserHandle.myUserId());
mMemWatchDumpUid = -1;
}
} break;
- case FOREGROUND_PROFILE_CHANGED_MSG: {
- mUserController.dispatchForegroundProfileChanged(msg.arg1);
- } break;
case REPORT_TIME_TRACKER_MSG: {
AppTimeTracker tracker = (AppTimeTracker)msg.obj;
tracker.deliverResult(mContext);
} break;
- case REPORT_USER_SWITCH_COMPLETE_MSG: {
- mUserController.dispatchUserSwitchComplete(msg.arg1);
- } break;
case SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG: {
IUiAutomationConnection connection = (IUiAutomationConnection) msg.obj;
try {
// it is finished we make sure it is reset to its default.
mUserIsMonkey = false;
} break;
- case APP_BOOST_DEACTIVATE_MSG: {
- synchronized(ActivityManagerService.this) {
- if (mIsBoosted) {
- if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) {
- nativeMigrateFromBoost();
- mIsBoosted = false;
- mBoostStartTime = 0;
- } else {
- Message newmsg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
- mHandler.sendMessageDelayed(newmsg, APP_BOOST_TIMEOUT);
- }
- }
- }
- } break;
case IDLE_UIDS_MSG: {
idleUids();
} break;
- case LOG_STACK_STATE: {
+ case VR_MODE_CHANGE_MSG: {
+ if (!mVrController.onVrModeChanged((ActivityRecord) msg.obj)) {
+ return;
+ }
synchronized (ActivityManagerService.this) {
- mStackSupervisor.logStackState();
+ final boolean disableNonVrUi = mVrController.shouldDisableNonVrUiLocked();
+ mWindowManager.disableNonVrUi(disableNonVrUi);
+ if (disableNonVrUi) {
+ // If we are in a VR mode where Picture-in-Picture mode is unsupported,
+ // then remove the pinned stack.
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
+ }
}
} break;
- case VR_MODE_CHANGE_MSG: {
- VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
- if (vrService == null) {
- break;
+ case DISPATCH_SCREEN_AWAKE_MSG: {
+ final boolean isAwake = msg.arg1 != 0;
+ for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+ mScreenObservers.get(i).onAwakeStateChanged(isAwake);
+ }
+ } break;
+ case DISPATCH_SCREEN_KEYGUARD_MSG: {
+ final boolean isShowing = msg.arg1 != 0;
+ for (int i = mScreenObservers.size() - 1; i >= 0; i--) {
+ mScreenObservers.get(i).onKeyguardStateChanged(isShowing);
}
- final ActivityRecord r = (ActivityRecord) msg.obj;
- boolean vrMode;
- ComponentName requestedPackage;
- ComponentName callingPackage;
- int userId;
+ } break;
+ case HANDLE_TRUST_STORAGE_UPDATE_MSG: {
synchronized (ActivityManagerService.this) {
- vrMode = r.requestedVrComponent != null;
- requestedPackage = r.requestedVrComponent;
- userId = r.userId;
- callingPackage = r.info.getComponentName();
- if (mInVrMode != vrMode) {
- mInVrMode = vrMode;
- mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
- if (r.app != null) {
- ProcessRecord proc = r.app;
- if (proc.vrThreadTid > 0) {
- if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
- try {
- if (mInVrMode == true) {
- Process.setThreadScheduler(proc.vrThreadTid,
- Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
- } else {
- Process.setThreadScheduler(proc.vrThreadTid,
- Process.SCHED_OTHER, 0);
- }
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed to set scheduling policy, thread does"
- + " not exist:\n" + e);
- }
- }
+ for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r.thread != null) {
+ try {
+ r.thread.handleTrustStorageUpdate();
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to handle trust storage update for: " +
+ r.info.processName);
}
}
}
}
- vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
- } case NOTIFY_VR_SLEEPING_MSG: {
- notifyVrManagerOfSleepState(msg.arg1 != 0);
} break;
}
}
final List<ProcessCpuTracker.Stats> stats;
synchronized (mProcessCpuTracker) {
stats = mProcessCpuTracker.getStats( (st)-> {
- return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID;
+ return st.vsize > 0 && st.uid < FIRST_APPLICATION_UID;
});
}
final int N = stats.size();
}
int num = 0;
- long[] tmp = new long[2];
+ long[] tmp = new long[3];
do {
ProcessRecord proc;
int procState;
+ int statType;
int pid;
long lastPssTime;
synchronized (ActivityManagerService.this) {
if (mPendingPssProcesses.size() <= 0) {
if (mTestPssMode || DEBUG_PSS) Slog.d(TAG_PSS,
- "Collected PSS of " + num + " processes in "
+ "Collected pss of " + num + " processes in "
+ (SystemClock.uptimeMillis() - start) + "ms");
mPendingPssProcesses.clear();
return;
}
proc = mPendingPssProcesses.remove(0);
procState = proc.pssProcState;
+ statType = proc.pssStatType;
lastPssTime = proc.lastPssTime;
+ long now = SystemClock.uptimeMillis();
if (proc.thread != null && procState == proc.setProcState
&& (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
- < SystemClock.uptimeMillis()) {
+ < now) {
pid = proc.pid;
} else {
+ ProcessList.abortNextPssTime(proc.procStateMemTracker);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Skipped pss collection of " + pid +
+ ": still need " +
+ (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE-now) +
+ "ms until safe");
proc = null;
pid = 0;
}
}
if (proc != null) {
+ long startTime = SystemClock.currentThreadTimeMillis();
long pss = Debug.getPss(pid, tmp, null);
+ long endTime = SystemClock.currentThreadTimeMillis();
synchronized (ActivityManagerService.this) {
if (pss != 0 && proc.thread != null && proc.setProcState == procState
&& proc.pid == pid && proc.lastPssTime == lastPssTime) {
num++;
- recordPssSampleLocked(proc, procState, pss, tmp[0], tmp[1],
- SystemClock.uptimeMillis());
+ ProcessList.commitNextPssTime(proc.procStateMemTracker);
+ recordPssSampleLocked(proc, procState, pss, tmp[0], tmp[1], tmp[2],
+ statType, endTime-startTime, SystemClock.uptimeMillis());
+ } else {
+ ProcessList.abortNextPssTime(proc.procStateMemTracker);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Skipped pss collection of " + pid +
+ ": " + (proc.thread == null ? "NO_THREAD " : "") +
+ (proc.pid != pid ? "PID_CHANGED " : "") +
+ " initState=" + procState + " curState=" +
+ proc.setProcState + " " +
+ (proc.lastPssTime != lastPssTime ? "TIME_CHANGED" : ""));
}
}
}
public void setSystemProcess() {
try {
- ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
+ ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
+ DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
- ServiceManager.addService("meminfo", new MemBinder(this));
+ ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
+ DUMP_FLAG_PRIORITY_HIGH);
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
- ServiceManager.addService("cpuinfo", new CpuBinder(this));
+ ServiceManager.addService("cpuinfo", new CpuBinder(this),
+ /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
throw new RuntimeException(
"Unable to find android system package", e);
}
+
+ // Start watching app ops after we and the package manager are up and running.
+ mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
+ new IAppOpsCallback.Stub() {
+ @Override public void opChanged(int op, int uid, String packageName) {
+ if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
+ if (mAppOpsService.checkOperation(op, uid, packageName)
+ != AppOpsManager.MODE_ALLOWED) {
+ runInBackgroundDisabled(uid);
+ }
+ }
+ }
+ });
}
public void setWindowManager(WindowManagerService wm) {
- mWindowManager = wm;
- mStackSupervisor.setWindowManager(wm);
- mActivityStarter.setWindowManager(wm);
+ synchronized (this) {
+ mWindowManager = wm;
+ mStackSupervisor.setWindowManager(wm);
+ mLockTaskController.setWindowManager(wm);
+ }
}
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
static class MemBinder extends Binder {
ActivityManagerService mActivityManagerService;
+ private final PriorityDump.PriorityDumper mPriorityDumper =
+ new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args,
+ boolean asProto) {
+ dump(fd, pw, new String[] {"-a"}, asProto);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+ mActivityManagerService.dumpApplicationMemoryUsage(
+ fd, pw, " ", args, false, null, asProto);
+ }
+ };
+
MemBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump meminfo from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " without permission " + android.Manifest.permission.DUMP);
- return;
- }
-
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "meminfo", pw)) return;
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump gfxinfo from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " without permission " + android.Manifest.permission.DUMP);
- return;
- }
-
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "gfxinfo", pw)) return;
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
}
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump dbinfo from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " without permission " + android.Manifest.permission.DUMP);
- return;
- }
-
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "dbinfo", pw)) return;
mActivityManagerService.dumpDbInfo(fd, pw, args);
}
}
static class CpuBinder extends Binder {
ActivityManagerService mActivityManagerService;
+ private final PriorityDump.PriorityDumper mPriorityDumper =
+ new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args,
+ boolean asProto) {
+ if (asProto) return;
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "cpuinfo", pw)) return;
+ synchronized (mActivityManagerService.mProcessCpuTracker) {
+ pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
+ pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
+ SystemClock.uptimeMillis()));
+ }
+ }
+ };
+
CpuBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump cpuinfo from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " without permission " + android.Manifest.permission.DUMP);
- return;
- }
-
- synchronized (mActivityManagerService.mProcessCpuTracker) {
- pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
- pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
- SystemClock.uptimeMillis()));
- }
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
}
mService.start();
}
+ @Override
+ public void onBootPhase(int phase) {
+ mService.mBootPhase = phase;
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ mService.mBatteryStatsService.systemServicesReady();
+ mService.mServices.systemServicesReady();
+ }
+ }
+
+ @Override
+ public void onCleanupUser(int userId) {
+ mService.mBatteryStatsService.onCleanupUser(userId);
+ }
+
public ActivityManagerService getService() {
return mService;
}
}
+ /**
+ * Encapsulates global settings related to hidden API enforcement behaviour, including tracking
+ * the latest value via a content observer.
+ */
+ static class HiddenApiSettings extends ContentObserver {
+
+ private final Context mContext;
+ private boolean mBlacklistDisabled;
+ private String mExemptionsStr;
+ private List<String> mExemptions = Collections.emptyList();
+ private int mLogSampleRate = -1;
+ @HiddenApiEnforcementPolicy private int mPolicyPreP = HIDDEN_API_ENFORCEMENT_DEFAULT;
+ @HiddenApiEnforcementPolicy private int mPolicyP = HIDDEN_API_ENFORCEMENT_DEFAULT;
+
+ public HiddenApiSettings(Handler handler, Context context) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void registerObserver() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS),
+ false,
+ this);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE),
+ false,
+ this);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_POLICY_PRE_P_APPS),
+ false,
+ this);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.HIDDEN_API_POLICY_P_APPS),
+ false,
+ this);
+ update();
+ }
+
+ private void update() {
+ String exemptions = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+ if (!TextUtils.equals(exemptions, mExemptionsStr)) {
+ mExemptionsStr = exemptions;
+ if ("*".equals(exemptions)) {
+ mBlacklistDisabled = true;
+ mExemptions = Collections.emptyList();
+ } else {
+ mBlacklistDisabled = false;
+ mExemptions = TextUtils.isEmpty(exemptions)
+ ? Collections.emptyList()
+ : Arrays.asList(exemptions.split(","));
+ }
+ if (!zygoteProcess.setApiBlacklistExemptions(mExemptions)) {
+ Slog.e(TAG, "Failed to set API blacklist exemptions!");
+ // leave mExemptionsStr as is, so we don't try to send the same list again.
+ mExemptions = Collections.emptyList();
+ }
+ }
+ int logSampleRate = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, -1);
+ if (logSampleRate < 0 || logSampleRate > 0x10000) {
+ logSampleRate = -1;
+ }
+ if (logSampleRate != -1 && logSampleRate != mLogSampleRate) {
+ mLogSampleRate = logSampleRate;
+ zygoteProcess.setHiddenApiAccessLogSampleRate(mLogSampleRate);
+ }
+ mPolicyPreP = getValidEnforcementPolicy(Settings.Global.HIDDEN_API_POLICY_PRE_P_APPS);
+ mPolicyP = getValidEnforcementPolicy(Settings.Global.HIDDEN_API_POLICY_P_APPS);
+ }
+
+ private @HiddenApiEnforcementPolicy int getValidEnforcementPolicy(String settingsKey) {
+ int policy = Settings.Global.getInt(mContext.getContentResolver(), settingsKey,
+ ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT);
+ if (ApplicationInfo.isValidHiddenApiEnforcementPolicy(policy)) {
+ return policy;
+ } else {
+ return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
+ }
+ }
+
+ boolean isDisabled() {
+ return mBlacklistDisabled;
+ }
+
+ @HiddenApiEnforcementPolicy int getPolicyForPrePApps() {
+ return mPolicyPreP;
+ }
+
+ @HiddenApiEnforcementPolicy int getPolicyForPApps() {
+ return mPolicyP;
+ }
+
+ public void onChange(boolean selfChange) {
+ update();
+ }
+ }
+
+ @VisibleForTesting
+ public ActivityManagerService(Injector injector) {
+ mInjector = injector;
+ mContext = mInjector.getContext();
+ mUiContext = null;
+ GL_ES_VERSION = 0;
+ mActivityStartController = null;
+ mAppErrors = null;
+ mAppWarnings = null;
+ mAppOpsService = mInjector.getAppOpsService(null, null);
+ mBatteryStatsService = null;
+ mCompatModePackages = null;
+ mConstants = null;
+ mGrantFile = null;
+ mHandler = null;
+ mHandlerThread = null;
+ mIntentFirewall = null;
+ mKeyguardController = null;
+ mPermissionReviewRequired = false;
+ mProcessCpuThread = null;
+ mProcessStats = null;
+ mProviderMap = null;
+ mRecentTasks = null;
+ mServices = null;
+ mStackSupervisor = null;
+ mSystemThread = null;
+ mTaskChangeNotificationController = null;
+ mUiHandler = injector.getUiHandler(null);
+ mUserController = null;
+ mVrController = null;
+ mLockTaskController = null;
+ mLifecycleManager = null;
+ mProcStartHandlerThread = null;
+ mProcStartHandler = null;
+ mHiddenApiBlacklist = null;
+ }
+
// Note: This method is invoked on the main thread but may need to attach various
// handlers to other threads. So take care to be explicit about the looper.
public ActivityManagerService(Context systemContext) {
+ LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
+ mInjector = new Injector();
mContext = systemContext;
+
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
+ mUiContext = mSystemThread.getSystemUiContext();
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
com.android.internal.R.bool.config_permissionReviewRequired);
mHandlerThread = new ServiceThread(TAG,
- android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
+ THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
- mUiHandler = new UiHandler();
+ mUiHandler = mInjector.getUiHandler(this);
+
+ mProcStartHandlerThread = new ServiceThread(TAG + ":procStart",
+ THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
+ mProcStartHandlerThread.start();
+ mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
+
+ mConstants = new ActivityManagerConstants(this, mHandler);
/* static; one-time init here */
if (sKillHandler == null) {
sKillThread = new ServiceThread(TAG + ":kill",
- android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+ THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
sKillThread.start();
sKillHandler = new KillHandler(sKillThread.getLooper());
}
mServices = new ActiveServices(this);
mProviderMap = new ProviderMap(this);
- mAppErrors = new AppErrors(mContext, this);
+ mAppErrors = new AppErrors(mUiContext, this);
- // TODO: Move creation of battery stats service outside of activity manager service.
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
- mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
+
+ mAppWarnings = new AppWarnings(this, mUiContext, mHandler, mUiHandler, systemDir);
+
+ // TODO: Move creation of battery stats service outside of activity manager service.
+ mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
- mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_IN_BACKGROUND, null,
- new IAppOpsCallback.Stub() {
- @Override public void opChanged(int op, int uid, String packageName) {
- if (op == AppOpsManager.OP_RUN_IN_BACKGROUND && packageName != null) {
- if (mAppOpsService.checkOperation(op, uid, packageName)
- != AppOpsManager.MODE_ALLOWED) {
- runInBackgroundDisabled(uid);
- }
- }
- }
- });
+ mAppOpsService = mInjector.getAppOpsService(new File(systemDir, "appops.xml"), mHandler);
- mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
+ mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"), "uri-grants");
mUserController = new UserController(this);
+ mVrController = new VrController(this);
+
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
}
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
-
- mConfiguration.setToDefaults();
- mConfiguration.setLocales(LocaleList.getDefault());
-
- mConfigurationSeq = mConfiguration.seq = 1;
- mProcessCpuTracker.init();
-
+ mTempConfig.setToDefaults();
+ mTempConfig.setLocales(LocaleList.getDefault());
+ mConfigurationSeq = mTempConfig.seq = 1;
+ mStackSupervisor = createStackSupervisor();
+ mStackSupervisor.onConfigurationChanged(mTempConfig);
+ mKeyguardController = mStackSupervisor.getKeyguardController();
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
- mStackSupervisor = new ActivityStackSupervisor(this);
- mActivityStarter = new ActivityStarter(this, mStackSupervisor);
- mRecentTasks = new RecentTasks(this, mStackSupervisor);
+ mTaskChangeNotificationController =
+ new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
+ mActivityStartController = new ActivityStartController(this);
+ mRecentTasks = createRecentTasks();
+ mStackSupervisor.setRecentTasks(mRecentTasks);
+ mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
+ mLifecycleManager = new ClientLifecycleManager();
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
+ synchronized (mProcessCpuTracker) {
+ mProcessCpuInitLatch.countDown();
+ mProcessCpuTracker.init();
+ }
while (true) {
try {
try {
}
};
+ mHiddenApiBlacklist = new HiddenApiSettings(mHandler, mContext);
+
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
+
+ // bind background thread to little cores
+ // this is expected to fail inside of framework tests because apps can't touch cpusets directly
+ // make sure we've already adjusted system_server's internal view of itself first
+ updateOomAdjLocked();
+ try {
+ Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
+ Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ } catch (Exception e) {
+ Slog.w(TAG, "Setting background thread cpuset failed");
+ }
+
+ }
+
+ protected ActivityStackSupervisor createStackSupervisor() {
+ final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mHandler.getLooper());
+ supervisor.initialize();
+ return supervisor;
+ }
+
+ protected RecentTasks createRecentTasks() {
+ return new RecentTasks(this, mStackSupervisor);
+ }
+
+ RecentTasks getRecentTasks() {
+ return mRecentTasks;
}
public void setSystemServiceManager(SystemServiceManager mgr) {
}
private void start() {
- Process.removeAllProcessGroups();
+ removeAllProcessGroups();
mProcessCpuThread.start();
- mBatteryStatsService.publish(mContext);
+ mBatteryStatsService.publish();
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+ // Wait for the synchronized block started in mProcessCpuThread,
+ // so that any other acccess to mProcessCpuTracker from main thread
+ // will be blocked during mProcessCpuTracker initialization.
+ try {
+ mProcessCpuInitLatch.await();
+ } catch (InterruptedException e) {
+ Slog.wtf(TAG, "Interrupted wait during start", e);
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Interrupted wait during start");
+ }
}
void onUserStoppedLocked(int userId) {
mRecentTasks.unloadUserDataFromMemoryLocked(userId);
+ mAllowAppSwitchUids.remove(userId);
}
public void initPowerManagement() {
mVoiceWakeLock.setReferenceCounted(false);
}
+ private ArraySet<String> getBackgroundLaunchBroadcasts() {
+ if (mBackgroundLaunchBroadcasts == null) {
+ mBackgroundLaunchBroadcasts = SystemConfig.getInstance().getAllowImplicitBroadcasts();
+ }
+ return mBackgroundLaunchBroadcasts;
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
for (int i=0; i<N; i++) {
Parcel data2 = Parcel.obtain();
try {
- procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, 0);
+ procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null,
+ Binder.FLAG_ONEWAY);
} catch (RemoteException e) {
}
data2.recycle();
try {
return super.onTransact(code, data, reply, flags);
} catch (RuntimeException e) {
- // The activity manager only throws security exceptions, so let's
+ // The activity manager only throws certain exceptions intentionally, so let's
// log all others.
- if (!(e instanceof SecurityException)) {
- Slog.wtf(TAG, "Activity Manager Crash", e);
+ if (!(e instanceof SecurityException
+ || e instanceof IllegalArgumentException
+ || e instanceof IllegalStateException)) {
+ Slog.wtf(TAG, "Activity Manager Crash."
+ + " UID:" + Binder.getCallingUid()
+ + " PID:" + Binder.getCallingPid()
+ + " TRANS:" + code, e);
}
throw e;
}
}
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
pr.curCpuTime += st.rel_utime + st.rel_stime;
+ if (pr.lastCpuTime == 0) {
+ pr.lastCpuTime = pr.curCpuTime;
+ }
} else {
BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
if (ps == null || !ps.isActive()) {
}
@Override
+ public void batteryStatsReset() {
+ BinderCallsStatsService.reset();
+ }
+
+ @Override
public void batterySendBroadcast(Intent intent) {
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- AppOpsManager.OP_NONE, null, false, false,
- -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ synchronized (this) {
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false,
+ -1, SYSTEM_UID, UserHandle.USER_ALL);
+ }
}
/**
* process when the bindApplication() IPC is sent to the process. They're
* lazily setup to make sure the services are running when they're asked for.
*/
- private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
+ private ArrayMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
// Isolated processes won't get this optimization, so that we don't
// violate the rules about which services they have access to.
if (isolated) {
if (mIsolatedAppBindArgs == null) {
- mIsolatedAppBindArgs = new HashMap<>();
- mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
+ mIsolatedAppBindArgs = new ArrayMap<>(1);
+ addServiceToMap(mIsolatedAppBindArgs, "package");
}
return mIsolatedAppBindArgs;
}
if (mAppBindArgs == null) {
- mAppBindArgs = new HashMap<>();
-
- // Setup the application init args
- mAppBindArgs.put("package", ServiceManager.getService("package"));
- mAppBindArgs.put("window", ServiceManager.getService("window"));
- mAppBindArgs.put(Context.ALARM_SERVICE,
- ServiceManager.getService(Context.ALARM_SERVICE));
+ mAppBindArgs = new ArrayMap<>();
+
+ // Add common services.
+ // IMPORTANT: Before adding services here, make sure ephemeral apps can access them too.
+ // Enable the check in ApplicationThread.bindApplication() to make sure.
+ addServiceToMap(mAppBindArgs, "package");
+ addServiceToMap(mAppBindArgs, Context.WINDOW_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.ALARM_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.DISPLAY_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.NETWORKMANAGEMENT_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.CONNECTIVITY_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.ACCESSIBILITY_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.INPUT_METHOD_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.INPUT_SERVICE);
+ addServiceToMap(mAppBindArgs, "graphicsstats");
+ addServiceToMap(mAppBindArgs, Context.APP_OPS_SERVICE);
+ addServiceToMap(mAppBindArgs, "content");
+ addServiceToMap(mAppBindArgs, Context.JOB_SCHEDULER_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.NOTIFICATION_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.VIBRATOR_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.ACCOUNT_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.POWER_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.USER_SERVICE);
+ addServiceToMap(mAppBindArgs, "mount");
}
return mAppBindArgs;
}
- boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
- if (r == null || mFocusedActivity == r) {
- return false;
- }
-
- if (!r.isFocusable()) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: unfocusable r=" + r);
- return false;
+ private static void addServiceToMap(ArrayMap<String, IBinder> map, String name) {
+ final IBinder service = ServiceManager.getService(name);
+ if (service != null) {
+ map.put(name, service);
+ if (false) {
+ Log.i(TAG, "Adding " + name + " to the pre-loaded service cache.");
+ }
}
+ }
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
-
- final boolean wasDoingSetFocusedActivity = mDoingSetFocusedActivity;
- if (wasDoingSetFocusedActivity) Slog.w(TAG,
- "setFocusedActivityLocked: called recursively, r=" + r + ", reason=" + reason);
- mDoingSetFocusedActivity = true;
-
- final ActivityRecord last = mFocusedActivity;
- mFocusedActivity = r;
- if (r.task.isApplicationTask()) {
+ /**
+ * Update AMS states when an activity is resumed. This should only be called by
+ * {@link ActivityStack#onActivityStateChanged(ActivityRecord, ActivityState, String)} when an
+ * activity is resumed.
+ */
+ @GuardedBy("this")
+ void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
+ final TaskRecord task = r.getTask();
+ if (task.isActivityTypeStandard()) {
if (mCurAppTimeTracker != r.appTimeTracker) {
// We are switching app tracking. Complete the current one.
if (mCurAppTimeTracker != null) {
// TODO: VI Maybe r.task.voiceInteractor || r.voiceInteractor != null
// TODO: Probably not, because we don't want to resume voice on switching
// back to this activity
- if (r.task.voiceInteractor != null) {
- startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
+ if (task.voiceInteractor != null) {
+ startRunningVoiceLocked(task.voiceSession, r.info.applicationInfo.uid);
} else {
finishRunningVoiceLocked();
- IVoiceInteractionSession session;
- if (last != null && ((session = last.task.voiceSession) != null
- || (session = last.voiceSession) != null)) {
- // We had been in a voice interaction session, but now focused has
- // move to something different. Just finish the session, we can't
- // return to it and retain the proper state and synchronization with
- // the voice interaction service.
- finishVoiceTask(session);
+
+ if (mLastResumedActivity != null) {
+ final IVoiceInteractionSession session;
+
+ final TaskRecord lastResumedActivityTask = mLastResumedActivity.getTask();
+ if (lastResumedActivityTask != null
+ && lastResumedActivityTask.voiceSession != null) {
+ session = lastResumedActivityTask.voiceSession;
+ } else {
+ session = mLastResumedActivity.voiceSession;
+ }
+
+ if (session != null) {
+ // We had been in a voice interaction session, but now focused has
+ // move to something different. Just finish the session, we can't
+ // return to it and retain the proper state and synchronization with
+ // the voice interaction service.
+ finishVoiceTask(session);
+ }
}
}
- if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
- mWindowManager.setFocusedApp(r.appToken, true);
+
+ if (mLastResumedActivity != null && r.userId != mLastResumedActivity.userId) {
+ mUserController.sendForegroundProfileChanged(r.userId);
}
+ updateResumedAppTrace(r);
+ mLastResumedActivity = r;
+
+ mWindowManager.setFocusedApp(r.appToken, true);
+
applyUpdateLockStateLocked(r);
applyUpdateVrModeLocked(r);
- if (mFocusedActivity.userId != mLastFocusedUserId) {
- mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
- mHandler.obtainMessage(
- FOREGROUND_PROFILE_CHANGED_MSG, mFocusedActivity.userId, 0).sendToTarget();
- mLastFocusedUserId = mFocusedActivity.userId;
- }
-
- // Log a warning if the focused app is changed during the process. This could
- // indicate a problem of the focus setting logic!
- if (mFocusedActivity != r) Slog.w(TAG,
- "setFocusedActivityLocked: r=" + r + " but focused to " + mFocusedActivity);
- mDoingSetFocusedActivity = wasDoingSetFocusedActivity;
-
- EventLogTags.writeAmFocusedActivity(
- mFocusedActivity == null ? -1 : mFocusedActivity.userId,
- mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
+
+ EventLogTags.writeAmSetResumedActivity(
+ r == null ? -1 : r.userId,
+ r == null ? "NULL" : r.shortComponentName,
reason);
- return true;
}
- final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
- if (mFocusedActivity != goingAway) {
- return;
- }
-
- final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
- if (focusedStack != null) {
- final ActivityRecord top = focusedStack.topActivity();
- if (top != null && top.userId != mLastFocusedUserId) {
- mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
- mHandler.sendMessage(
- mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
- mLastFocusedUserId = top.userId;
- }
+ private void updateResumedAppTrace(@Nullable ActivityRecord resumed) {
+ if (mTracedResumedActivity != null) {
+ Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER,
+ constructResumedTraceName(mTracedResumedActivity.packageName), 0);
}
-
- // Try to move focus to another activity if possible.
- if (setFocusedActivityLocked(
- focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
- return;
+ if (resumed != null) {
+ Trace.asyncTraceBegin(TRACE_TAG_ACTIVITY_MANAGER,
+ constructResumedTraceName(resumed.packageName), 0);
}
+ mTracedResumedActivity = resumed;
+ }
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
- + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
- mFocusedActivity = null;
- EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
+ private String constructResumedTraceName(String packageName) {
+ return "focused app: " + packageName;
}
@Override
synchronized (this) {
final ActivityStack stack = mStackSupervisor.getStack(stackId);
if (stack == null) {
+ Slog.w(TAG, "setFocusedStack: No stack with id=" + stackId);
return;
}
final ActivityRecord r = stack.topRunningActivityLocked();
- if (setFocusedActivityLocked(r, "setFocusedStack")) {
+ if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, "setFocusedStack")) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
if (task == null) {
return;
}
- if (mUserController.shouldConfirmCredentials(task.userId)) {
- mActivityStarter.showConfirmDeviceCredential(task.userId);
- if (task.stack != null && task.stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- mStackSupervisor.moveTaskToStackLocked(task.taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, !ON_TOP, !FORCE_FOCUS,
- "setFocusedTask", ANIMATE);
- }
- return;
- }
final ActivityRecord r = task.topRunningActivityLocked();
- if (setFocusedActivityLocked(r, "setFocusedTask")) {
+ if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, "setFocusedTask")) {
mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
/** Sets the task stack listener that gets callbacks when a task stack changes. */
@Override
public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "registerTaskStackListener()");
- synchronized (this) {
- if (listener != null) {
- mTaskStackListeners.register(listener);
- }
- }
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "registerTaskStackListener()");
+ mTaskChangeNotificationController.registerTaskStackListener(listener);
}
+ /**
+ * Unregister a task stack listener so that it stops receiving callbacks.
+ */
+ @Override
+ public void unregisterTaskStackListener(ITaskStackListener listener) throws RemoteException {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "unregisterTaskStackListener()");
+ mTaskChangeNotificationController.unregisterTaskStackListener(listener);
+ }
+
@Override
public void notifyActivityDrawn(IBinder token) {
if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token);
synchronized (this) {
ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
if (r != null) {
- r.task.stack.notifyActivityDrawnLocked(r);
+ r.getStack().notifyActivityDrawnLocked(r);
}
}
}
}
final void applyUpdateVrModeLocked(ActivityRecord r) {
+ // VR apps are expected to run in a main display. If an app is turning on VR for
+ // itself, but lives in a dynamic stack, then make sure that it is moved to the main
+ // fullscreen stack before enabling VR Mode.
+ // TODO: The goal of this code is to keep the VR app on the main display. When the
+ // stack implementation changes in the future, keep in mind that the use of the fullscreen
+ // stack is a means to move the activity to the main display and a moveActivityToDisplay()
+ // option would be a better choice here.
+ if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) {
+ Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId()
+ + " to main stack for VR");
+ final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, r.getActivityType(), true /* toTop */);
+ moveTaskToStack(r.getTask().taskId, stack.mStackId, true /* toTop */);
+ }
mHandler.sendMessage(
mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
}
- private void sendNotifyVrManagerOfSleepState(boolean isSleeping) {
- mHandler.sendMessage(
- mHandler.obtainMessage(NOTIFY_VR_SLEEPING_MSG, isSleeping ? 1 : 0, 0));
- }
-
- private void notifyVrManagerOfSleepState(boolean isSleeping) {
- final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
- if (vrService == null) {
- return;
- }
- vrService.onSleepStateChanged(isSleeping);
- }
-
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
- msg.obj = r.task.askedCompatMode ? null : r;
+ msg.obj = r.getTask().askedCompatMode ? null : r;
mUiHandler.sendMessage(msg);
}
- final void showUnsupportedZoomDialogIfNeededLocked(ActivityRecord r) {
- if (mConfiguration.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
- && r.appInfo.requiresSmallestWidthDp > mConfiguration.smallestScreenWidthDp) {
- final Message msg = Message.obtain();
- msg.what = SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG;
- msg.obj = r;
- mUiHandler.sendMessage(msg);
- }
+ final AppWarnings getAppWarningsLocked() {
+ return mAppWarnings;
+ }
+
+ /**
+ * Shows app warning dialogs, if necessary.
+ *
+ * @param r activity record for which the warnings may be displayed
+ */
+ final void showAppWarningsIfNeededLocked(ActivityRecord r) {
+ mAppWarnings.showUnsupportedCompileSdkDialogIfNeeded(r);
+ mAppWarnings.showUnsupportedDisplaySizeDialogIfNeeded(r);
+ mAppWarnings.showDeprecatedTargetDialogIfNeeded(r);
}
private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
String what, Object obj, ProcessRecord srcApp) {
app.lastActivityTime = now;
- if (app.activities.size() > 0) {
+ if (app.activities.size() > 0 || app.recentTasks.size() > 0) {
// Don't want to touch dependent processes that are hosting activities.
return index;
}
int lrui = mLruProcesses.lastIndexOf(app);
if (lrui >= 0) {
if (!app.killed) {
- Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
- Process.killProcessQuiet(app.pid);
- killProcessGroup(app.uid, app.pid);
+ if (app.persistent) {
+ Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app);
+ } else {
+ Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
+ if (app.pid > 0) {
+ killProcessQuiet(app.pid);
+ killProcessGroup(app.uid, app.pid);
+ } else {
+ app.pendingStart = false;
+ }
+ }
}
if (lrui <= mLruProcessActivityStart) {
mLruProcessActivityStart--;
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
- || app.treatLikeActivity;
+ || app.treatLikeActivity || app.recentTasks.size() > 0;
final boolean hasService = false; // not impl yet. app.services.size() > 0;
if (!activityChange && hasActivity) {
// The process has activities, so we are only allowing activity-based adjustments
int nextIndex;
if (hasActivity) {
final int N = mLruProcesses.size();
- if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {
+ if ((app.activities.size() == 0 || app.recentTasks.size() > 0)
+ && mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but one below the top (the top
// should always have a real activity).
}
final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
- if (uid == Process.SYSTEM_UID) {
+ if (uid == SYSTEM_UID) {
// The system gets to run in any process. If there are multiple
// processes with the same uid, just pick the first (this
// should never happen).
}
void notifyPackageUse(String packageName, int reason) {
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- pm.notifyPackageUse(packageName, reason);
- } catch (RemoteException e) {
+ synchronized(this) {
+ getPackageManagerInternalLocked().notifyPackageUse(packageName, reason);
}
}
|| transit == TRANSIT_TASK_TO_FRONT;
}
- int startIsolatedProcess(String entryPoint, String[] entryPointArgs,
+ boolean startIsolatedProcess(String entryPoint, String[] entryPointArgs,
String processName, String abiOverride, int uid, Runnable crashHandler) {
synchronized(this) {
ApplicationInfo info = new ApplicationInfo();
// closest thing to a parent's uid is SYSTEM_UID.
// The only important thing here is to keep AI.uid != PR.uid, in order to trigger
// the |isolated| logic in the ProcessRecord constructor.
- info.uid = Process.SYSTEM_UID;
+ info.uid = SYSTEM_UID;
info.processName = processName;
info.className = entryPoint;
info.packageName = "android";
+ info.seInfoUser = SELinuxUtil.COMPLETE_STR;
+ info.targetSdkVersion = Build.VERSION.SDK_INT;
ProcessRecord proc = startProcessLocked(processName, info /* info */,
false /* knownToBeDead */, 0 /* intentFlags */, "" /* hostingType */,
null /* hostingName */, true /* allowWhileBooting */, true /* isolated */,
uid, true /* keepIfLarge */, abiOverride, entryPoint, entryPointArgs,
crashHandler);
- return proc != null ? proc.pid : 0;
+ return proc != null;
}
}
+ @GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
null /* crashHandler */);
}
+ @GuardedBy("this")
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
app = null;
}
- // app launch boost for big.little configurations
- // use cpusets to migrate freshly launched tasks to big cores
- nativeMigrateToBoost();
- mIsBoosted = true;
- mBoostStartTime = SystemClock.uptimeMillis();
- Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
- mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
-
// We don't have to do anything more if:
// (1) There is an existing application record; and
// (2) The caller doesn't think it is dead, OR there is no thread
return null;
}
app.crashHandler = crashHandler;
+ app.isolatedEntryPoint = entryPoint;
+ app.isolatedEntryPointArgs = entryPointArgs;
checkTime(startTime, "startProcess: done creating new process record");
} else {
// If this is a new package in the process, add the package to the list
}
checkTime(startTime, "startProcess: stepping in to startProcess");
- startProcessLocked(
- app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
+ final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
checkTime(startTime, "startProcess: done starting proc!");
- return (app.pid != 0) ? app : null;
+ return success ? app : null;
}
boolean isAllowedWhileBooting(ApplicationInfo ai) {
return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
}
+ @GuardedBy("this")
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
- startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
- null /* entryPoint */, null /* entryPointArgs */);
+ startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
+ }
+
+ @GuardedBy("this")
+ private final boolean startProcessLocked(ProcessRecord app,
+ String hostingType, String hostingNameStr, String abiOverride) {
+ return startProcessLocked(app, hostingType, hostingNameStr,
+ false /* disableHiddenApiChecks */, abiOverride);
}
- private final void startProcessLocked(ProcessRecord app, String hostingType,
- String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
+ /**
+ * @return {@code true} if process start is successful, false otherwise.
+ */
+ @GuardedBy("this")
+ private final boolean startProcessLocked(ProcessRecord app, String hostingType,
+ String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
+ if (app.pendingStart) {
+ return true;
+ }
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
checkTime(startTime, "startProcess: removing from pids map");
}
checkTime(startTime, "startProcess: done removing from pids map");
app.setPid(0);
+ app.startSeq = 0;
}
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
- MountServiceInternal mountServiceInternal = LocalServices.getService(
- MountServiceInternal.class);
- mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
* resources like shared libraries and access user-wide resources
*/
if (ArrayUtils.isEmpty(permGids)) {
- gids = new int[2];
+ gids = new int[3];
} else {
- gids = new int[permGids.length + 2];
- System.arraycopy(permGids, 0, gids, 2, permGids.length);
+ gids = new int[permGids.length + 3];
+ System.arraycopy(permGids, 0, gids, 3, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
- gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+ gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
+ gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+
+ // Replace any invalid GIDs
+ if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
+ if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
}
checkTime(startTime, "startProcess: building args");
if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
uid = 0;
}
}
- int debugFlags = 0;
+ int runtimeFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
+ runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
- debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
// Run the app in safe mode if its manifest requests so or the
// system is booted in safe mode.
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
mSafeMode == true) {
- debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
- debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
- if ("true".equals(genDebugInfoProperty)) {
- debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
+ if ("1".equals(genDebugInfoProperty) || "true".equals(genDebugInfoProperty)) {
+ runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
+ }
+ String genMiniDebugInfoProperty = SystemProperties.get("dalvik.vm.minidebuginfo");
+ if ("1".equals(genMiniDebugInfoProperty) || "true".equals(genMiniDebugInfoProperty)) {
+ runtimeFlags |= Zygote.DEBUG_GENERATE_MINI_DEBUG_INFO;
}
if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
- debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1".equals(SystemProperties.get("debug.assert"))) {
- debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {
// Enable all debug flags required by the native debugger.
- debugFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
- debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
- debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
+ runtimeFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
+ runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
+ runtimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
mNativeDebuggingApp = null;
}
+ if (app.info.isPrivilegedApp() &&
+ DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
+ runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
+ }
+
+ if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) {
+ app.info.maybeUpdateHiddenApiEnforcementPolicy(
+ mHiddenApiBlacklist.getPolicyForPrePApps(),
+ mHiddenApiBlacklist.getPolicyForPApps());
+ @HiddenApiEnforcementPolicy int policy =
+ app.info.getHiddenApiEnforcementPolicy();
+ int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
+ if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
+ throw new IllegalStateException("Invalid API policy: " + policy);
+ }
+ runtimeFlags |= policyBits;
+ }
+
+ String invokeWith = null;
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ // Debuggable apps may include a wrapper script with their library directory.
+ String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ if (new File(wrapperFileName).exists()) {
+ invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
+ // the per-user SELinux context must be set
+ if (TextUtils.isEmpty(app.info.seInfoUser)) {
+ Slog.wtf(TAG, "SELinux tag not defined",
+ new IllegalStateException("SELinux tag not defined for "
+ + app.info.packageName + " (uid " + app.uid + ")"));
+ }
+ final String seInfo = app.info.seInfo
+ + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
- boolean isActivityProcess = (entryPoint == null);
- if (entryPoint == null) entryPoint = "android.app.ActivityThread";
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
- app.processName);
- checkTime(startTime, "startProcess: asking zygote to start proc");
- Process.ProcessStartResult startResult = Process.start(entryPoint,
- app.processName, uid, uid, gids, debugFlags, mountExternal,
- app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
- app.info.dataDir, entryPointArgs);
- checkTime(startTime, "startProcess: returned from zygote!");
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
- mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
- checkTime(startTime, "startProcess: done updating battery stats");
-
- EventLog.writeEvent(EventLogTags.AM_PROC_START,
- UserHandle.getUserId(uid), startResult.pid, uid,
- app.processName, hostingType,
- hostingNameStr != null ? hostingNameStr : "");
+ final String entryPoint = "android.app.ActivityThread";
- try {
- AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
- app.info.seinfo, app.info.sourceDir, startResult.pid);
- } catch (RemoteException ex) {
- // Ignore
- }
-
- if (app.persistent) {
- Watchdog.getInstance().processStarted(app.processName, startResult.pid);
- }
-
- checkTime(startTime, "startProcess: building log message");
- StringBuilder buf = mStringBuilder;
- buf.setLength(0);
- buf.append("Start proc ");
- buf.append(startResult.pid);
- buf.append(':');
- buf.append(app.processName);
- buf.append('/');
- UserHandle.formatUid(buf, uid);
- if (!isActivityProcess) {
- buf.append(" [");
- buf.append(entryPoint);
- buf.append("]");
- }
- buf.append(" for ");
- buf.append(hostingType);
- if (hostingNameStr != null) {
- buf.append(" ");
- buf.append(hostingNameStr);
- }
- Slog.i(TAG, buf.toString());
- app.setPid(startResult.pid);
- app.usingWrapper = startResult.usingWrapper;
- app.removed = false;
- app.killed = false;
- app.killedByAm = false;
- checkTime(startTime, "startProcess: starting to update pids map");
- ProcessRecord oldApp;
- synchronized (mPidsSelfLocked) {
- oldApp = mPidsSelfLocked.get(startResult.pid);
- }
- // If there is already an app occupying that pid that hasn't been cleaned up
- if (oldApp != null && !app.isolated) {
- // Clean up anything relating to this pid first
- Slog.w(TAG, "Reusing pid " + startResult.pid
- + " while app is still mapped to it");
- cleanUpApplicationRecordLocked(oldApp, false, false, -1,
- true /*replacingPid*/);
- }
- synchronized (mPidsSelfLocked) {
- this.mPidsSelfLocked.put(startResult.pid, app);
- if (isActivityProcess) {
- Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, startResult.usingWrapper
- ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
- }
- }
- checkTime(startTime, "startProcess: done updating pids map");
+ return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
+ runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
+ startTime);
} catch (RuntimeException e) {
Slog.e(TAG, "Failure starting process " + app.processName, e);
// it doesn't hurt to use it again.)
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
+ return false;
+ }
+ }
+
+ @GuardedBy("this")
+ private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
+ ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
+ String seInfo, String requiredAbi, String instructionSet, String invokeWith,
+ long startTime) {
+ app.pendingStart = true;
+ app.killedByAm = false;
+ app.removed = false;
+ app.killed = false;
+ if (app.startSeq != 0) {
+ Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+ + " with non-zero startSeq:" + app.startSeq);
+ }
+ if (app.pid != 0) {
+ Slog.wtf(TAG, "startProcessLocked processName:" + app.processName
+ + " with non-zero pid:" + app.pid);
+ }
+ final long startSeq = app.startSeq = ++mProcStartSeqCounter;
+ app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
+ if (mConstants.FLAG_PROCESS_START_ASYNC) {
+ if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
+ "Posting procStart msg for " + app.toShortString());
+ mProcStartHandler.post(() -> {
+ try {
+ synchronized (ActivityManagerService.this) {
+ final String reason = isProcStartValidLocked(app, startSeq);
+ if (reason != null) {
+ Slog.w(TAG_PROCESSES, app + " not valid anymore,"
+ + " don't start process, " + reason);
+ app.pendingStart = false;
+ return;
+ }
+ app.usingWrapper = invokeWith != null
+ || SystemProperties.get("wrap." + app.processName) != null;
+ mPendingStarts.put(startSeq, app);
+ }
+ final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
+ app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
+ requiredAbi, instructionSet, invokeWith, app.startTime);
+ synchronized (ActivityManagerService.this) {
+ handleProcessStartedLocked(app, startResult, startSeq);
+ }
+ } catch (RuntimeException e) {
+ synchronized (ActivityManagerService.this) {
+ Slog.e(TAG, "Failure starting process " + app.processName, e);
+ mPendingStarts.remove(startSeq);
+ app.pendingStart = false;
+ forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
+ false, false, true, false, false,
+ UserHandle.getUserId(app.userId), "start failure");
+ }
+ }
+ });
+ return true;
+ } else {
+ try {
+ final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
+ uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
+ invokeWith, startTime);
+ handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
+ startSeq, false);
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Failure starting process " + app.processName, e);
+ app.pendingStart = false;
+ forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
+ false, false, true, false, false,
+ UserHandle.getUserId(app.userId), "start failure");
+ }
+ return app.pid > 0;
+ }
+ }
+
+ private ProcessStartResult startProcess(String hostingType, String entryPoint,
+ ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
+ String seInfo, String requiredAbi, String instructionSet, String invokeWith,
+ long startTime) {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
+ app.processName);
+ checkTime(startTime, "startProcess: asking zygote to start proc");
+ final ProcessStartResult startResult;
+ if (hostingType.equals("webview_service")) {
+ startResult = startWebView(entryPoint,
+ app.processName, uid, uid, gids, runtimeFlags, mountExternal,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
+ app.info.dataDir, null,
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ } else {
+ startResult = Process.start(entryPoint,
+ app.processName, uid, uid, gids, runtimeFlags, mountExternal,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
+ app.info.dataDir, invokeWith,
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ }
+ checkTime(startTime, "startProcess: returned from zygote!");
+ return startResult;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
+ @GuardedBy("this")
+ private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
+ StringBuilder sb = null;
+ if (app.killedByAm) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("killedByAm=true;");
+ }
+ if (mProcessNames.get(app.processName, app.uid) != app) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("No entry in mProcessNames;");
+ }
+ if (!app.pendingStart) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("pendingStart=false;");
+ }
+ if (app.startSeq > expectedStartSeq) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("seq=" + app.startSeq + ",expected=" + expectedStartSeq + ";");
+ }
+ return sb == null ? null : sb.toString();
+ }
+
+ @GuardedBy("this")
+ private boolean handleProcessStartedLocked(ProcessRecord pending,
+ ProcessStartResult startResult, long expectedStartSeq) {
+ // Indicates that this process start has been taken care of.
+ if (mPendingStarts.get(expectedStartSeq) == null) {
+ if (pending.pid == startResult.pid) {
+ pending.usingWrapper = startResult.usingWrapper;
+ // TODO: Update already existing clients of usingWrapper
+ }
+ return false;
+ }
+ return handleProcessStartedLocked(pending, startResult.pid, startResult.usingWrapper,
+ expectedStartSeq, false);
+ }
+
+ @GuardedBy("this")
+ private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
+ long expectedStartSeq, boolean procAttached) {
+ mPendingStarts.remove(expectedStartSeq);
+ final String reason = isProcStartValidLocked(app, expectedStartSeq);
+ if (reason != null) {
+ Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" + pid
+ + ", " + reason);
+ app.pendingStart = false;
+ Process.killProcessQuiet(pid);
+ Process.killProcessGroup(app.uid, app.pid);
+ return false;
+ }
+ mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
+ checkTime(app.startTime, "startProcess: done updating battery stats");
+
+ EventLog.writeEvent(EventLogTags.AM_PROC_START,
+ UserHandle.getUserId(app.startUid), pid, app.startUid,
+ app.processName, app.hostingType,
+ app.hostingNameStr != null ? app.hostingNameStr : "");
+
+ try {
+ AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
+ app.seInfo, app.info.sourceDir, pid);
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+
+ if (app.persistent) {
+ Watchdog.getInstance().processStarted(app.processName, pid);
+ }
+
+ checkTime(app.startTime, "startProcess: building log message");
+ StringBuilder buf = mStringBuilder;
+ buf.setLength(0);
+ buf.append("Start proc ");
+ buf.append(pid);
+ buf.append(':');
+ buf.append(app.processName);
+ buf.append('/');
+ UserHandle.formatUid(buf, app.startUid);
+ if (app.isolatedEntryPoint != null) {
+ buf.append(" [");
+ buf.append(app.isolatedEntryPoint);
+ buf.append("]");
+ }
+ buf.append(" for ");
+ buf.append(app.hostingType);
+ if (app.hostingNameStr != null) {
+ buf.append(" ");
+ buf.append(app.hostingNameStr);
+ }
+ reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid);
+ app.setPid(pid);
+ app.usingWrapper = usingWrapper;
+ app.pendingStart = false;
+ checkTime(app.startTime, "startProcess: starting to update pids map");
+ ProcessRecord oldApp;
+ synchronized (mPidsSelfLocked) {
+ oldApp = mPidsSelfLocked.get(pid);
+ }
+ // If there is already an app occupying that pid that hasn't been cleaned up
+ if (oldApp != null && !app.isolated) {
+ // Clean up anything relating to this pid first
+ Slog.wtf(TAG, "handleProcessStartedLocked process:" + app.processName
+ + " startSeq:" + app.startSeq
+ + " pid:" + pid
+ + " belongs to another existing app:" + oldApp.processName
+ + " startSeq:" + oldApp.startSeq);
+ cleanUpApplicationRecordLocked(oldApp, false, false, -1,
+ true /*replacingPid*/);
+ }
+ synchronized (mPidsSelfLocked) {
+ this.mPidsSelfLocked.put(pid, app);
+ if (!procAttached) {
+ Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ msg.obj = app;
+ mHandler.sendMessageDelayed(msg, usingWrapper
+ ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
+ }
}
+ checkTime(app.startTime, "startProcess: done updating pids map");
+ return true;
}
void updateUsageStats(ActivityRecord component, boolean resumed) {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
"updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
+ component.app.uid, component.realActivity.getPackageName(),
+ component.realActivity.getShortClassName(), resumed ?
+ StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
+ StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
if (resumed) {
if (mUsageStatsService != null) {
mUsageStatsService.reportEvent(component.realActivity, component.userId,
UsageEvents.Event.MOVE_TO_FOREGROUND);
+
}
synchronized (stats) {
stats.noteActivityResumedLocked(component.app.uid);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
- if (app == null || app.instrumentationClass == null) {
- intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
+ if (app == null || app.instr == null) {
+ intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
+ final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
+ // For ANR debugging to verify if the user activity is the one that actually
+ // launched.
+ final String myReason = reason + ":" + userId + ":" + resolvedUserId;
+ mActivityStartController.startHomeActivity(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
return ai;
}
- /**
- * Starts the "new version setup screen" if appropriate.
- */
- void startSetupActivityLocked() {
- // Only do this once per boot.
- if (mCheckedForSetup) {
- return;
- }
+ boolean getCheckedForSetup() {
+ return mCheckedForSetup;
+ }
- // We will show this screen if the current one is a different
- // version than the last one shown, and we are not running in
- // low-level factory test mode.
- final ContentResolver resolver = mContext.getContentResolver();
- if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL &&
- Settings.Global.getInt(resolver,
- Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
- mCheckedForSetup = true;
-
- // See if we should be showing the platform update setup UI.
- final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
- final List<ResolveInfo> ris = mContext.getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
- if (!ris.isEmpty()) {
- final ResolveInfo ri = ris.get(0);
- String vers = ri.activityInfo.metaData != null
- ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
- : null;
- if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
- vers = ri.activityInfo.applicationInfo.metaData.getString(
- Intent.METADATA_SETUP_VERSION);
- }
- String lastVers = Settings.Secure.getString(
- resolver, Settings.Secure.LAST_SETUP_SHOWN);
- if (vers != null && !vers.equals(lastVers)) {
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setComponent(new ComponentName(
- ri.activityInfo.packageName, ri.activityInfo.name));
- mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
- null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
- null, 0, 0, 0, null, false, false, null, null, null);
- }
- }
- }
+ void setCheckedForSetup(boolean checked) {
+ mCheckedForSetup = checked;
}
CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
}
}
- void enforceShellRestriction(String restriction, int userHandle) {
- if (Binder.getCallingUid() == Process.SHELL_UID) {
- if (userHandle < 0 || mUserController.hasUserRestriction(restriction, userHandle)) {
- throw new SecurityException("Shell does not have permission to access user "
- + userHandle);
- }
- }
- }
-
@Override
public int getFrontActivityScreenCompatMode() {
enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
}
private boolean hasUsageStatsPermission(String callingPackage) {
- final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_GET_USAGE_STATS,
+ final int mode = mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS,
Binder.getCallingUid(), callingPackage);
if (mode == AppOpsManager.MODE_DEFAULT) {
return checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)
@Override
public int getPackageProcessState(String packageName, String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
- enforceCallingPermission(android.Manifest.permission.GET_PACKAGE_IMPORTANCE,
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
"getPackageProcessState");
}
synchronized (this) {
for (int i=mLruProcesses.size()-1; i>=0; i--) {
final ProcessRecord proc = mLruProcesses.get(i);
- if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT
- || procState > proc.setProcState) {
- boolean found = false;
- for (int j=proc.pkgList.size()-1; j>=0 && !found; j--) {
- if (proc.pkgList.keyAt(j).equals(packageName)) {
- procState = proc.setProcState;
- found = true;
- }
- }
- if (proc.pkgDeps != null && !found) {
- for (int j=proc.pkgDeps.size()-1; j>=0; j--) {
- if (proc.pkgDeps.valueAt(j).equals(packageName)) {
- procState = proc.setProcState;
- break;
- }
- }
+ if (procState > proc.setProcState) {
+ if (proc.pkgList.containsKey(packageName) ||
+ (proc.pkgDeps != null && proc.pkgDeps.contains(packageName))) {
+ procState = proc.setProcState;
}
}
}
}
@Override
- public boolean setProcessMemoryTrimLevel(String process, int userId, int level) {
+ public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
+ throws RemoteException {
synchronized (this) {
final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel");
if (app == null) {
- return false;
+ throw new IllegalArgumentException("Unknown process: " + process);
}
- if (app.trimMemoryLevel < level && app.thread != null &&
- (level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
- app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND)) {
- try {
- app.thread.scheduleTrimMemory(level);
- app.trimMemoryLevel = level;
- return true;
- } catch (RemoteException e) {
- // Fallthrough to failure case.
- }
+ if (app.thread == null) {
+ throw new IllegalArgumentException("Process has no app thread");
+ }
+ if (app.trimMemoryLevel >= level) {
+ throw new IllegalArgumentException(
+ "Unable to set a higher trim level than current level");
+ }
+ if (!(level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
+ app.curProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) {
+ throw new IllegalArgumentException("Unable to set a background trim level "
+ + "on a foreground process");
}
+ app.thread.scheduleTrimMemory(level);
+ app.trimMemoryLevel = level;
+ return true;
}
- return false;
}
private void dispatchProcessesChanged() {
observer.onForegroundActivitiesChanged(item.pid, item.uid,
item.foregroundActivities);
}
- if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "PROCSTATE CHANGED pid=" + item.pid + " uid=" + item.uid
- + ": " + item.processState);
- observer.onProcessStateChanged(item.pid, item.uid, item.processState);
- }
}
} catch (RemoteException e) {
}
mProcessObservers.finishBroadcast();
}
- private void dispatchUidsChanged() {
+ @VisibleForTesting
+ void dispatchUidsChanged() {
int N;
synchronized (this) {
N = mPendingUidChanges.size();
"*** Delivering " + N + " uid changes");
}
- if (mLocalPowerManager != null) {
- for (int j=0; j<N; j++) {
- UidRecord.ChangeItem item = mActiveUidChanges[j];
- if (item.change == UidRecord.CHANGE_GONE
- || item.change == UidRecord.CHANGE_GONE_IDLE) {
- mLocalPowerManager.uidGone(item.uid);
+ mUidChangeDispatchCount += N;
+ int i = mUidObservers.beginBroadcast();
+ while (i > 0) {
+ i--;
+ dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i),
+ (UidObserverRegistration) mUidObservers.getBroadcastCookie(i), N);
+ }
+ mUidObservers.finishBroadcast();
+
+ if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) {
+ for (int j = 0; j < N; ++j) {
+ final UidRecord.ChangeItem item = mActiveUidChanges[j];
+ if ((item.change & UidRecord.CHANGE_GONE) != 0) {
+ mValidateUids.remove(item.uid);
} else {
- mLocalPowerManager.updateUidProcState(item.uid, item.processState);
+ UidRecord validateUid = mValidateUids.get(item.uid);
+ if (validateUid == null) {
+ validateUid = new UidRecord(item.uid);
+ mValidateUids.put(item.uid, validateUid);
+ }
+ if ((item.change & UidRecord.CHANGE_IDLE) != 0) {
+ validateUid.idle = true;
+ } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) {
+ validateUid.idle = false;
+ }
+ validateUid.curProcState = validateUid.setProcState = item.processState;
+ validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
}
}
}
- int i = mUidObservers.beginBroadcast();
- while (i > 0) {
- i--;
- final IUidObserver observer = mUidObservers.getBroadcastItem(i);
- final int which = (Integer)mUidObservers.getBroadcastCookie(i);
- if (observer != null) {
- try {
- for (int j=0; j<N; j++) {
- UidRecord.ChangeItem item = mActiveUidChanges[j];
- final int change = item.change;
- UidRecord validateUid = null;
- if (VALIDATE_UID_STATES && i == 0) {
- validateUid = mValidateUids.get(item.uid);
- if (validateUid == null && change != UidRecord.CHANGE_GONE
- && change != UidRecord.CHANGE_GONE_IDLE) {
- validateUid = new UidRecord(item.uid);
- mValidateUids.put(item.uid, validateUid);
- }
- }
- if (change == UidRecord.CHANGE_IDLE
- || change == UidRecord.CHANGE_GONE_IDLE) {
- if ((which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "UID idle uid=" + item.uid);
- observer.onUidIdle(item.uid);
- }
- if (VALIDATE_UID_STATES && i == 0) {
- if (validateUid != null) {
- validateUid.idle = true;
- }
- }
- } else if (change == UidRecord.CHANGE_ACTIVE) {
- if ((which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "UID active uid=" + item.uid);
- observer.onUidActive(item.uid);
- }
- if (VALIDATE_UID_STATES && i == 0) {
- validateUid.idle = false;
+ synchronized (this) {
+ for (int j = 0; j < N; j++) {
+ mAvailUidChanges.add(mActiveUidChanges[j]);
+ }
+ }
+ }
+
+ private void dispatchUidsChangedForObserver(IUidObserver observer,
+ UidObserverRegistration reg, int changesSize) {
+ if (observer == null) {
+ return;
+ }
+ try {
+ for (int j = 0; j < changesSize; j++) {
+ UidRecord.ChangeItem item = mActiveUidChanges[j];
+ final int change = item.change;
+ if (change == UidRecord.CHANGE_PROCSTATE &&
+ (reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) {
+ // No-op common case: no significant change, the observer is not
+ // interested in all proc state changes.
+ continue;
+ }
+ final long start = SystemClock.uptimeMillis();
+ if ((change & UidRecord.CHANGE_IDLE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) {
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "UID idle uid=" + item.uid);
+ observer.onUidIdle(item.uid, item.ephemeral);
+ }
+ } else if ((change & UidRecord.CHANGE_ACTIVE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "UID active uid=" + item.uid);
+ observer.onUidActive(item.uid);
+ }
+ }
+ if ((reg.which & ActivityManager.UID_OBSERVER_CACHED) != 0) {
+ if ((change & UidRecord.CHANGE_CACHED) != 0) {
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "UID cached uid=" + item.uid);
+ observer.onUidCachedChanged(item.uid, true);
+ } else if ((change & UidRecord.CHANGE_UNCACHED) != 0) {
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "UID active uid=" + item.uid);
+ observer.onUidCachedChanged(item.uid, false);
+ }
+ }
+ if ((change & UidRecord.CHANGE_GONE) != 0) {
+ if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) {
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "UID gone uid=" + item.uid);
+ observer.onUidGone(item.uid, item.ephemeral);
+ }
+ if (reg.lastProcStates != null) {
+ reg.lastProcStates.delete(item.uid);
+ }
+ } else {
+ if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "UID CHANGED uid=" + item.uid
+ + ": " + item.processState);
+ boolean doReport = true;
+ if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
+ final int lastState = reg.lastProcStates.get(item.uid,
+ ActivityManager.PROCESS_STATE_UNKNOWN);
+ if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) {
+ final boolean lastAboveCut = lastState <= reg.cutpoint;
+ final boolean newAboveCut = item.processState <= reg.cutpoint;
+ doReport = lastAboveCut != newAboveCut;
+ } else {
+ doReport = item.processState
+ != ActivityManager.PROCESS_STATE_NONEXISTENT;
}
}
- if (change == UidRecord.CHANGE_GONE
- || change == UidRecord.CHANGE_GONE_IDLE) {
- if ((which & ActivityManager.UID_OBSERVER_GONE) != 0) {
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "UID gone uid=" + item.uid);
- observer.onUidGone(item.uid);
- }
- if (VALIDATE_UID_STATES && i == 0) {
- if (validateUid != null) {
- mValidateUids.remove(item.uid);
- }
- }
- } else {
- if ((which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "UID CHANGED uid=" + item.uid
- + ": " + item.processState);
- observer.onUidStateChanged(item.uid, item.processState);
- }
- if (VALIDATE_UID_STATES && i == 0) {
- validateUid.curProcState = validateUid.setProcState
- = item.processState;
+ if (doReport) {
+ if (reg.lastProcStates != null) {
+ reg.lastProcStates.put(item.uid, item.processState);
}
+ observer.onUidStateChanged(item.uid, item.processState,
+ item.procStateSeq);
}
}
- } catch (RemoteException e) {
+ }
+ final int duration = (int) (SystemClock.uptimeMillis() - start);
+ if (reg.mMaxDispatchTime < duration) {
+ reg.mMaxDispatchTime = duration;
+ }
+ if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) {
+ reg.mSlowDispatchCount++;
}
}
+ } catch (RemoteException e) {
}
- mUidObservers.finishBroadcast();
+ }
+ void dispatchOomAdjObserver(String msg) {
+ OomAdjObserver observer;
synchronized (this) {
- for (int j=0; j<N; j++) {
- mAvailUidChanges.add(mActiveUidChanges[j]);
- }
+ observer = mCurOomAdjObserver;
+ }
+
+ if (observer != null) {
+ observer.onOomAdjMessage(msg);
}
}
- @Override
- public final int startActivity(IApplicationThread caller, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
- return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
- resultWho, requestCode, startFlags, profilerInfo, bOptions,
- UserHandle.getCallingUserId());
+ void setOomAdjObserver(int uid, OomAdjObserver observer) {
+ synchronized (this) {
+ mCurOomAdjUid = uid;
+ mCurOomAdjObserver = observer;
+ }
+ }
+
+ void clearOomAdjObserver() {
+ synchronized (this) {
+ mCurOomAdjUid = -1;
+ mCurOomAdjObserver = null;
+ }
}
- final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) {
- enforceNotIsolatedCaller("ActivityContainer.startActivity");
- final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false,
- ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
+ void reportOomAdjMessageLocked(String tag, String msg) {
+ Slog.d(tag, msg);
+ if (mCurOomAdjObserver != null) {
+ mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
+ }
+ }
- // TODO: Switch to user app stacks here.
- String mimeType = intent.getType();
- final Uri data = intent.getData();
- if (mimeType == null && data != null && "content".equals(data.getScheme())) {
- mimeType = getProviderMimeType(data, userId);
+ void reportUidInfoMessageLocked(String tag, String msg, int uid) {
+ Slog.i(TAG, msg);
+ if (mCurOomAdjObserver != null && uid == mCurOomAdjUid) {
+ mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
}
- container.checkEmbeddedAllowedInner(userId, intent, mimeType);
- intent.addFlags(FORCE_NEW_TASK_FLAGS);
- return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
- null, 0, 0, null, null, null, null, false, userId, container, null);
}
@Override
- public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ public final int startActivity(IApplicationThread caller, String callingPackage,
+ Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
+ return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
+ resultWho, requestCode, startFlags, profilerInfo, bOptions,
+ UserHandle.getCallingUserId());
+ }
+
+ @Override
+ public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
+ resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
+ true /*validateIncomingUser*/);
+ }
+
+ public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
+ boolean validateIncomingUser) {
enforceNotIsolatedCaller("startActivity");
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivity", null);
+
+ userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
+ Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
+
// TODO: Switch to user app stacks here.
- return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- profilerInfo, null, null, bOptions, false, userId, null, null);
+ return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setProfilerInfo(profilerInfo)
+ .setActivityOptions(bOptions)
+ .setMayWait(userId)
+ .execute();
+
}
@Override
final ActivityRecord sourceRecord;
final int targetUid;
final String targetPackage;
+ final boolean isResolver;
synchronized (this) {
if (resultTo == null) {
throw new SecurityException("Must be called from an activity");
if (sourceRecord.app == null) {
throw new SecurityException("Called without a process attached to activity");
}
- if (UserHandle.getAppId(sourceRecord.app.uid) != Process.SYSTEM_UID) {
+ if (UserHandle.getAppId(sourceRecord.app.uid) != SYSTEM_UID) {
// This is still okay, as long as this activity is running under the
// uid of the original calling activity.
if (sourceRecord.app.uid != sourceRecord.launchedFromUid) {
}
targetUid = sourceRecord.launchedFromUid;
targetPackage = sourceRecord.launchedFromPackage;
+ isResolver = sourceRecord.isResolverOrChildActivity();
}
if (userId == UserHandle.USER_NULL) {
// TODO: Switch to user app stacks here.
try {
- int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
- null, null, bOptions, ignoreTargetSecurity, userId, null, null);
- return ret;
+ return mActivityStartController.obtainStarter(intent, "startActivityAsCaller")
+ .setCallingUid(targetUid)
+ .setCallingPackage(targetPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setActivityOptions(bOptions)
+ .setMayWait(userId)
+ .setIgnoreTargetSecurity(ignoreTargetSecurity)
+ .setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
+ .execute();
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
// A SecurityException here is generally actually a fault of the original
userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
- mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
- null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
- bOptions, false, userId, null, null);
+ mActivityStartController.obtainStarter(intent, "startActivityAndWait")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setActivityOptions(bOptions)
+ .setMayWait(userId)
+ .setProfilerInfo(profilerInfo)
+ .setWaitResult(res)
+ .execute();
return res;
}
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, config, bOptions, false, userId, null, null);
- return ret;
+ return mActivityStartController.obtainStarter(intent, "startActivityWithConfig")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setGlobalConfiguration(config)
+ .setActivityOptions(bOptions)
+ .setMayWait(userId)
+ .execute();
}
@Override
- public int startActivityIntentSender(IApplicationThread caller, IntentSender intent,
- Intent fillInIntent, String resolvedType, IBinder resultTo, String resultWho,
- int requestCode, int flagsMask, int flagsValues, Bundle bOptions)
+ public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
+ IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
+ String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- IIntentSender sender = intent.getTarget();
- if (!(sender instanceof PendingIntentRecord)) {
+ if (!(target instanceof PendingIntentRecord)) {
throw new IllegalArgumentException("Bad PendingIntent object");
}
- PendingIntentRecord pir = (PendingIntentRecord)sender;
+ PendingIntentRecord pir = (PendingIntentRecord)target;
synchronized (this) {
// If this is coming from the currently resumed activity, it is
mAppSwitchesAllowedTime = 0;
}
}
- int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null,
- resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions, null);
+ int ret = pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+ resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
return ret;
}
Intent intent, String resolvedType, IVoiceInteractionSession session,
IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
- if (checkCallingPermission(Manifest.permission.BIND_VOICE_INTERACTION)
- != PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: startVoiceActivity() from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.BIND_VOICE_INTERACTION;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
+ enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
if (session == null || interactor == null) {
throw new NullPointerException("null session or interactor");
}
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startVoiceActivity", null);
// TODO: Switch to user app stacks here.
- return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
- resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
- null, bOptions, false, userId, null, null);
+ return mActivityStartController.obtainStarter(intent, "startVoiceActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setVoiceSession(session)
+ .setVoiceInteractor(interactor)
+ .setStartFlags(startFlags)
+ .setProfilerInfo(profilerInfo)
+ .setActivityOptions(bOptions)
+ .setMayWait(userId)
+ .execute();
+ }
+
+ @Override
+ public int startAssistantActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, Bundle bOptions, int userId) {
+ enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
+ userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
+ ALLOW_FULL_ONLY, "startAssistantActivity", null);
+
+ return mActivityStartController.obtainStarter(intent, "startAssistantActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setActivityOptions(bOptions)
+ .setMayWait(userId)
+ .execute();
+ }
+
+ @Override
+ public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
+ IRecentsAnimationRunner recentsAnimationRunner) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
+ final int callingPid = Binder.getCallingPid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
+ final int recentsUid = mRecentTasks.getRecentsComponentUid();
+
+ // Start a new recents animation
+ final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
+ mActivityStartController, mWindowManager, mUserController, callingPid);
+ anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
+ recentsUid, assistDataReceiver);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
+ final long callingUid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ // Cancel the recents animation synchronously (do not hold the WM lock)
+ mWindowManager.cancelRecentsAnimationSynchronously(restoreHomeStackPosition
+ ? REORDER_MOVE_TO_ORIGINAL_POSITION
+ : REORDER_KEEP_IN_PLACE, "cancelRecentsAnimation/uid=" + callingUid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
@Override
throws RemoteException {
Slog.i(TAG, "Activity tried to startVoiceInteraction");
synchronized (this) {
- ActivityRecord activity = getFocusedStack().topActivity();
+ ActivityRecord activity = getFocusedStack().getTopActivity();
if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
throw new SecurityException("Only focused activity can call startVoiceInteraction");
}
- if (mRunningVoice != null || activity.task.voiceSession != null
+ if (mRunningVoice != null || activity.getTask().voiceSession != null
|| activity.voiceSession != null) {
Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
return;
.supportsLocalVoiceInteraction();
}
+ @GuardedBy("this")
void onLocalVoiceInteractionStartedLocked(IBinder activity,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
ActivityRecord activityToCallback = ActivityRecord.forTokenLocked(activity);
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- ActivityOptions options = ActivityOptions.fromBundle(bOptions);
+ SafeActivityOptions options = SafeActivityOptions.fromBundle(bOptions);
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(callingActivity);
if (r == null) {
- ActivityOptions.abort(options);
+ SafeActivityOptions.abort(options);
return false;
}
if (r.app == null || r.app.thread == null) {
// The caller is not running... d'oh!
- ActivityOptions.abort(options);
+ SafeActivityOptions.abort(options);
return false;
}
intent = new Intent(intent);
if (aInfo == null) {
// Nobody who is next!
- ActivityOptions.abort(options);
+ SafeActivityOptions.abort(options);
if (debug) Slog.d(TAG, "Next matching activity: nothing found");
return false;
}
Intent.FLAG_ACTIVITY_FORWARD_RESULT|
Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
- Intent.FLAG_ACTIVITY_NEW_TASK));
+ FLAG_ACTIVITY_NEW_TASK));
// Okay now we need to start the new activity, replacing the
// currently running activity. This is a little tricky because
}
final long origId = Binder.clearCallingIdentity();
- int res = mActivityStarter.startActivityLocked(r.app.thread, intent,
- null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
- null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
- r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
- false, false, null, null, null);
+ // TODO(b/64750076): Check if calling pid should really be -1.
+ final int res = mActivityStartController
+ .obtainStarter(intent, "startNextMatchingActivity")
+ .setCaller(r.app.thread)
+ .setResolvedType(r.resolvedType)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo != null ? resultTo.appToken : null)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setCallingPid(-1)
+ .setCallingUid(r.launchedFromUid)
+ .setCallingPackage(r.launchedFromPackage)
+ .setRealCallingPid(-1)
+ .setRealCallingUid(r.launchedFromUid)
+ .setActivityOptions(options)
+ .execute();
Binder.restoreCallingIdentity(origId);
r.finishing = wasFinishing;
@Override
public final int startActivityFromRecents(int taskId, Bundle bOptions) {
- if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
- String msg = "Permission Denial: startActivityFromRecents called without " +
- START_TASKS_FROM_RECENTS;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
+ enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
+ "startActivityFromRecents()");
+
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
- return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
+ return mStackSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
+ safeOptions);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- final int startActivityInPackage(int uid, String callingPackage,
- Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
- IActivityContainer container, TaskRecord inTask) {
-
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
-
- // TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, null, bOptions, false, userId, container, inTask);
- return ret;
- }
-
@Override
public final int startActivities(IApplicationThread caller, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
int userId) {
- enforceNotIsolatedCaller("startActivities");
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivity", null);
- // TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
- resolvedTypes, resultTo, bOptions, userId);
- return ret;
- }
-
- final int startActivitiesInPackage(int uid, String callingPackage,
- Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- Bundle bOptions, int userId) {
-
+ final String reason = "startActivities";
+ enforceNotIsolatedCaller(reason);
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
+ userId, false, ALLOW_FULL_ONLY, reason, null);
// TODO: Switch to user app stacks here.
- int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
- resultTo, bOptions, userId);
+ int ret = mActivityStartController.startActivities(caller, -1, 0,
+ UserHandle.USER_NULL, callingPackage, intents, resolvedTypes, resultTo,
+ SafeActivityOptions.fromBundle(bOptions), userId, reason,
+ null /* originatingPendingIntent */);
return ret;
}
@Override
- public void reportActivityFullyDrawn(IBinder token) {
+ public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) {
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r == null) {
return;
}
- r.reportFullyDrawnLocked();
+ r.reportFullyDrawnLocked(restoredFromBundle);
}
}
if (r == null) {
return;
}
- TaskRecord task = r.task;
- if (task != null && (!task.mFullscreen || !task.stack.mFullscreen)) {
- // Fixed screen orientation isn't supported when activities aren't in full screen
- // mode.
- return;
- }
final long origId = Binder.clearCallingIdentity();
- mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
- Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
- if (config != null) {
- r.frozenBeforeDestroy = true;
- if (!updateConfigurationLocked(config, r, false)) {
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- }
+ try {
+ r.setRequestedOrientation(requestedOrientation);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- Binder.restoreCallingIdentity(origId);
}
}
if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return mWindowManager.getAppOrientation(r.appToken);
+ return r.getRequestedOrientation();
}
}
return true;
}
// Keep track of the root activity of the task before we finish it
- TaskRecord tr = r.task;
+ TaskRecord tr = r.getTask();
ActivityRecord rootR = tr.getRootActivity();
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
}
// Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
// finish.
- if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV && rootR == r &&
- mStackSupervisor.isLastLockedTask(tr)) {
- Slog.i(TAG, "Not finishing task in lock task mode");
- mStackSupervisor.showLockTaskToast();
+ if (mLockTaskController.activityBlockedFromFinish(r)) {
return false;
}
+
if (mController != null) {
// Find the first activity that is not finishing.
- ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
+ ActivityRecord next = r.getStack().topRunningActivityLocked(token, 0);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
// because we don't support returning them across task boundaries. Also, to
// keep backwards compatibility we remove the task from recents when finishing
// task with root activity.
- res = removeTaskByIdLocked(tr.taskId, false, finishWithRootActivity);
+ res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
+ finishWithRootActivity, "finish-activity");
if (!res) {
Slog.i(TAG, "Removing task failed to finish activity");
}
} else {
- res = tr.stack.requestFinishActivityLocked(token, resultCode,
+ res = tr.getStack().requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
if (!res) {
Slog.i(TAG, "Failed to finish by app-request");
}
synchronized(this) {
- if (mHeavyWeightProcess == null) {
+ final ProcessRecord proc = mHeavyWeightProcess;
+ if (proc == null) {
return;
}
- ArrayList<ActivityRecord> activities = new ArrayList<>(mHeavyWeightProcess.activities);
+ ArrayList<ActivityRecord> activities = new ArrayList<>(proc.activities);
for (int i = 0; i < activities.size(); i++) {
ActivityRecord r = activities.get(i);
if (!r.finishing && r.isInStackLocked()) {
- r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+ r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
null, "finish-heavy", true);
}
}
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
- mHeavyWeightProcess.userId, 0));
+ proc.userId, 0));
mHeavyWeightProcess = null;
}
}
@Override
- public void crashApplication(int uid, int initialPid, String packageName,
+ public void crashApplication(int uid, int initialPid, String packageName, int userId,
String message) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
}
synchronized(this) {
- mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, message);
+ mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message);
}
}
final long origId = Binder.clearCallingIdentity();
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.task.stack.finishSubActivityLocked(r, resultWho, requestCode);
+ r.getStack().finishSubActivityLocked(r, resultWho, requestCode);
}
Binder.restoreCallingIdentity(origId);
}
// Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
// can finish.
- final TaskRecord task = r.task;
- if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV &&
- mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
- mStackSupervisor.showLockTaskToast();
+ final TaskRecord task = r.getTask();
+ if (mLockTaskController.activityBlockedFromFinish(r)) {
return false;
}
- return task.stack.finishActivityAffinityLocked(r);
+ return task.getStack().finishActivityAffinityLocked(r);
} finally {
Binder.restoreCallingIdentity(origId);
}
if (r == null) {
return false;
}
- return r.task.stack.safelyDestroyActivityLocked(r, "app-req");
+ return r.getStack().safelyDestroyActivityLocked(r, "app-req");
} finally {
Binder.restoreCallingIdentity(origId);
}
final long origId = Binder.clearCallingIdentity();
- if (self.state == ActivityState.RESUMED
- || self.state == ActivityState.PAUSING) {
+ if (self.isState(ActivityState.RESUMED, ActivityState.PAUSING)) {
mWindowManager.overridePendingAppTransition(packageName,
enterAnim, exitAnim, null);
}
* as a result of that process going away. Clears out all connections
* to the process.
*/
+ @GuardedBy("this")
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
// Remove this application's activities from active lists.
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
+ app.clearRecentTasks();
+
app.activities.clear();
- if (app.instrumentationClass != null) {
+ if (app.instr != null) {
Slog.w(TAG, "Crash of app " + app.processName
- + " running instrumentation " + app.instrumentationClass);
+ + " running instrumentation " + app.instr.mClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
}
- if (!restarting && hasVisibleActivities
- && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
- // If there was nothing to resume, and we are not already restarting this process, but
- // there is a visible activity that is hosted by the process... then make sure all
- // visible activities are running, taking care of restarting this process.
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ mWindowManager.deferSurfaceLayout();
+ try {
+ if (!restarting && hasVisibleActivities
+ && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+ // If there was nothing to resume, and we are not already restarting this process, but
+ // there is a visible activity that is hosted by the process... then make sure all
+ // visible activities are running, taking care of restarting this process.
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ }
+ } finally {
+ mWindowManager.continueSurfaceLayout();
}
+
}
private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
- IBinder threadBinder = thread.asBinder();
+ final IBinder threadBinder = thread.asBinder();
// Find the application record.
for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
+ final ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
return i;
}
return -1;
}
- final ProcessRecord getRecordForAppLocked(
- IApplicationThread thread) {
+ ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
if (thread == null) {
return null;
}
int appIndex = getLRURecordIndexForAppLocked(thread);
- return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
+ if (appIndex >= 0) {
+ return mLruProcesses.get(appIndex);
+ }
+
+ // Validation: if it isn't in the LRU list, it shouldn't exist, but let's
+ // double-check that.
+ final IBinder threadBinder = thread.asBinder();
+ final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
+ for (int i = pmap.size()-1; i >= 0; i--) {
+ final SparseArray<ProcessRecord> procs = pmap.valueAt(i);
+ for (int j = procs.size()-1; j >= 0; j--) {
+ final ProcessRecord proc = procs.valueAt(j);
+ if (proc.thread != null && proc.thread.asBinder() == threadBinder) {
+ Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "
+ + proc);
+ return proc;
+ }
+ }
+ }
+
+ return null;
}
final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
rec.setProcState, rec.adjType, rec.makeAdjReason()));
}
- if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+ if ((rec.lastLowMemory+mConstants.GC_MIN_INTERVAL) <= now) {
// The low memory report is overriding any current
// state for a GC request. Make sure to do
// heavy/important/visible/foreground processes first.
}
}
+ @GuardedBy("this")
final void appDiedLocked(ProcessRecord app) {
appDiedLocked(app, app.pid, app.thread, false);
}
+ @GuardedBy("this")
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
boolean fromBinderDied) {
// First check if this ProcessRecord is actually active for the pid.
if (!app.killed) {
if (!fromBinderDied) {
- Process.killProcessQuiet(pid);
+ killProcessQuiet(pid);
}
killProcessGroup(app.uid, pid);
app.killed = true;
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- boolean doLowMem = app.instrumentationClass == null;
+ boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
- Slog.i(TAG, "Process " + app.processName + " (pid " + pid
- + ") has died");
+ reportUidInfoMessageLocked(TAG,
+ "Process " + app.processName + " (pid " + pid + ") has died: "
+ + ProcessList.makeOomAdjString(app.setAdj)
+ + ProcessList.makeProcStateString(app.setProcState), app.info.uid);
mAllowLowerMemLevel = true;
} else {
// Note that we always want to do oom adj to update our state with the
mAllowLowerMemLevel = false;
doLowMem = false;
}
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
+ app.setAdj, app.setProcState);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
handleAppDiedLocked(app, false, true);
}
} else if (app.pid != pid) {
// A new process has already been started.
- Slog.i(TAG, "Process " + app.processName + " (pid " + pid
- + ") has died and restarted (pid " + app.pid + ").");
+ reportUidInfoMessageLocked(TAG,
+ "Process " + app.processName + " (pid " + pid
+ + ") has died and restarted (pid " + app.pid + ").", app.info.uid);
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
} else if (DEBUG_PROCESSES) {
Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
+ thread.asBinder());
}
+
+ // On the device which doesn't have Cgroup, log LmkStateChanged which is used as a signal
+ // for pulling memory stats of other running processes when this process died.
+ if (!hasMemcg()) {
+ StatsLog.write(StatsLog.APP_DIED, SystemClock.elapsedRealtime());
+ }
}
/**
* appended to any existing file content.
* @param firstPids of dalvik VM processes to dump stack traces for first
* @param lastPids of dalvik VM processes to dump stack traces for last
- * @param nativeProcs optional list of native process names to dump stack crawls
- * @return file containing stack traces, or null if no dump file is configured
+ * @param nativePids optional list of native pids to dump stack crawls
*/
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,
- ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
- String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
- if (tracesPath == null || tracesPath.length() == 0) {
- return null;
+ ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
+ ArrayList<Integer> nativePids) {
+ ArrayList<Integer> extraPids = null;
+
+ // Measure CPU usage as soon as we're called in order to get a realistic sampling
+ // of the top users at the time of the request.
+ if (processCpuTracker != null) {
+ processCpuTracker.init();
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ignored) {
+ }
+
+ processCpuTracker.update();
+
+ // We'll take the stack crawls of just the top apps using CPU.
+ final int N = processCpuTracker.countWorkingStats();
+ extraPids = new ArrayList<>();
+ for (int i = 0; i < N && extraPids.size() < 5; i++) {
+ ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
+ if (lastPids.indexOfKey(stats.pid) >= 0) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);
+
+ extraPids.add(stats.pid);
+ } else if (DEBUG_ANR) {
+ Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
+ + stats.pid);
+ }
+ }
}
- File tracesFile = new File(tracesPath);
- try {
- if (clearTraces && tracesFile.exists()) tracesFile.delete();
- tracesFile.createNewFile();
- FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
- } catch (IOException e) {
- Slog.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
- return null;
+ boolean useTombstonedForJavaTraces = false;
+ File tracesFile;
+
+ final String tracesDirProp = SystemProperties.get("dalvik.vm.stack-trace-dir", "");
+ if (tracesDirProp.isEmpty()) {
+ // When dalvik.vm.stack-trace-dir is not set, we are using the "old" trace
+ // dumping scheme. All traces are written to a global trace file (usually
+ // "/data/anr/traces.txt") so the code below must take care to unlink and recreate
+ // the file if requested.
+ //
+ // This mode of operation will be removed in the near future.
+
+
+ String globalTracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
+ if (globalTracesPath.isEmpty()) {
+ Slog.w(TAG, "dumpStackTraces: no trace path configured");
+ return null;
+ }
+
+ tracesFile = new File(globalTracesPath);
+ try {
+ if (clearTraces && tracesFile.exists()) {
+ tracesFile.delete();
+ }
+
+ tracesFile.createNewFile();
+ FileUtils.setPermissions(globalTracesPath, 0666, -1, -1); // -rw-rw-rw-
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to prepare ANR traces file: " + tracesFile, e);
+ return null;
+ }
+ } else {
+ File tracesDir = new File(tracesDirProp);
+ // When dalvik.vm.stack-trace-dir is set, we use the "new" trace dumping scheme.
+ // Each set of ANR traces is written to a separate file and dumpstate will process
+ // all such files and add them to a captured bug report if they're recent enough.
+ maybePruneOldTraces(tracesDir);
+
+ // NOTE: We should consider creating the file in native code atomically once we've
+ // gotten rid of the old scheme of dumping and lot of the code that deals with paths
+ // can be removed.
+ tracesFile = createAnrDumpFile(tracesDir);
+ if (tracesFile == null) {
+ return null;
+ }
+
+ useTombstonedForJavaTraces = true;
}
- dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativeProcs);
+ dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids,
+ useTombstonedForJavaTraces);
return tracesFile;
}
- private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
- ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
- // Use a FileObserver to detect when traces finish writing.
- // The order of traces is considered important to maintain for legibility.
- FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
- @Override
- public synchronized void onEvent(int event, String path) { notify(); }
- };
+ @GuardedBy("ActivityManagerService.class")
+ private static SimpleDateFormat sAnrFileDateFormat;
+
+ private static synchronized File createAnrDumpFile(File tracesDir) {
+ if (sAnrFileDateFormat == null) {
+ sAnrFileDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
+ }
+
+ final String formattedDate = sAnrFileDateFormat.format(new Date());
+ final File anrFile = new File(tracesDir, "anr_" + formattedDate);
try {
- observer.startWatching();
+ if (anrFile.createNewFile()) {
+ FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw-------
+ return anrFile;
+ } else {
+ Slog.w(TAG, "Unable to create ANR dump file: createNewFile failed");
+ }
+ } catch (IOException ioe) {
+ Slog.w(TAG, "Exception creating ANR dump file:", ioe);
+ }
- // First collect all of the stacks of the most important pids.
- if (firstPids != null) {
- try {
- int num = firstPids.size();
- for (int i = 0; i < num; i++) {
- synchronized (observer) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
- + firstPids.get(i));
- final long sime = SystemClock.elapsedRealtime();
- Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
- observer.wait(1000); // Wait for write-close, give up after 1 sec
- if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
- + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
- }
+ return null;
+ }
+
+ /**
+ * Prune all trace files that are more than a day old.
+ *
+ * NOTE: It might make sense to move this functionality to tombstoned eventually, along with a
+ * shift away from anr_XX and tombstone_XX to a more descriptive name. We do it here for now
+ * since it's the system_server that creates trace files for most ANRs.
+ */
+ private static void maybePruneOldTraces(File tracesDir) {
+ final long now = System.currentTimeMillis();
+ final File[] traceFiles = tracesDir.listFiles();
+
+ if (traceFiles != null) {
+ for (File file : traceFiles) {
+ if ((now - file.lastModified()) > DAY_IN_MILLIS) {
+ if (!file.delete()) {
+ Slog.w(TAG, "Unable to prune stale trace file: " + file);
}
+ }
+ }
+ }
+ }
+
+ /**
+ * Legacy code, do not use. Existing users will be deleted.
+ *
+ * @deprecated
+ */
+ @Deprecated
+ public static class DumpStackFileObserver extends FileObserver {
+ // Keep in sync with frameworks/native/cmds/dumpstate/utils.cpp
+ private static final int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
+
+ private final String mTracesPath;
+ private boolean mClosed;
+
+ public DumpStackFileObserver(String tracesPath) {
+ super(tracesPath, FileObserver.CLOSE_WRITE);
+ mTracesPath = tracesPath;
+ }
+
+ @Override
+ public synchronized void onEvent(int event, String path) {
+ mClosed = true;
+ notify();
+ }
+
+ public long dumpWithTimeout(int pid, long timeout) {
+ sendSignal(pid, SIGNAL_QUIT);
+ final long start = SystemClock.elapsedRealtime();
+
+ final long waitTime = Math.min(timeout, TRACE_DUMP_TIMEOUT_MS);
+ synchronized (this) {
+ try {
+ wait(waitTime); // Wait for traces file to be closed.
} catch (InterruptedException e) {
Slog.wtf(TAG, e);
}
}
- // Next collect the stacks of the native pids
- if (nativeProcs != null) {
- int[] pids = Process.getPidsForCommands(nativeProcs);
- if (pids != null) {
- for (int pid : pids) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
- final long sime = SystemClock.elapsedRealtime();
- Debug.dumpNativeBacktraceToFile(pid, tracesPath);
- if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
- + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
+ // This avoids a corner case of passing a negative time to the native
+ // trace in case we've already hit the overall timeout.
+ final long timeWaited = SystemClock.elapsedRealtime() - start;
+ if (timeWaited >= timeout) {
+ return timeWaited;
+ }
+
+ if (!mClosed) {
+ Slog.w(TAG, "Didn't see close of " + mTracesPath + " for pid " + pid +
+ ". Attempting native stack collection.");
+
+ final long nativeDumpTimeoutMs = Math.min(
+ NATIVE_DUMP_TIMEOUT_MS, timeout - timeWaited);
+
+ Debug.dumpNativeBacktraceToFileTimeout(pid, mTracesPath,
+ (int) (nativeDumpTimeoutMs / 1000));
+ }
+
+ final long end = SystemClock.elapsedRealtime();
+ mClosed = false;
+
+ return (end - start);
+ }
+ }
+
+ /**
+ * Dump java traces for process {@code pid} to the specified file. If java trace dumping
+ * fails, a native backtrace is attempted. Note that the timeout {@code timeoutMs} only applies
+ * to the java section of the trace, a further {@code NATIVE_DUMP_TIMEOUT_MS} might be spent
+ * attempting to obtain native traces in the case of a failure. Returns the total time spent
+ * capturing traces.
+ */
+ private static long dumpJavaTracesTombstoned(int pid, String fileName, long timeoutMs) {
+ final long timeStart = SystemClock.elapsedRealtime();
+ if (!Debug.dumpJavaBacktraceToFileTimeout(pid, fileName, (int) (timeoutMs / 1000))) {
+ Debug.dumpNativeBacktraceToFileTimeout(pid, fileName,
+ (NATIVE_DUMP_TIMEOUT_MS / 1000));
+ }
+
+ return SystemClock.elapsedRealtime() - timeStart;
+ }
+
+ private static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
+ ArrayList<Integer> nativePids, ArrayList<Integer> extraPids,
+ boolean useTombstonedForJavaTraces) {
+
+ // We don't need any sort of inotify based monitoring when we're dumping traces via
+ // tombstoned. Data is piped to an "intercept" FD installed in tombstoned so we're in full
+ // control of all writes to the file in question.
+ final DumpStackFileObserver observer;
+ if (useTombstonedForJavaTraces) {
+ observer = null;
+ } else {
+ // Use a FileObserver to detect when traces finish writing.
+ // The order of traces is considered important to maintain for legibility.
+ observer = new DumpStackFileObserver(tracesFile);
+ }
+
+ // We must complete all stack dumps within 20 seconds.
+ long remainingTime = 20 * 1000;
+ try {
+ if (observer != null) {
+ observer.startWatching();
+ }
+
+ // First collect all of the stacks of the most important pids.
+ if (firstPids != null) {
+ int num = firstPids.size();
+ for (int i = 0; i < num; i++) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
+ + firstPids.get(i));
+ final long timeTaken;
+ if (useTombstonedForJavaTraces) {
+ timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile, remainingTime);
+ } else {
+ timeTaken = observer.dumpWithTimeout(firstPids.get(i), remainingTime);
+ }
+
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +
+ "); deadline exceeded.");
+ return;
+ }
+
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
}
}
}
- // Lastly, measure CPU usage.
- if (processCpuTracker != null) {
- processCpuTracker.init();
- System.gc();
- processCpuTracker.update();
- try {
- synchronized (processCpuTracker) {
- processCpuTracker.wait(500); // measure over 1/2 second.
+ // Next collect the stacks of the native pids
+ if (nativePids != null) {
+ for (int pid : nativePids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
+ final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime);
+
+ final long start = SystemClock.elapsedRealtime();
+ Debug.dumpNativeBacktraceToFileTimeout(
+ pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000));
+ final long timeTaken = SystemClock.elapsedRealtime() - start;
+
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
+ "); deadline exceeded.");
+ return;
+ }
+
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms");
}
- } catch (InterruptedException e) {
}
- processCpuTracker.update();
+ }
- // We'll take the stack crawls of just the top apps using CPU.
- final int N = processCpuTracker.countWorkingStats();
- int numProcs = 0;
- for (int i=0; i<N && numProcs<5; i++) {
- ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
- if (lastPids.indexOfKey(stats.pid) >= 0) {
- numProcs++;
- try {
- synchronized (observer) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
- + stats.pid);
- final long stime = SystemClock.elapsedRealtime();
- Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
- observer.wait(1000); // Wait for write-close, give up after 1 sec
- if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
- + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
- }
- } catch (InterruptedException e) {
- Slog.wtf(TAG, e);
- }
- } else if (DEBUG_ANR) {
- Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
- + stats.pid);
+ // Lastly, dump stacks for all extra PIDs from the CPU tracker.
+ if (extraPids != null) {
+ for (int pid : extraPids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + pid);
+
+ final long timeTaken;
+ if (useTombstonedForJavaTraces) {
+ timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime);
+ } else {
+ timeTaken = observer.dumpWithTimeout(pid, remainingTime);
+ }
+
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
+ "); deadline exceeded.");
+ return;
+ }
+
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms");
}
}
}
} finally {
- observer.stopWatching();
+ if (observer != null) {
+ observer.stopWatching();
+ }
}
}
final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
- if (true || IS_USER_BUILD) {
+ if (true || Build.IS_USER) {
return;
}
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
return;
}
- if (app != null) {
+ if (app != null && app.pid > 0) {
ArrayList<Integer> firstPids = new ArrayList<Integer>();
firstPids.add(app.pid);
- dumpStackTraces(tracesPath, firstPids, null, null, null);
+ dumpStackTraces(tracesPath, firstPids, null, null, true /* useTombstoned */);
}
File lastTracesFile = null;
}
}
+ @GuardedBy("this")
final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
if (!mLaunchWarningShown) {
mLaunchWarningShown = true;
}
@Override
- public boolean clearApplicationUserData(final String packageName,
+ public boolean clearApplicationUserData(final String packageName, boolean keepState,
final IPackageDataObserver observer, int userId) {
enforceNotIsolatedCaller("clearApplicationUserData");
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
- userId = mUserController.handleIncomingUser(pid, uid, userId, false,
+ final int resolvedUserId = mUserController.handleIncomingUser(pid, uid, userId, false,
ALLOW_FULL_ONLY, "clearApplicationUserData", null);
+ final ApplicationInfo appInfo;
+ final boolean isInstantApp;
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
- int pkgUid = -1;
synchronized(this) {
+ // Instant packages are not protected
if (getPackageManagerInternalLocked().isPackageDataProtected(
- userId, packageName)) {
+ resolvedUserId, packageName)) {
throw new SecurityException(
"Cannot clear data for a protected package: " + packageName);
}
+ ApplicationInfo applicationInfo = null;
try {
- pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES, userId);
+ applicationInfo = pm.getApplicationInfo(packageName,
+ MATCH_UNINSTALLED_PACKAGES, resolvedUserId);
} catch (RemoteException e) {
+ /* ignore */
}
- if (pkgUid == -1) {
+ appInfo = applicationInfo;
+
+ final boolean clearingOwnUidData = appInfo != null && appInfo.uid == uid;
+
+ if (!clearingOwnUidData && checkComponentPermission(permission.CLEAR_APP_USER_DATA,
+ pid, uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("PID " + pid + " does not have permission "
+ + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data"
+ + " of package " + packageName);
+ }
+
+ final boolean hasInstantMetadata = getPackageManagerInternalLocked()
+ .hasInstantApplicationMetadata(packageName, resolvedUserId);
+ final boolean isUninstalledAppWithoutInstantMetadata =
+ (appInfo == null && !hasInstantMetadata);
+ isInstantApp = (appInfo != null && appInfo.isInstantApp())
+ || hasInstantMetadata;
+ final boolean canAccessInstantApps = checkComponentPermission(
+ permission.ACCESS_INSTANT_APPS, pid, uid, -1, true)
+ == PackageManager.PERMISSION_GRANTED;
+
+ if (isUninstalledAppWithoutInstantMetadata || (isInstantApp
+ && !canAccessInstantApps)) {
Slog.w(TAG, "Invalid packageName: " + packageName);
if (observer != null) {
try {
}
return false;
}
- if (uid == pkgUid || checkComponentPermission(
- android.Manifest.permission.CLEAR_APP_USER_DATA,
- pid, uid, -1, true)
- == PackageManager.PERMISSION_GRANTED) {
- forceStopPackageLocked(packageName, pkgUid, "clear data");
- } else {
- throw new SecurityException("PID " + pid + " does not have permission "
- + android.Manifest.permission.CLEAR_APP_USER_DATA + " to clear data"
- + " of package " + packageName);
- }
- // Remove all tasks match the cleared application package and user
- for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
- final TaskRecord tr = mRecentTasks.get(i);
- final String taskPackageName =
- tr.getBaseIntent().getComponent().getPackageName();
- if (tr.userId != userId) continue;
- if (!taskPackageName.equals(packageName)) continue;
- removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
+ if (appInfo != null) {
+ forceStopPackageLocked(packageName, appInfo.uid, "clear data");
+ mRecentTasks.removeTasksByPackageName(packageName, resolvedUserId);
}
}
- final int pkgUidF = pkgUid;
- final int userIdF = userId;
final IPackageDataObserver localObserver = new IPackageDataObserver.Stub() {
@Override
public void onRemoveCompleted(String packageName, boolean succeeded)
throws RemoteException {
- synchronized (ActivityManagerService.this) {
- finishForceStopPackageLocked(packageName, pkgUidF);
+ if (appInfo != null) {
+ synchronized (ActivityManagerService.this) {
+ finishForceStopPackageLocked(packageName, appInfo.uid);
+ }
}
-
final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
Uri.fromParts("package", packageName, null));
- intent.putExtra(Intent.EXTRA_UID, pkgUidF);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUidF));
- broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
- null, null, 0, null, null, null, null, false, false, userIdF);
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ intent.putExtra(Intent.EXTRA_UID, (appInfo != null) ? appInfo.uid : -1);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
+ if (isInstantApp) {
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
+ null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
+ resolvedUserId);
+ } else {
+ broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
+ null, null, null, null, false, false, resolvedUserId);
+ }
if (observer != null) {
observer.onRemoveCompleted(packageName, succeeded);
try {
// Clear application user data
- pm.clearApplicationUserData(packageName, localObserver, userId);
+ pm.clearApplicationUserData(packageName, localObserver, resolvedUserId);
+
+ if (appInfo != null) {
+ // Restore already established notification state and permission grants,
+ // so it told us to keep those intact -- it's about to emplace app data
+ // that is appropriate for those bits of system state.
+ if (!keepState) {
+ synchronized (this) {
+ // Remove all permissions granted from/to this package
+ removeUriPermissionsForPackageLocked(packageName, resolvedUserId, true,
+ false);
+ }
- synchronized(this) {
- // Remove all permissions granted from/to this package
- removeUriPermissionsForPackageLocked(packageName, userId, true);
- }
+ // Reset notification state
+ INotificationManager inm = NotificationManager.getService();
+ inm.clearData(packageName, appInfo.uid, uid == appInfo.uid);
+ }
- // Remove all zen rules created by this package; revoke it's zen access.
- INotificationManager inm = NotificationManager.getService();
- inm.removeAutomaticZenRules(packageName);
- inm.setNotificationPolicyAccessGranted(packageName, false);
+ // Clear its scheduled jobs
+ JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
+ js.cancelJobsForUid(appInfo.uid, "clear data");
+ // Clear its pending alarms
+ AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class);
+ ami.removeAlarmsForUid(appInfo.uid);
+ }
} catch (RemoteException e) {
}
} finally {
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
+ final int[] userIds = mUserController.expandUserId(userId);
+
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
- synchronized(this) {
+ for (int targetUserId : userIds) {
int appId = -1;
try {
appId = UserHandle.getAppId(
- pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
+ pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
+ targetUserId));
} catch (RemoteException e) {
}
if (appId == -1) {
Slog.w(TAG, "Invalid packageName: " + packageName);
return;
}
- killPackageProcessesLocked(packageName, appId, userId,
- ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
- }
+ synchronized (this) {
+ killPackageProcessesLocked(packageName, appId, targetUserId,
+ ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+ }
+ }
} finally {
Binder.restoreCallingIdentity(callingId);
}
int[] users = userId == UserHandle.USER_ALL
? mUserController.getUsers() : new int[] { userId };
for (int user : users) {
+ if (getPackageManagerInternalLocked().isPackageStateProtected(
+ packageName, user)) {
+ Slog.w(TAG, "Ignoring request to force stop protected package "
+ + packageName + " u" + user);
+ return;
+ }
+
int pkgUid = -1;
try {
pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
Slog.w(TAG, "Failed trying to unstop package "
+ packageName + ": " + e);
}
- if (mUserController.isUserRunningLocked(user, 0)) {
+ if (mUserController.isUserRunning(user, 0)) {
forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
finishForceStopPackageLocked(packageName, pkgUid);
}
public void addPackageDependency(String packageName) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
- if (callingPid == Process.myPid()) {
+ if (callingPid == myPid()) {
// Yeah, um, no.
return;
}
}
int callerUid = Binder.getCallingUid();
// Only the system server can kill an application
- if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
+ if (UserHandle.getAppId(callerUid) == SYSTEM_UID) {
// Post an aysnc message to kill the application
Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
msg.arg1 = appId;
synchronized (this) {
// Only allow this from foreground processes, so that background
// applications can't abuse it to prevent system UI from being shown.
- if (uid >= Process.FIRST_APPLICATION_UID) {
+ if (uid >= FIRST_APPLICATION_UID) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
}
}
+ @GuardedBy("this")
void closeSystemDialogsLocked(String reason) {
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
mStackSupervisor.closeSystemDialogsLocked();
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- AppOpsManager.OP_NONE, null, false, false,
- -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ OP_NONE, null, false, false,
+ -1, SYSTEM_UID, UserHandle.USER_ALL);
}
@Override
}
}
infos[i] = new Debug.MemoryInfo();
+ long startTime = SystemClock.currentThreadTimeMillis();
Debug.getMemoryInfo(pids[i], infos[i]);
+ long endTime = SystemClock.currentThreadTimeMillis();
if (proc != null) {
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
- infos[i].getTotalUss(), false, proc.pkgList);
+ infos[i].getTotalUss(), infos[i].getTotalRss(), false,
+ ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime-startTime,
+ proc.pkgList);
}
}
}
oomAdj = proc != null ? proc.setAdj : 0;
}
}
- long[] tmpUss = new long[1];
+ long[] tmpUss = new long[3];
+ long startTime = SystemClock.currentThreadTimeMillis();
pss[i] = Debug.getPss(pids[i], tmpUss, null);
+ long endTime = SystemClock.currentThreadTimeMillis();
if (proc != null) {
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
- proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false, proc.pkgList);
+ proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false,
+ ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList);
}
}
}
int callerUid = Binder.getCallingUid();
// Only the system server can kill an application
- if (callerUid == Process.SYSTEM_UID) {
+ if (callerUid == SYSTEM_UID) {
synchronized (this) {
ProcessRecord app = getProcessRecordLocked(processName, uid, true);
if (app != null && app.thread != null) {
}
}
+ @GuardedBy("this")
private void forceStopPackageLocked(final String packageName, int uid, String reason) {
forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
false, true, false, false, UserHandle.getUserId(uid), reason);
}
+ @GuardedBy("this")
private void finishForceStopPackageLocked(final String packageName, int uid) {
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
Uri.fromParts("package", packageName, null));
intent.putExtra(Intent.EXTRA_UID, uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
+ null, null, 0, null, null, null, OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
}
+ @GuardedBy("this")
private final boolean killPackageProcessesLocked(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
boolean doit, boolean evenPersistent, String reason) {
}
// Clean-up disabled tasks
- cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
+ mRecentTasks.cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
// Clean-up disabled services.
mServices.bringDownDisabledPackageServicesLocked(
return didSomething;
}
+ @GuardedBy("this")
final boolean forceStopPackageLocked(String packageName, int appId,
boolean callerWillRestart, boolean purgeCache, boolean doit,
boolean evenPersistent, boolean uninstalling, int userId, String reason) {
ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
+ didSomething |= mActivityStartController.clearPendingActivityLaunches(packageName);
+
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
packageName, null, doit, evenPersistent, userId)) {
if (!doit) {
}
// Remove transient permissions granted from/to this package/user
- removeUriPermissionsForPackageLocked(packageName, userId, false);
+ removeUriPermissionsForPackageLocked(packageName, userId, false, false);
if (doit) {
for (i = mBroadcastQueues.length - 1; i >= 0; i--) {
}
didSomething = true;
it.remove();
- pir.canceled = true;
+ makeIntentSenderCanceledLocked(pir);
if (pir.key.activity != null && pir.key.activity.pendingResults != null) {
pir.key.activity.pendingResults.remove(pir.ref);
}
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"No more processes in " + old.uidRecord);
enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
+ EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
}
// This is the first appearance of the uid, report it now!
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Creating new process uid: " + uidRec);
+ if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0
+ || mPendingTempWhitelist.indexOfKey(proc.uid) >= 0) {
+ uidRec.setWhitelist = uidRec.curWhitelist = true;
+ }
+ uidRec.updateHasInternetPermission();
mActiveUids.put(proc.uid, uidRec);
+ EventLogTags.writeAmUidRunning(uidRec.uid);
noteUidProcessState(uidRec.uid, uidRec.curProcState);
- enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
}
proc.uidRecord = uidRec;
}
}
+ @GuardedBy("this")
boolean removeProcessLocked(ProcessRecord app,
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
mHeavyWeightProcess = null;
}
boolean needRestart = false;
- if (app.pid > 0 && app.pid != MY_PID) {
+ if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
int pid = app.pid;
- synchronized (mPidsSelfLocked) {
- mPidsSelfLocked.remove(pid);
- mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
- }
- mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
- if (app.isolated) {
- mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+ if (pid > 0) {
+ synchronized (mPidsSelfLocked) {
+ mPidsSelfLocked.remove(pid);
+ mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
+ }
+ mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
+ if (app.isolated) {
+ mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+ getPackageManagerInternalLocked().removeIsolatedUid(app.uid);
+ }
}
boolean willRestart = false;
if (app.persistent && !app.isolated) {
handleAppDiedLocked(app, willRestart, allowRestart);
if (willRestart) {
removeLruProcessLocked(app);
- addAppLocked(app.info, false, null /* ABI override */);
+ addAppLocked(app.info, null, false, null /* ABI override */);
}
} else {
mRemovedProcesses.add(app);
return needRestart;
}
+ @GuardedBy("this")
private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
cleanupAppInLaunchingProvidersLocked(app, true);
removeProcessLocked(app, false, true, "timeout publishing content providers");
mHeavyWeightProcess = null;
}
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
- if (app.isolated) {
- mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
- }
// Take care of any launching providers waiting for this process.
cleanupAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
app.kill("start timeout", true);
+ if (app.isolated) {
+ mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+ }
removeLruProcessLocked(app);
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
- try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnected(app.info.packageName);
- } catch (RemoteException e) {
- // Can't happen; the backup manager is local
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run(){
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentDisconnected(app.info.packageName);
+ } catch (RemoteException e) {
+ // Can't happen; the backup manager is local
+ }
+ }
+ });
}
if (isPendingBroadcastProcessLocked(pid)) {
Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
}
}
+ @GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
- int pid) {
+ int pid, int callingUid, long startSeq) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
+ if (app != null && (app.startUid != callingUid || app.startSeq != startSeq)) {
+ String processName = null;
+ final ProcessRecord pending = mPendingStarts.get(startSeq);
+ if (pending != null) {
+ processName = pending.processName;
+ }
+ final String msg = "attachApplicationLocked process:" + processName
+ + " startSeq:" + startSeq
+ + " pid:" + pid
+ + " belongs to another existing app:" + app.processName
+ + " startSeq:" + app.startSeq;
+ Slog.wtf(TAG, msg);
+ // SafetyNet logging for b/131105245.
+ EventLog.writeEvent(0x534e4554, "131105245", app.startUid, msg);
+ // If there is already an app occupying that pid that hasn't been cleaned up
+ cleanUpApplicationRecordLocked(app, false, false, -1,
+ true /*replacingPid*/);
+ mPidsSelfLocked.remove(pid);
+ app = null;
+ }
} else {
app = null;
}
+ // It's possible that process called attachApplication before we got a chance to
+ // update the internal state.
+ if (app == null && startSeq > 0) {
+ final ProcessRecord pending = mPendingStarts.get(startSeq);
+ if (pending != null && pending.startUid == callingUid && pending.startSeq == startSeq
+ && handleProcessStartedLocked(pending, pid, pending.usingWrapper,
+ startSeq, true)) {
+ app = pending;
+ }
+ }
+
if (app == null) {
Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
- Process.killProcessQuiet(pid);
+ killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
} else {
try {
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- app.forcingToForeground = null;
+ app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
+ app.killed = false;
+
// We carefully use the same state that PackageManager uses for
// filtering, since we use this flag to decide if we need to install
}
checkTime(startTime, "attachApplicationLocked: before bindApplication");
-
+
if (!normalMode) {
Slog.i(TAG, "Launching preboot mode app: " + app);
}
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
try {
- int testMode = IApplicationThread.DEBUG_OFF;
+ int testMode = ApplicationThreadConstants.DEBUG_OFF;
if (mDebugApp != null && mDebugApp.equals(processName)) {
testMode = mWaitForDebugger
- ? IApplicationThread.DEBUG_WAIT
- : IApplicationThread.DEBUG_ON;
+ ? ApplicationThreadConstants.DEBUG_WAIT
+ : ApplicationThreadConstants.DEBUG_ON;
app.debugging = true;
if (mDebugTransient) {
mDebugApp = mOrigDebugApp;
mWaitForDebugger = mOrigWaitForDebugger;
}
}
- String profileFile = app.instrumentationProfileFile;
- ParcelFileDescriptor profileFd = null;
- int samplingInterval = 0;
- boolean profileAutoStop = false;
- if (mProfileApp != null && mProfileApp.equals(processName)) {
- mProfileProc = app;
- profileFile = mProfileFile;
- profileFd = mProfileFd;
- samplingInterval = mSamplingInterval;
- profileAutoStop = mAutoStopProfiler;
- }
+
boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
enableTrackAllocation = true;
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) {
- isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
+ isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
&& ((mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
- if (app.instrumentationClass != null) {
- notifyPackageUse(app.instrumentationClass.getPackageName(),
+ if (app.instr != null) {
+ notifyPackageUse(app.instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
- + processName + " with config " + mConfiguration);
- ApplicationInfo appInfo = app.instrumentationInfo != null
- ? app.instrumentationInfo : app.info;
+ + processName + " with config " + getGlobalConfiguration());
+ ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
- if (profileFd != null) {
- profileFd = profileFd.dup();
+
+ ProfilerInfo profilerInfo = null;
+ String preBindAgent = null;
+ if (mProfileApp != null && mProfileApp.equals(processName)) {
+ mProfileProc = app;
+ if (mProfilerInfo != null) {
+ // Send a profiler info object to the app if either a file is given, or
+ // an agent should be loaded at bind-time.
+ boolean needsInfo = mProfilerInfo.profileFile != null
+ || mProfilerInfo.attachAgentDuringBind;
+ profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
+ if (mProfilerInfo.agent != null) {
+ preBindAgent = mProfilerInfo.agent;
+ }
+ }
+ } else if (app.instr != null && app.instr.mProfileFile != null) {
+ profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
+ null, false);
+ }
+ if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
+ // We need to do a debuggable check here. See setAgentApp for why the check is
+ // postponed to here.
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ String agent = mAppAgentMap.get(processName);
+ // Do not overwrite already requested agent.
+ if (profilerInfo == null) {
+ profilerInfo = new ProfilerInfo(null, null, 0, false, false,
+ mAppAgentMap.get(processName), true);
+ } else if (profilerInfo.agent == null) {
+ profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
+ }
+ }
+ }
+
+ if (profilerInfo != null && profilerInfo.profileFd != null) {
+ profilerInfo.profileFd = profilerInfo.profileFd.dup();
+ if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) {
+ clearProfilerLocked();
+ }
+ }
+
+ // We deprecated Build.SERIAL and it is not accessible to
+ // apps that target the v2 security sandbox and to apps that
+ // target APIs higher than O MR1. Since access to the serial
+ // is now behind a permission we push down the value.
+ final String buildSerial = (appInfo.targetSandboxVersion < 2
+ && appInfo.targetSdkVersion < Build.VERSION_CODES.P)
+ ? sTheRealBuildSerial : Build.UNKNOWN;
+
+ // Check if this is a secondary process that should be incorporated into some
+ // currently active instrumentation. (Note we do this AFTER all of the profiling
+ // stuff above because profiling can currently happen only in the primary
+ // instrumentation process.)
+ if (mActiveInstrumentation.size() > 0 && app.instr == null) {
+ for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
+ ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
+ if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
+ if (aInstr.mTargetProcesses.length == 0) {
+ // This is the wildcard mode, where every process brought up for
+ // the target instrumentation should be included.
+ if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
+ app.instr = aInstr;
+ aInstr.mRunningProcesses.add(app);
+ }
+ } else {
+ for (String proc : aInstr.mTargetProcesses) {
+ if (proc.equals(app.processName)) {
+ app.instr = aInstr;
+ aInstr.mRunningProcesses.add(app);
+ break;
+ }
+ }
+ }
+ }
+ }
}
- ProfilerInfo profilerInfo = profileFile == null ? null
- : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+
+ // If we were asked to attach an agent on startup, do so now, before we're binding
+ // application code.
+ if (preBindAgent != null) {
+ thread.attachAgent(preBindAgent);
+ }
+
+
+ // Figure out whether the app needs to run in autofill compat mode.
+ boolean isAutofillCompatEnabled = false;
+ if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
+ final AutofillManagerInternal afm = LocalServices.getService(
+ AutofillManagerInternal.class);
+ if (afm != null) {
+ isAutofillCompatEnabled = afm.isCompatibilityModeRequested(
+ app.info.packageName, app.info.versionCode, app.userId);
+ }
+ }
+
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
- thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
- profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
- app.instrumentationUiAutomationConnection, testMode,
- mBinderTransactionTrackingEnabled, enableTrackAllocation,
- isRestrictedBackupMode || !normalMode, app.persistent,
- new Configuration(mConfiguration), app.compat,
- getCommonServicesLocked(app.isolated),
- mCoreSettingsObserver.getCoreSettingsLocked());
+ mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
+ if (app.isolatedEntryPoint != null) {
+ // This is an isolated process which should just call an entry point instead of
+ // being bound to an application.
+ thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
+ } else if (app.instr != null) {
+ thread.bindApplication(processName, appInfo, providers,
+ app.instr.mClass,
+ profilerInfo, app.instr.mArguments,
+ app.instr.mWatcher,
+ app.instr.mUiAutomationConnection, testMode,
+ mBinderTransactionTrackingEnabled, enableTrackAllocation,
+ isRestrictedBackupMode || !normalMode, app.persistent,
+ new Configuration(getGlobalConfiguration()), app.compat,
+ getCommonServicesLocked(app.isolated),
+ mCoreSettingsObserver.getCoreSettingsLocked(),
+ buildSerial, isAutofillCompatEnabled);
+ } else {
+ thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
+ null, null, null, testMode,
+ mBinderTransactionTrackingEnabled, enableTrackAllocation,
+ isRestrictedBackupMode || !normalMode, app.persistent,
+ new Configuration(getGlobalConfiguration()), app.compat,
+ getCommonServicesLocked(app.isolated),
+ mCoreSettingsObserver.getCoreSettingsLocked(),
+ buildSerial, isAutofillCompatEnabled);
+ }
+ if (profilerInfo != null) {
+ profilerInfo.closeFd();
+ profilerInfo = null;
+ }
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
}
// Check whether the next backup agent is in this process...
- if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
+ if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
"New app is backup target, launching agent for " + app);
notifyPackageUse(mBackupTarget.appInfo.packageName,
}
@Override
- public final void attachApplication(IApplicationThread thread) {
+ public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
- attachApplicationLocked(thread, callingPid);
+ attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
ActivityRecord r =
- mStackSupervisor.activityIdleInternalLocked(token, false, config);
+ mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
+ false /* processPausingActivities */, config);
if (stopProfiling) {
- if ((mProfileProc == r.app) && (mProfileFd != null)) {
- try {
- mProfileFd.close();
- } catch (IOException e) {
- }
+ if ((mProfileProc == r.app) && mProfilerInfo != null) {
clearProfilerLocked();
}
}
@Override
public void showBootMessage(final CharSequence msg, final boolean always) {
- if (Binder.getCallingUid() != Process.myUid()) {
+ if (Binder.getCallingUid() != myUid()) {
throw new SecurityException();
}
mWindowManager.showBootMessage(msg, always);
}
@Override
- public void keyguardWaitingForActivityDrawn() {
- enforceNotIsolatedCaller("keyguardWaitingForActivityDrawn");
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- if (DEBUG_LOCKSCREEN) logLockScreen("");
- mWindowManager.keyguardWaitingForActivityDrawn();
- if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
- mLockScreenShown = LOCK_SCREEN_LEAVING;
- updateSleepIfNeededLocked();
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
public void keyguardGoingAway(int flags) {
enforceNotIsolatedCaller("keyguardGoingAway");
final long token = Binder.clearCallingIdentity();
try {
synchronized (this) {
- if (DEBUG_LOCKSCREEN) logLockScreen("");
- mWindowManager.keyguardGoingAway(flags);
- if (mLockScreenShown == LOCK_SCREEN_SHOWN) {
- mLockScreenShown = LOCK_SCREEN_HIDDEN;
- updateSleepIfNeededLocked();
-
- // Some stack visibility might change (e.g. docked stack)
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- }
+ mKeyguardController.keyguardGoingAway(flags);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
+ /**
+ * @return whther the keyguard is currently locked.
+ */
+ boolean isKeyguardLocked() {
+ return mKeyguardController.isKeyguardLocked();
+ }
+
final void finishBooting() {
synchronized (this) {
if (!mBootAnimationComplete) {
ArraySet<String> completedIsas = new ArraySet<String>();
for (String abi : Build.SUPPORTED_ABIS) {
- Process.establishZygoteConnectionForAbi(abi);
+ zygoteProcess.establishZygoteConnectionForAbi(abi);
final String instructionSet = VMRuntime.getInstructionSet(abi);
if (!completedIsas.contains(instructionSet)) {
try {
startProcessLocked(procs.get(ip), "on-hold", null);
}
}
+ if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+ return;
+ }
+ // Start looking for apps that are abusing wake locks.
+ Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
+ mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);
+ // Tell anyone interested that we are done booting!
+ SystemProperties.set("sys.boot_completed", "1");
- if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- // Start looking for apps that are abusing wake locks.
- Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
- // Tell anyone interested that we are done booting!
- SystemProperties.set("sys.boot_completed", "1");
-
- // And trigger dev.bootcomplete if we are not showing encryption progress
- if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
+ // And trigger dev.bootcomplete if we are not showing encryption progress
+ if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
|| "".equals(SystemProperties.get("vold.encrypt_progress"))) {
- SystemProperties.set("dev.bootcomplete", "1");
- }
- mUserController.sendBootCompletedLocked(
- new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered,
- boolean sticky, int sendingUser) {
- synchronized (ActivityManagerService.this) {
- requestPssAllProcsLocked(SystemClock.uptimeMillis(),
- true, false);
- }
- }
- });
- scheduleStartProfilesLocked();
+ SystemProperties.set("dev.bootcomplete", "1");
}
+ mUserController.sendBootCompleted(
+ new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser) {
+ synchronized (ActivityManagerService.this) {
+ requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ }
+ }
+ });
+ mUserController.scheduleStartProfiles();
}
}
public final void activityResumed(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- stack.activityResumedLocked(token);
- }
+ ActivityRecord.activityResumedLocked(token);
+ mWindowManager.notifyAppResumedFinished(token);
}
Binder.restoreCallingIdentity(origId);
}
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
+ r.activityStoppedLocked(icicle, persistentState, description);
}
}
}
@Override
- public final void backgroundResourcesReleased(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- stack.backgroundResourcesReleased();
- }
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
public final void notifyLaunchTaskBehindComplete(IBinder token) {
mStackSupervisor.scheduleLaunchTaskBehindComplete(token);
}
userId = UserHandle.USER_CURRENT;
}
try {
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ if (callingUid != 0 && callingUid != SYSTEM_UID) {
final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid));
if (!UserHandle.isSameApp(callingUid, uid)) {
flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
|PendingIntent.FLAG_UPDATE_CURRENT);
- PendingIntentRecord.Key key = new PendingIntentRecord.Key(
- type, packageName, activity, resultWho,
- requestCode, intents, resolvedTypes, flags, bOptions, userId);
+ PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity,
+ resultWho, requestCode, intents, resolvedTypes, flags,
+ SafeActivityOptions.fromBundle(bOptions), userId);
WeakReference<PendingIntentRecord> ref;
ref = mIntentSenderRecords.get(key);
PendingIntentRecord rec = ref != null ? ref.get() : null;
}
return rec;
}
- rec.canceled = true;
+ makeIntentSenderCanceledLocked(rec);
mIntentSenderRecords.remove(key);
}
if (noCreate) {
}
@Override
- public int sendIntentSender(IIntentSender target, int code, Intent intent, String resolvedType,
+ public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
+ Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
if (target instanceof PendingIntentRecord) {
return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
- finishedReceiver, requiredPermission, options);
+ whitelistToken, finishedReceiver, requiredPermission, options);
} else {
if (intent == null) {
// Weird case: someone has given us their own custom IIntentSender, and now
intent = new Intent(Intent.ACTION_MAIN);
}
try {
- target.send(code, intent, resolvedType, null, requiredPermission, options);
+ target.send(code, intent, resolvedType, whitelistToken, null,
+ requiredPermission, options);
} catch (RemoteException e) {
}
// Platform code can rely on getting a result back when the send is done, but if
}
}
- /**
- * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
- *
- * <p>{@code callerUid} must be allowed to request such whitelist by calling
- * {@link #addTempPowerSaveWhitelistGrantorUid(int)}.
- */
- void tempWhitelistAppForPowerSave(int callerPid, int callerUid, int targetUid, long duration) {
- if (DEBUG_WHITELISTS) {
- Slog.d(TAG, "tempWhitelistAppForPowerSave(" + callerPid + ", " + callerUid + ", "
- + targetUid + ", " + duration + ")");
- }
- synchronized (mPidsSelfLocked) {
- final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
- if (pr == null) {
- Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " + callerPid);
- return;
- }
- if (!pr.whitelistManager) {
- if (DEBUG_WHITELISTS) {
- Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid + ": pid "
- + callerPid + " is not allowed");
- }
- return;
- }
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(targetUid, duration,
- true, "pe from uid:" + callerUid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
@Override
public void cancelIntentSender(IIntentSender sender) {
if (!(sender instanceof PendingIntentRecord)) {
String msg = "Permission Denial: cancelIntentSender() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
- + " is not allowed to cancel packges "
+ + " is not allowed to cancel package "
+ rec.key.packageName;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
- rec.canceled = true;
+ makeIntentSenderCanceledLocked(rec);
mIntentSenderRecords.remove(rec.key);
if (cleanActivity && rec.key.activity != null) {
rec.key.activity.pendingResults.remove(rec.ref);
}
}
+ void makeIntentSenderCanceledLocked(PendingIntentRecord rec) {
+ rec.canceled = true;
+ RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
+ if (callbacks != null) {
+ mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget();
+ }
+ }
+
@Override
public String getPackageForIntentSender(IIntentSender pendingResult) {
if (!(pendingResult instanceof PendingIntentRecord)) {
}
@Override
+ public void registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+ boolean isCancelled;
+ synchronized(this) {
+ PendingIntentRecord pendingIntent = (PendingIntentRecord) sender;
+ isCancelled = pendingIntent.canceled;
+ if (!isCancelled) {
+ pendingIntent.registerCancelListenerLocked(receiver);
+ }
+ }
+ if (isCancelled) {
+ try {
+ receiver.send(Activity.RESULT_CANCELED, null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void unregisterIntentSenderCancelListener(IIntentSender sender,
+ IResultReceiver receiver) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+ synchronized(this) {
+ ((PendingIntentRecord)sender).unregisterCancelListenerLocked(receiver);
+ }
+ }
+
+ @Override
public int getUidForIntentSender(IIntentSender sender) {
if (sender instanceof PendingIntentRecord) {
try {
}
@Override
+ public boolean isIntentSenderAForegroundService(IIntentSender pendingResult) {
+ if (pendingResult instanceof PendingIntentRecord) {
+ final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
+ return res.key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE;
+ }
+ return false;
+ }
+
+ @Override
public Intent getIntentForIntentSender(IIntentSender pendingResult) {
enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
"getIntentForIntentSender()");
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
synchronized (this) {
- mProcessLimit = max < 0 ? ProcessList.MAX_CACHED_APPS : max;
- mProcessLimitOverride = max;
+ mConstants.setOverrideMaxCachedProcesses(max);
}
trimApplications();
}
@Override
public int getProcessLimit() {
synchronized (this) {
- return mProcessLimitOverride;
+ return mConstants.getOverrideMaxCachedProcesses();
}
}
- void foregroundTokenDied(ForegroundToken token) {
+ void importanceTokenDied(ImportanceToken token) {
synchronized (ActivityManagerService.this) {
synchronized (mPidsSelfLocked) {
- ForegroundToken cur
- = mForegroundProcesses.get(token.pid);
+ ImportanceToken cur
+ = mImportantProcesses.get(token.pid);
if (cur != token) {
return;
}
- mForegroundProcesses.remove(token.pid);
+ mImportantProcesses.remove(token.pid);
ProcessRecord pr = mPidsSelfLocked.get(token.pid);
if (pr == null) {
return;
}
- pr.forcingToForeground = null;
+ pr.forcingToImportant = null;
updateProcessForegroundLocked(pr, false, false);
}
updateOomAdjLocked();
}
@Override
- public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
+ public void setProcessImportant(IBinder token, int pid, boolean isForeground, String reason) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
- "setProcessForeground()");
+ "setProcessImportant()");
synchronized(this) {
boolean changed = false;
Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
return;
}
- ForegroundToken oldToken = mForegroundProcesses.get(pid);
+ ImportanceToken oldToken = mImportantProcesses.get(pid);
if (oldToken != null) {
oldToken.token.unlinkToDeath(oldToken, 0);
- mForegroundProcesses.remove(pid);
+ mImportantProcesses.remove(pid);
if (pr != null) {
- pr.forcingToForeground = null;
+ pr.forcingToImportant = null;
}
changed = true;
}
if (isForeground && token != null) {
- ForegroundToken newToken = new ForegroundToken() {
+ ImportanceToken newToken = new ImportanceToken(pid, token, reason) {
@Override
public void binderDied() {
- foregroundTokenDied(this);
+ importanceTokenDied(this);
}
};
- newToken.pid = pid;
- newToken.token = token;
try {
token.linkToDeath(newToken, 0);
- mForegroundProcesses.put(pid, newToken);
- pr.forcingToForeground = token;
+ mImportantProcesses.put(pid, newToken);
+ pr.forcingToImportant = newToken;
changed = true;
} catch (RemoteException e) {
// If the process died while doing this, we will later
}
@Override
- public boolean isAppForeground(int uid) throws RemoteException {
+ public boolean isAppForeground(int uid) {
+ int callerUid = Binder.getCallingUid();
+ if (UserHandle.isCore(callerUid) || callerUid == uid) {
+ return isAppForegroundInternal(uid);
+ }
+ return false;
+ }
+
+ private boolean isAppForegroundInternal(int uid) {
synchronized (this) {
UidRecord uidRec = mActiveUids.get(uid);
if (uidRec == null || uidRec.idle) {
// be guarded by permission checking.
int getUidState(int uid) {
synchronized (this) {
- UidRecord uidRec = mActiveUids.get(uid);
- return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+ return getUidStateLocked(uid);
}
}
+ int getUidStateLocked(int uid) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+ }
+
@Override
public boolean isInMultiWindowMode(IBinder token) {
final long origId = Binder.clearCallingIdentity();
return false;
}
// An activity is consider to be in multi-window mode if its task isn't fullscreen.
- return !r.task.mFullscreen;
+ return r.inMultiWindowMode();
}
} finally {
Binder.restoreCallingIdentity(origId);
final long origId = Binder.clearCallingIdentity();
try {
synchronized(this) {
- final ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack == null) {
- return false;
- }
- return stack.mStackId == PINNED_STACK_ID;
+ return isInPictureInPictureMode(ActivityRecord.forTokenLocked(token));
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ private boolean isInPictureInPictureMode(ActivityRecord r) {
+ if (r == null || r.getStack() == null || !r.inPinnedWindowingMode()
+ || r.getStack().isInStackLocked(r) == null) {
+ return false;
+ }
+
+ // If we are animating to fullscreen then we have already dispatched the PIP mode
+ // changed, so we should reflect that check here as well.
+ final PinnedActivityStack stack = r.getStack();
+ final PinnedStackWindowController windowController = stack.getWindowContainerController();
+ return !windowController.isAnimatingBoundsToFullscreen();
+ }
+
@Override
- public void enterPictureInPictureMode(IBinder token) {
+ public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized(this) {
- if (!mSupportsPictureInPicture) {
- throw new IllegalStateException("enterPictureInPictureMode: "
- + "Device doesn't support picture-in-picture mode.");
- }
+ final ActivityRecord r = ensureValidPictureInPictureActivityParamsLocked(
+ "enterPictureInPictureMode", token, params);
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ // If the activity is already in picture in picture mode, then just return early
+ if (isInPictureInPictureMode(r)) {
+ return true;
+ }
- if (r == null) {
- throw new IllegalStateException("enterPictureInPictureMode: "
- + "Can't find activity for token=" + token);
+ // Activity supports picture-in-picture, now check that we can enter PiP at this
+ // point, if it is
+ if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
+ false /* beforeStopping */)) {
+ return false;
}
- if (!r.supportsPictureInPicture()) {
- throw new IllegalArgumentException("enterPictureInPictureMode: "
- + "Picture-In-Picture not supported for r=" + r);
+ final Runnable enterPipRunnable = () -> {
+ // Only update the saved args from the args that are set
+ r.pictureInPictureArgs.copyOnlySet(params);
+ final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
+ final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
+ // Adjust the source bounds by the insets for the transition down
+ final Rect sourceBounds = new Rect(r.pictureInPictureArgs.getSourceRectHint());
+ mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, aspectRatio,
+ "enterPictureInPictureMode");
+ final PinnedActivityStack stack = r.getStack();
+ stack.setPictureInPictureAspectRatio(aspectRatio);
+ stack.setPictureInPictureActions(actions);
+ MetricsLoggerWrapper.logPictureInPictureEnter(mContext, r.appInfo.uid,
+ r.shortComponentName, r.supportsEnterPipOnTaskSwitch);
+ logPictureInPictureArgs(params);
+ };
+
+ if (isKeyguardLocked()) {
+ // If the keyguard is showing or occluded, then try and dismiss it before
+ // entering picture-in-picture (this will prompt the user to authenticate if the
+ // device is currently locked).
+ try {
+ dismissKeyguard(token, new KeyguardDismissCallback() {
+ @Override
+ public void onDismissSucceeded() throws RemoteException {
+ mHandler.post(enterPipRunnable);
+ }
+ }, null /* message */);
+ } catch (RemoteException e) {
+ // Local call
+ }
+ } else {
+ // Enter picture in picture immediately otherwise
+ enterPipRunnable.run();
}
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
- // Use the default launch bounds for pinned stack if it doesn't exist yet or use the
- // current bounds.
- final ActivityStack pinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID);
- final Rect bounds = (pinnedStack != null)
- ? pinnedStack.mBounds : mDefaultPinnedStackBounds;
+ @Override
+ public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ final ActivityRecord r = ensureValidPictureInPictureActivityParamsLocked(
+ "setPictureInPictureParams", token, params);
- mStackSupervisor.moveActivityToPinnedStackLocked(
- r, "enterPictureInPictureMode", bounds);
+ // Only update the saved args from the args that are set
+ r.pictureInPictureArgs.copyOnlySet(params);
+ if (r.inPinnedWindowingMode()) {
+ // If the activity is already in picture-in-picture, update the pinned stack now
+ // if it is not already expanding to fullscreen. Otherwise, the arguments will
+ // be used the next time the activity enters PiP
+ final PinnedActivityStack stack = r.getStack();
+ if (!stack.isAnimatingBoundsToFullscreen()) {
+ stack.setPictureInPictureAspectRatio(
+ r.pictureInPictureArgs.getAspectRatio());
+ stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
+ }
+ }
+ logPictureInPictureArgs(params);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
+ @Override
+ public int getMaxNumPictureInPictureActions(IBinder token) {
+ // Currently, this is a static constant, but later, we may change this to be dependent on
+ // the context of the activity
+ return 3;
+ }
+
+ private void logPictureInPictureArgs(PictureInPictureParams params) {
+ if (params.hasSetActions()) {
+ MetricsLogger.histogram(mContext, "tron_varz_picture_in_picture_actions_count",
+ params.getActions().size());
+ }
+ if (params.hasSetAspectRatio()) {
+ LogMaker lm = new LogMaker(MetricsEvent.ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED);
+ lm.addTaggedData(MetricsEvent.PICTURE_IN_PICTURE_ASPECT_RATIO, params.getAspectRatio());
+ MetricsLogger.action(lm);
+ }
+ }
+
+ /**
+ * Checks the state of the system and the activity associated with the given {@param token} to
+ * verify that picture-in-picture is supported for that activity.
+ *
+ * @return the activity record for the given {@param token} if all the checks pass.
+ */
+ private ActivityRecord ensureValidPictureInPictureActivityParamsLocked(String caller,
+ IBinder token, PictureInPictureParams params) {
+ if (!mSupportsPictureInPicture) {
+ throw new IllegalStateException(caller
+ + ": Device doesn't support picture-in-picture mode.");
+ }
+
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r == null) {
+ throw new IllegalStateException(caller
+ + ": Can't find activity for token=" + token);
+ }
+
+ if (!r.supportsPictureInPicture()) {
+ throw new IllegalStateException(caller
+ + ": Current activity does not support picture-in-picture.");
+ }
+
+ if (params.hasSetAspectRatio()
+ && !mWindowManager.isValidPictureInPictureAspectRatio(r.getStack().mDisplayId,
+ params.getAspectRatio())) {
+ final float minAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+ final float maxAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
+ throw new IllegalArgumentException(String.format(caller
+ + ": Aspect ratio is too extreme (must be between %f and %f).",
+ minAspectRatio, maxAspectRatio));
+ }
+
+ // Truncate the number of actions if necessary
+ params.truncateActions(getMaxNumPictureInPictureActions(token));
+
+ return r;
+ }
+
// =========================================================
// PROCESS INFO
// =========================================================
}
@Override
- public String[] getPackagesForUid(int uid) {
+ public int noteOp(String op, int uid, String packageName) {
+ return mActivityManagerService.mAppOpsService
+ .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName);
+ }
+
+ @Override
+ public String[] getPackagesForUid(int uid) {
return mActivityManagerService.mContext.getPackageManager()
.getPackagesForUid(uid);
}
try {
PermissionInfo info = mActivityManagerService.mContext.getPackageManager()
.getPermissionInfo(permission, 0);
- return info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS;
+ return (info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_DANGEROUS;
} catch (NameNotFoundException nnfe) {
Slog.e(TAG, "No such permission: "+ permission, nnfe);
}
return false;
}
+
+ @Override
+ public int getPackageUid(String packageName, int flags) {
+ try {
+ return mActivityManagerService.mContext.getPackageManager()
+ .getPackageUid(packageName, flags);
+ } catch (NameNotFoundException nnfe) {
+ return -1;
+ }
+ }
}
class IntentFirewallInterface implements IntentFirewall.AMSInterface {
}
}
- /**
- * This can be called with or without the global lock held.
- */
int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
if (pid == MY_PID) {
}
/**
+ * This can be called with or without the global lock held.
+ */
+ void enforcePermission(String permission, int pid, int uid, String func) {
+ if (checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
+ String msg = "Permission Denial: " + func + " from pid=" + pid + ", uid=" + uid
+ + " requires " + permission;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ /**
+ * This can be called with or without the global lock held.
+ */
+ void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
+ if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
+ enforceCallingPermission(permission, func);
+ }
+ }
+
+ /**
* Determine if UID is holding permissions required to access {@link Uri} in
* the given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
return readMet && writeMet;
}
- public int getAppStartMode(int uid, String packageName) {
+ public boolean isAppStartModeDisabled(int uid, String packageName) {
synchronized (this) {
- return checkAllowBackgroundLocked(uid, packageName, -1, true);
+ return getAppStartModeLocked(uid, packageName, 0, -1, false, true, false)
+ == ActivityManager.APP_START_MODE_DISABLED;
}
}
- int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
- boolean allowWhenForeground) {
- UidRecord uidRec = mActiveUids.get(uid);
- if (!mLenientBackgroundCheck) {
- if (!allowWhenForeground || uidRec == null
- || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
- packageName) != AppOpsManager.MODE_ALLOWED) {
+ // Unified app-op and target sdk check
+ int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
+ // Apps that target O+ are always subject to background check
+ if (packageTargetSdk >= Build.VERSION_CODES.O) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
+ }
+ return ActivityManager.APP_START_MODE_DELAYED_RIGID;
+ }
+ // ...and legacy apps get an AppOp check
+ int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
+ uid, packageName);
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
+ }
+ switch (appop) {
+ case AppOpsManager.MODE_ALLOWED:
+ // If force-background-check is enabled, restrict all apps that aren't whitelisted.
+ if (mForceBackgroundCheck &&
+ !UserHandle.isCore(uid) &&
+ !isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ true)) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Force background check: " +
+ uid + "/" + packageName + " restricted");
+ }
return ActivityManager.APP_START_MODE_DELAYED;
}
+ return ActivityManager.APP_START_MODE_NORMAL;
+ case AppOpsManager.MODE_IGNORED:
+ return ActivityManager.APP_START_MODE_DELAYED;
+ default:
+ return ActivityManager.APP_START_MODE_DELAYED_RIGID;
+ }
+ }
+
+ // Service launch is available to apps with run-in-background exemptions but
+ // some other background operations are not. If we're doing a check
+ // of service-launch policy, allow those callers to proceed unrestricted.
+ int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
+ // Persistent app?
+ if (mPackageManagerInt.isPackagePersistent(packageName)) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "App " + uid + "/" + packageName
+ + " is persistent; not restricted in background");
}
+ return ActivityManager.APP_START_MODE_NORMAL;
+ }
- } else if (uidRec == null || uidRec.idle) {
- if (callingPid >= 0) {
- ProcessRecord proc;
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(callingPid);
- }
- if (proc != null && proc.curProcState < ActivityManager.PROCESS_STATE_RECEIVER) {
- // Whoever is instigating this is in the foreground, so we will allow it
- // to go through.
+ // Non-persistent but background whitelisted?
+ if (uidOnBackgroundWhitelist(uid)) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "App " + uid + "/" + packageName
+ + " on background whitelist; not restricted in background");
+ }
+ return ActivityManager.APP_START_MODE_NORMAL;
+ }
+
+ // Is this app on the battery whitelist?
+ if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "App " + uid + "/" + packageName
+ + " on idle whitelist; not restricted in background");
+ }
+ return ActivityManager.APP_START_MODE_NORMAL;
+ }
+
+ // None of the service-policy criteria apply, so we apply the common criteria
+ return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
+ }
+
+ int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
+ int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+ + (uidRec != null ? uidRec.idle : false));
+ if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
+ boolean ephemeral;
+ if (uidRec == null) {
+ ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
+ UserHandle.getUserId(uid), packageName);
+ } else {
+ ephemeral = uidRec.ephemeral;
+ }
+
+ if (ephemeral) {
+ // We are hard-core about ephemeral apps not running in the background.
+ return ActivityManager.APP_START_MODE_DISABLED;
+ } else {
+ if (disabledOnly) {
+ // The caller is only interested in whether app starts are completely
+ // disabled for the given package (that is, it is an instant app). So
+ // we don't need to go further, which is all just seeing if we should
+ // apply a "delayed" mode for a regular app.
return ActivityManager.APP_START_MODE_NORMAL;
}
- }
- if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName)
- != AppOpsManager.MODE_ALLOWED) {
- return ActivityManager.APP_START_MODE_DELAYED;
+ final int startMode = (alwaysRestrict)
+ ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
+ : appServicesRestrictedInBackgroundLocked(uid, packageName,
+ packageTargetSdk);
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ + " pkg=" + packageName + " startMode=" + startMode
+ + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid, false)
+ + " onwhitelist(ei)=" + isOnDeviceIdleWhitelistLocked(uid, true));
+ }
+ if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
+ // This is an old app that has been forced into a "compatible as possible"
+ // mode of background check. To increase compatibility, we will allow other
+ // foreground apps to cause its services to start.
+ if (callingPid >= 0) {
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ if (proc != null &&
+ !ActivityManager.isProcStateBackground(proc.curProcState)) {
+ // Whoever is instigating this is in the foreground, so we will allow it
+ // to go through.
+ return ActivityManager.APP_START_MODE_NORMAL;
+ }
+ }
+ }
+ return startMode;
}
}
return ActivityManager.APP_START_MODE_NORMAL;
}
+ /**
+ * @return whether a UID is in the system, user or temp doze whitelist.
+ */
+ boolean isOnDeviceIdleWhitelistLocked(int uid, boolean allowExceptIdleToo) {
+ final int appId = UserHandle.getAppId(uid);
+
+ final int[] whitelist = allowExceptIdleToo
+ ? mDeviceIdleExceptIdleWhitelist
+ : mDeviceIdleWhitelist;
+
+ return Arrays.binarySearch(whitelist, appId) >= 0
+ || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0
+ || mPendingTempWhitelist.indexOfKey(uid) >= 0;
+ }
+
private ProviderInfo getProviderInfoLocked(String authority, int userHandle, int pmFlags) {
ProviderInfo pi = null;
ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userHandle);
return pi;
}
+ void grantEphemeralAccessLocked(int userId, Intent intent,
+ int targetAppId, int ephemeralAppId) {
+ getPackageManagerInternalLocked().
+ grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId);
+ }
+
+ @GuardedBy("this")
private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris != null) {
return null;
}
+ @GuardedBy("this")
private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
String targetPkg, int targetUid, GrantUri grantUri) {
ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
return perm;
}
+ @GuardedBy("this")
private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid,
final int modeFlags) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
* If you already know the uid of the target, you can supply it in
* lastTargetUid else set that to -1.
*/
+ @GuardedBy("this")
int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
final int modeFlags, int lastTargetUid) {
if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
}
+ // Bail early if system is trying to hand out permissions directly; it
+ // must always grant permissions on behalf of someone explicit.
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
+ if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
+ // Exempted authority for
+ // 1. cropping user photos and sharing a generated license html
+ // file in Settings app
+ // 2. sharing a generated license html file in TvSettings app
+ } else {
+ Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ + " grant to " + grantUri + "; use startActivityAsCaller() instead");
+ return -1;
+ }
+ }
+
final String authority = grantUri.uri.getAuthority();
final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId,
MATCH_DEBUG_TRIAGED_MISSING);
}
}
+ // Figure out the value returned when access is allowed
+ final int allowedResult;
+ if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
+ // If we're extending a persistable grant, then we need to return
+ // "targetUid" so that we always create a grant data structure to
+ // support take/release APIs
+ allowedResult = targetUid;
+ } else {
+ // Otherwise, we can return "-1" to indicate that no grant data
+ // structures need to be created
+ allowedResult = -1;
+ }
+
if (targetUid >= 0) {
// First... does the target actually need this permission?
if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Target " + targetPkg + " already has full permission to " + grantUri);
- return -1;
+ return allowedResult;
}
} else {
// First... there is no target package, so can anyone access it?
allowed = false;
}
}
+ if (pi.pathPermissions != null) {
+ final int N = pi.pathPermissions.length;
+ for (int i=0; i<N; i++) {
+ if (pi.pathPermissions[i] != null
+ && pi.pathPermissions[i].match(grantUri.uri.getPath())) {
+ if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ if (pi.pathPermissions[i].getReadPermission() != null) {
+ allowed = false;
+ }
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ if (pi.pathPermissions[i].getWritePermission() != null) {
+ allowed = false;
+ }
+ }
+ break;
+ }
+ }
+ }
if (allowed) {
- return -1;
+ return allowedResult;
}
}
// Third... does the caller itself have permission to access
// this uri?
- if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
- if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
- // Require they hold a strong enough Uri permission
- if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
- throw new SecurityException("Uid " + callingUid
- + " does not have permission to uri " + grantUri);
+ if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
+ // Require they hold a strong enough Uri permission
+ if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
+ if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
+ throw new SecurityException(
+ "UID " + callingUid + " does not have permission to " + grantUri
+ + "; you could obtain access using ACTION_OPEN_DOCUMENT "
+ + "or related APIs");
+ } else {
+ throw new SecurityException(
+ "UID " + callingUid + " does not have permission to " + grantUri);
}
}
}
}
}
+ @GuardedBy("this")
void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner) {
if (!Intent.isAccessUriMode(modeFlags)) {
perm.grantModes(modeFlags, owner);
}
+ @GuardedBy("this")
void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner, int targetUserId) {
if (targetPkg == null) {
this.targetUid = targetUid;
this.flags = flags;
}
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(NeededUriGrantsProto.TARGET_PACKAGE, targetPkg);
+ proto.write(NeededUriGrantsProto.TARGET_UID, targetUid);
+ proto.write(NeededUriGrantsProto.FLAGS, flags);
+
+ final int N = this.size();
+ for (int i=0; i<N; i++) {
+ this.get(i).writeToProto(proto, NeededUriGrantsProto.GRANTS);
+ }
+ proto.end(token);
+ }
}
/**
* Like checkGrantUriPermissionLocked, but takes an Intent.
*/
+ @GuardedBy("this")
NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
/**
* Like grantUriPermissionUncheckedLocked, but takes an Intent.
*/
+ @GuardedBy("this")
void grantUriPermissionUncheckedFromIntentLocked(NeededUriGrants needed,
UriPermissionOwner owner) {
if (needed != null) {
}
}
+ @GuardedBy("this")
void grantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId) {
NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg,
}
}
+ @GuardedBy("this")
void removeUriPermissionIfNeededLocked(UriPermission perm) {
if (perm.modeFlags == 0) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
}
}
- private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) {
+ @GuardedBy("this")
+ private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
+ final int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Revoking all granted permissions to " + grantUri);
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
if (perms != null) {
boolean persistChanged = false;
- for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
- final UriPermission perm = it.next();
+ for (int i = perms.size()-1; i >= 0; i--) {
+ final UriPermission perm = perms.valueAt(i);
+ if (targetPackage != null && !targetPackage.equals(perm.targetPkg)) {
+ continue;
+ }
if (perm.uri.sourceUserId == grantUri.sourceUserId
&& perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
persistChanged |= perm.revokeModes(
modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
if (perm.modeFlags == 0) {
- it.remove();
+ perms.removeAt(i);
}
}
}
boolean persistChanged = false;
// Go through all of the permissions and remove any that match.
- int N = mGrantedUriPermissions.size();
- for (int i = 0; i < N; i++) {
+ for (int i = mGrantedUriPermissions.size()-1; i >= 0; i--) {
final int targetUid = mGrantedUriPermissions.keyAt(i);
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
- final UriPermission perm = it.next();
+ for (int j = perms.size()-1; j >= 0; j--) {
+ final UriPermission perm = perms.valueAt(j);
+ if (targetPackage != null && !targetPackage.equals(perm.targetPkg)) {
+ continue;
+ }
if (perm.uri.sourceUserId == grantUri.sourceUserId
&& perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Revoking " + perm.targetUid + " permission to " + perm.uri);
persistChanged |= perm.revokeModes(
- modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
+ modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,
+ targetPackage == null);
if (perm.modeFlags == 0) {
- it.remove();
+ perms.removeAt(j);
}
}
}
if (perms.isEmpty()) {
- mGrantedUriPermissions.remove(targetUid);
- N--;
- i--;
+ mGrantedUriPermissions.removeAt(i);
}
}
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void revokeUriPermission(IApplicationThread caller, Uri uri, final int modeFlags,
- int userId) {
+ public void revokeUriPermission(IApplicationThread caller, String targetPackage, Uri uri,
+ final int modeFlags, int userId) {
enforceNotIsolatedCaller("revokeUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
return;
}
- revokeUriPermissionLocked(r.uid, new GrantUri(userId, uri, false), modeFlags);
+ revokeUriPermissionLocked(targetPackage, r.uid, new GrantUri(userId, uri, false),
+ modeFlags);
}
}
* @param userHandle User to match, or {@link UserHandle#USER_ALL} to apply
* to all users.
* @param persistable If persistable grants should be removed.
+ * @param targetOnly When {@code true}, only remove permissions where the app is the target,
+ * not source.
*/
+ @GuardedBy("this")
private void removeUriPermissionsForPackageLocked(
- String packageName, int userHandle, boolean persistable) {
+ String packageName, int userHandle, boolean persistable, boolean targetOnly) {
if (userHandle == UserHandle.USER_ALL && packageName == null) {
throw new IllegalArgumentException("Must narrow by either package or user");
}
final UriPermission perm = it.next();
// Only inspect grants matching package
- if (packageName == null || perm.sourcePkg.equals(packageName)
+ if (packageName == null || (!targetOnly && perm.sourcePkg.equals(packageName))
|| perm.targetPkg.equals(packageName)) {
// Hacky solution as part of fixing a security bug; ignore
// grants associated with DownloadManager so we don't have
throw new IllegalArgumentException("Unknown owner: " + token);
}
if (fromUid != Binder.getCallingUid()) {
- if (Binder.getCallingUid() != Process.myUid()) {
+ if (Binder.getCallingUid() != myUid()) {
// Only system code can grant URI permissions on behalf
// of other users.
throw new SecurityException("nice try");
private void writeGrantedUriPermissions() {
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "writeGrantedUriPermissions()");
+ final long startTime = SystemClock.uptimeMillis();
+
// Snapshot permissions so we can persist without lock
ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
synchronized (this) {
FileOutputStream fos = null;
try {
- fos = mGrantFile.startWrite();
+ fos = mGrantFile.startWrite(startTime);
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, StandardCharsets.UTF_8.name());
}
}
+ @GuardedBy("this")
private void readGrantedUriPermissionsLocked() {
if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
/**
* @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of package whose uri is being granted to (if {@code null}, uses
+ * calling uid)
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void takePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
- enforceNotIsolatedCaller("takePersistableUriPermission");
+ public void takePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+ final int uid;
+ if (toPackage != null) {
+ enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "takePersistableUriPermission");
+ uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("takePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
GrantUri grantUri = new GrantUri(userId, uri, false);
- UriPermission exactPerm = findUriPermissionLocked(callingUid,
- new GrantUri(userId, uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ UriPermission exactPerm = findUriPermissionLocked(uid, grantUri);
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, true));
final boolean exactValid = (exactPerm != null)
if (!(exactValid || prefixValid)) {
throw new SecurityException("No persistable permission grants found for UID "
- + callingUid + " and Uri " + grantUri.toSafeString());
+ + uid + " and Uri " + grantUri.toSafeString());
}
if (exactValid) {
persistChanged |= prefixPerm.takePersistableModes(modeFlags);
}
- persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
if (persistChanged) {
schedulePersistUriGrants();
/**
* @param uri This uri must NOT contain an embedded userId.
+ * @param toPackage Name of the target package whose uri is being released (if {@code null},
+ * uses calling uid)
* @param userId The userId in which the uri is to be resolved.
*/
@Override
- public void releasePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
- enforceNotIsolatedCaller("releasePersistableUriPermission");
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags,
+ @Nullable String toPackage, int userId) {
+
+ final int uid;
+ if (toPackage != null) {
+ enforceCallingPermission(android.Manifest.permission.FORCE_PERSISTABLE_URI_PERMISSIONS,
+ "releasePersistableUriPermission");
+ uid = mPackageManagerInt.getPackageUid(toPackage, 0, userId);
+ } else {
+ enforceNotIsolatedCaller("releasePersistableUriPermission");
+ uid = Binder.getCallingUid();
+ }
Preconditions.checkFlagsArgument(modeFlags,
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
synchronized (this) {
- final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
- UriPermission exactPerm = findUriPermissionLocked(callingUid,
+ UriPermission exactPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ UriPermission prefixPerm = findUriPermissionLocked(uid,
new GrantUri(userId, uri, true));
- if (exactPerm == null && prefixPerm == null) {
- throw new SecurityException("No permission grants found for UID " + callingUid
+ if (exactPerm == null && prefixPerm == null && toPackage == null) {
+ throw new SecurityException("No permission grants found for UID " + uid
+ " and Uri " + uri.toSafeString());
}
*
* @return if any mutations occured that require persisting.
*/
+ @GuardedBy("this")
private boolean maybePrunePersistedUriGrantsLocked(int uid) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
if (perms == null) {
Slog.w(TAG, "No permission grants found for " + packageName);
} else {
- for (UriPermission perm : perms.values()) {
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
for (int i = 0; i < size; i++) {
final ArrayMap<GrantUri, UriPermission> perms =
mGrantedUriPermissions.valueAt(i);
- for (UriPermission perm : perms.values()) {
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
}
@Override
- public ParceledListSlice<android.content.UriPermission> getGrantedUriPermissions(
- String packageName, int userId) {
+ public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+ @Nullable String packageName, int userId) {
enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
"getGrantedUriPermissions");
- final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+ final List<GrantedUriPermission> result = new ArrayList<>();
synchronized (this) {
final int size = mGrantedUriPermissions.size();
for (int i = 0; i < size; i++) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- for (UriPermission perm : perms.values()) {
- if (packageName.equals(perm.targetPkg) && perm.targetUserId == userId
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
+ if ((packageName == null || packageName.equals(perm.targetPkg))
+ && perm.targetUserId == userId
&& perm.persistedModeFlags != 0) {
- result.add(perm.buildPersistedPublicApiObject());
+ result.add(perm.buildGrantedUriPermission());
}
}
}
}
- return new ParceledListSlice<android.content.UriPermission>(result);
+ return new ParceledListSlice<>(result);
}
@Override
public void clearGrantedUriPermissions(String packageName, int userId) {
enforceCallingPermission(android.Manifest.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS,
"clearGrantedUriPermissions");
- removeUriPermissionsForPackageLocked(packageName, userId, true);
+ synchronized(this) {
+ removeUriPermissionsForPackageLocked(packageName, userId, true, true);
+ }
}
@Override
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ);
- outInfo.availMem = Process.getFreeMemory();
- outInfo.totalMem = Process.getTotalMemory();
+ outInfo.availMem = getFreeMemory();
+ outInfo.totalMem = getTotalMemory();
outInfo.threshold = homeAppMem;
outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2));
outInfo.hiddenAppThreshold = cachedAppMem;
// =========================================================
@Override
- public List<IAppTask> getAppTasks(String callingPackage) {
+ public List<IBinder> getAppTasks(String callingPackage) {
int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
-
- synchronized(this) {
- ArrayList<IAppTask> list = new ArrayList<IAppTask>();
- try {
- if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
-
- final int N = mRecentTasks.size();
- for (int i = 0; i < N; i++) {
- TaskRecord tr = mRecentTasks.get(i);
- // Skip tasks that do not match the caller. We don't need to verify
- // callingPackage, because we are also limiting to callingUid and know
- // that will limit to the correct security sandbox.
- if (tr.effectiveUid != callingUid) {
- continue;
- }
- Intent intent = tr.getBaseIntent();
- if (intent == null ||
- !callingPackage.equals(intent.getComponent().getPackageName())) {
- continue;
- }
- ActivityManager.RecentTaskInfo taskInfo =
- createRecentTaskInfoFromTaskRecord(tr);
- AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
- list.add(taskImpl);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
+ try {
+ synchronized(this) {
+ return mRecentTasks.getAppTasksList(callingUid, callingPackage);
}
- return list;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@Override
- public List<RunningTaskInfo> getTasks(int maxNum, int flags) {
+ public List<RunningTaskInfo> getTasks(int maxNum) {
+ return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED);
+ }
+
+ @Override
+ public List<RunningTaskInfo> getFilteredTasks(int maxNum, @ActivityType int ignoreActivityType,
+ @WindowingMode int ignoreWindowingMode) {
final int callingUid = Binder.getCallingUid();
- ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
+ ArrayList<RunningTaskInfo> list = new ArrayList<>();
synchronized(this) {
- if (DEBUG_ALL) Slog.v(
- TAG, "getTasks: max=" + maxNum + ", flags=" + flags);
+ if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
callingUid);
-
- // TODO: Improve with MRU list from all ActivityStacks.
- mStackSupervisor.getTasksLocked(maxNum, list, callingUid, allowed);
+ mStackSupervisor.getRunningTasks(maxNum, list, ignoreActivityType,
+ ignoreWindowingMode, callingUid, allowed);
}
return list;
}
- /**
- * Creates a new RecentTaskInfo from a TaskRecord.
- */
- private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
- // Update the task description to reflect any changes in the task stack
- tr.updateTaskDescription();
-
- // Compose the recent task info
- ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
- rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;
- rti.persistentId = tr.taskId;
- rti.baseIntent = new Intent(tr.getBaseIntent());
- rti.origActivity = tr.origActivity;
- rti.realActivity = tr.realActivity;
- rti.description = tr.lastDescription;
- rti.stackId = tr.stack != null ? tr.stack.mStackId : -1;
- rti.userId = tr.userId;
- rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
- rti.firstActiveTime = tr.firstActiveTime;
- rti.lastActiveTime = tr.lastActiveTime;
- rti.affiliatedTaskId = tr.mAffiliatedTaskId;
- rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;
- rti.numActivities = 0;
- if (tr.mBounds != null) {
- rti.bounds = new Rect(tr.mBounds);
- }
- rti.isDockable = tr.canGoInDockedStack();
- rti.resizeMode = tr.mResizeMode;
-
- ActivityRecord base = null;
- ActivityRecord top = null;
- ActivityRecord tmp;
-
- for (int i = tr.mActivities.size() - 1; i >= 0; --i) {
- tmp = tr.mActivities.get(i);
- if (tmp.finishing) {
- continue;
- }
- base = tmp;
- if (top == null || (top.state == ActivityState.INITIALIZING)) {
- top = base;
- }
- rti.numActivities++;
+ private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
+ if (mRecentTasks.isCallerRecents(callingUid)) {
+ // Always allow the recents component to get tasks
+ return true;
}
- rti.baseActivity = (base != null) ? base.intent.getComponent() : null;
- rti.topActivity = (top != null) ? top.intent.getComponent() : null;
-
- return rti;
- }
-
- private boolean isGetTasksAllowed(String caller, int callingPid, int callingUid) {
boolean allowed = checkPermission(android.Manifest.permission.REAL_GET_TASKS,
callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
if (!allowed) {
final int callingUid = Binder.getCallingUid();
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
false, ALLOW_FULL_ONLY, "getRecentTasks", null);
+ final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+ callingUid);
+ final boolean detailed = checkCallingPermission(
+ android.Manifest.permission.GET_DETAILED_TASKS)
+ == PackageManager.PERMISSION_GRANTED;
- final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
- final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;
synchronized (this) {
- final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
+ return mRecentTasks.getRecentTasks(maxNum, flags, allowed, detailed, userId,
callingUid);
- final boolean detailed = checkCallingPermission(
- android.Manifest.permission.GET_DETAILED_TASKS)
- == PackageManager.PERMISSION_GRANTED;
-
- if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
- Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
- return ParceledListSlice.emptyList();
- }
- mRecentTasks.loadUserRecentsLocked(userId);
-
- final int recentsCount = mRecentTasks.size();
- ArrayList<ActivityManager.RecentTaskInfo> res =
- new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);
-
- final Set<Integer> includedUsers;
- if (includeProfiles) {
- includedUsers = mUserController.getProfileIds(userId);
- } else {
- includedUsers = new HashSet<>();
- }
- includedUsers.add(Integer.valueOf(userId));
-
- for (int i = 0; i < recentsCount && maxNum > 0; i++) {
- TaskRecord tr = mRecentTasks.get(i);
- // Only add calling user or related users recent tasks
- if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
- continue;
- }
-
- if (tr.realActivitySuspended) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
- continue;
- }
-
- // Return the entry if desired by the caller. We always return
- // the first entry, because callers always expect this to be the
- // foreground app. We may filter others if the caller has
- // not supplied RECENT_WITH_EXCLUDED and there is some reason
- // we should exclude the entry.
-
- if (i == 0
- || withExcluded
- || (tr.intent == null)
- || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- == 0)) {
- if (!allowed) {
- // If the caller doesn't have the GET_TASKS permission, then only
- // allow them to see a small subset of tasks -- their own and home.
- if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
- continue;
- }
- }
- if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
- if (tr.stack != null && tr.stack.isHomeStack()) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, home stack task: " + tr);
- continue;
- }
- }
- if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
- final ActivityStack stack = tr.stack;
- if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, top task in docked stack: " + tr);
- continue;
- }
- }
- if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
- if (tr.stack != null && tr.stack.isPinnedStack()) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, pinned stack task: " + tr);
- continue;
- }
- }
- if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
- // Don't include auto remove tasks that are finished or finishing.
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, auto-remove without activity: " + tr);
- continue;
- }
- if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
- && !tr.isAvailable) {
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, unavail real act: " + tr);
- continue;
- }
-
- if (!tr.mUserSetupComplete) {
- // Don't include task launched while user is not done setting-up.
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
- "Skipping, user setup not complete: " + tr);
- continue;
- }
-
- ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
- if (!detailed) {
- rti.baseIntent.replaceExtras((Bundle)null);
- }
-
- res.add(rti);
- maxNum--;
- }
- }
- return new ParceledListSlice<>(res);
}
}
@Override
- public ActivityManager.TaskThumbnail getTaskThumbnail(int id) {
+ public ActivityManager.TaskDescription getTaskDescription(int id) {
synchronized (this) {
- enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
- "getTaskThumbnail()");
- final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
- id, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getTaskDescription()");
+ final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id,
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (tr != null) {
- return tr.getTaskThumbnailLocked();
+ return tr.lastTaskDescription;
}
}
return null;
intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
}
}
- if (!comp.equals(mLastAddedTaskComponent) || callingUid != mLastAddedTaskUid) {
- mLastAddedTaskActivity = null;
- }
- ActivityInfo ainfo = mLastAddedTaskActivity;
- if (ainfo == null) {
- ainfo = mLastAddedTaskActivity = AppGlobals.getPackageManager().getActivityInfo(
- comp, 0, UserHandle.getUserId(callingUid));
- if (ainfo.applicationInfo.uid != callingUid) {
- throw new SecurityException(
- "Can't add task for another application: target uid="
- + ainfo.applicationInfo.uid + ", calling uid=" + callingUid);
- }
+ final ActivityInfo ainfo = AppGlobals.getPackageManager().getActivityInfo(comp,
+ STOCK_PM_FLAGS, UserHandle.getUserId(callingUid));
+ if (ainfo.applicationInfo.uid != callingUid) {
+ throw new SecurityException(
+ "Can't add task for another application: target uid="
+ + ainfo.applicationInfo.uid + ", calling uid=" + callingUid);
}
- // Use the full screen as the context for the task thumbnail
- final Point displaySize = new Point();
- final TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
- r.task.stack.getDisplaySize(displaySize);
- thumbnailInfo.taskWidth = displaySize.x;
- thumbnailInfo.taskHeight = displaySize.y;
- thumbnailInfo.screenOrientation = mConfiguration.orientation;
-
- TaskRecord task = new TaskRecord(this,
- mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
- ainfo, intent, description, thumbnailInfo);
-
- int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
- if (trimIdx >= 0) {
- // If this would have caused a trim, then we'll abort because that
- // means it would be added at the end of the list but then just removed.
+ final ActivityStack stack = r.getStack();
+ final TaskRecord task = stack.createTaskRecord(
+ mStackSupervisor.getNextTaskIdForUserLocked(r.userId), ainfo, intent,
+ null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
+ if (!mRecentTasks.addToBottom(task)) {
+ // The app has too many tasks already and we can't add any more
+ stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING);
return INVALID_TASK_ID;
}
+ task.lastTaskDescription.copyFrom(description);
- final int N = mRecentTasks.size();
- if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) {
- final TaskRecord tr = mRecentTasks.remove(N - 1);
- tr.removedFromRecents();
- }
-
- task.inRecents = true;
- mRecentTasks.add(task);
- r.task.stack.addTask(task, false, "addAppTask");
-
- task.setLastThumbnailLocked(thumbnail);
- task.freeLastThumbnail();
+ // TODO: Send the thumbnail to WM to store it.
return task.taskId;
}
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
r.setTaskDescription(td);
- r.task.updateTaskDescription();
+ final TaskRecord task = r.getTask();
+ task.updateTaskDescription();
+ mTaskChangeNotificationController.notifyTaskDescriptionChanged(task.taskId, td);
}
}
}
public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
- taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+ taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
}
- if (task.mResizeMode != resizeableMode) {
- task.mResizeMode = resizeableMode;
- mWindowManager.setTaskResizeable(taskId, resizeableMode);
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- }
+ task.setResizeMode(resizeableMode);
}
}
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return;
}
- int stackId = task.stack.mStackId;
- // We allow the task to scroll instead of resizing if this is a non-resizeable task
- // in crop windows resize mode or if the task size is affected by the docked stack
- // changing size. No need to update configuration.
- if (bounds != null && task.inCropWindowsResizeMode()
- && mStackSupervisor.isStackDockedInEffect(stackId)) {
- mWindowManager.scrollTask(task.taskId, bounds);
- return;
- }
-
// Place the task in the right stack if it isn't there already based on
// the requested bounds.
// The stack transition logic is:
// - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
// that task to freeform
// - otherwise the task is not moved
- if (!StackId.isTaskResizeAllowed(stackId)) {
+ ActivityStack stack = task.getStack();
+ if (!task.getWindowConfiguration().canResizeTask()) {
throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
}
- if (bounds == null && stackId == FREEFORM_WORKSPACE_STACK_ID) {
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
- } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID ) {
- stackId = FREEFORM_WORKSPACE_STACK_ID;
+ if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ stack = stack.getDisplay().getOrCreateStack(
+ WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
+ } else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ stack = stack.getDisplay().getOrCreateStack(
+ WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP);
}
+
+ // Reparent the task to the right stack if necessary
boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
- if (stackId != task.stack.mStackId) {
- mStackSupervisor.moveTaskToStackUncheckedLocked(
- task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
+ if (stack != task.getStack()) {
+ // Defer resume until the task is resized below
+ task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE,
+ DEFER_RESUME, "resizeTask");
preserveWindow = false;
}
- mStackSupervisor.resizeTaskLocked(task, bounds, resizeMode, preserveWindow,
- false /* deferResume */);
+ // After reparenting (which only resizes the task to the stack bounds), resize the
+ // task to the actual bounds provided
+ task.resize(bounds, resizeMode, preserveWindow, !DEFER_RESUME);
}
} finally {
Binder.restoreCallingIdentity(ident);
Rect rect = new Rect();
try {
synchronized (this) {
- final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
- taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
return rect;
}
- if (task.stack != null) {
+ if (task.getStack() != null) {
// Return the bounds from window manager since it will be adjusted for various
// things like the presense of a docked stack for tasks that aren't resizeable.
- mWindowManager.getTaskBounds(task.taskId, rect);
+ task.getWindowContainerBounds(rect);
} else {
// Task isn't in window manager yet since it isn't associated with a stack.
// Return the persist value from activity manager
- if (task.mBounds != null) {
- rect.set(task.mBounds);
+ if (!task.matchParentBounds()) {
+ rect.set(task.getBounds());
} else if (task.mLastNonFullscreenBounds != null) {
rect.set(task.mLastNonFullscreenBounds);
}
}
@Override
- public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
- if (userId != UserHandle.getCallingUserId()) {
- enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "getTaskDescriptionIcon");
- }
- final File passedIconFile = new File(filePath);
- final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
- passedIconFile.getName());
- if (!legitIconFile.getPath().equals(filePath)
- || !filePath.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
- throw new IllegalArgumentException("Bad file path: " + filePath
- + " passed for userId " + userId);
+ public void cancelTaskWindowTransition(int taskId) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "cancelTaskWindowTransition()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
+ MATCH_TASK_IN_STACKS_ONLY);
+ if (task == null) {
+ Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
+ return;
+ }
+ task.cancelWindowTransition();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- return mRecentTasks.getTaskDescriptionIcon(filePath);
}
@Override
- public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
- throws RemoteException {
- if (opts.getAnimationType() != ActivityOptions.ANIM_CUSTOM_IN_PLACE ||
- opts.getCustomInPlaceResId() == 0) {
- throw new IllegalArgumentException("Expected in-place ActivityOption " +
- "with valid animation");
- }
- mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
- mWindowManager.overridePendingAppTransitionInPlace(opts.getPackageName(),
- opts.getCustomInPlaceResId());
- mWindowManager.executeAppTransition();
- }
-
- private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess,
- boolean removeFromRecents) {
- if (removeFromRecents) {
- mRecentTasks.remove(tr);
- tr.removedFromRecents();
- }
- ComponentName component = tr.getBaseIntent().getComponent();
- if (component == null) {
- Slog.w(TAG, "No component for base intent of task: " + tr);
- return;
+ public TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
+ enforceCallerIsRecentsOrHasPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final TaskRecord task;
+ synchronized (this) {
+ task = mStackSupervisor.anyTaskForIdLocked(taskId,
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ if (task == null) {
+ Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
+ return null;
+ }
+ }
+ // Don't call this while holding the lock as this operation might hit the disk.
+ return task.getSnapshot(reducedResolution);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
+ }
- // Find any running services associated with this app and stop if needed.
- mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
+ @Override
+ public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
+ userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, ALLOW_FULL_ONLY, "getTaskDescriptionIcon", null);
- if (!killProcess) {
- return;
+ final File passedIconFile = new File(filePath);
+ final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
+ passedIconFile.getName());
+ if (!legitIconFile.getPath().equals(filePath)
+ || !filePath.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
+ throw new IllegalArgumentException("Bad file path: " + filePath
+ + " passed for userId " + userId);
}
+ return mRecentTasks.getTaskDescriptionIcon(filePath);
+ }
- // Determine if the process(es) for this task should be killed.
- final String pkg = component.getPackageName();
- ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
- ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
- for (int i = 0; i < pmap.size(); i++) {
-
- SparseArray<ProcessRecord> uids = pmap.valueAt(i);
- for (int j = 0; j < uids.size(); j++) {
- ProcessRecord proc = uids.valueAt(j);
- if (proc.userId != tr.userId) {
- // Don't kill process for a different user.
- continue;
- }
- if (proc == mHomeProcess) {
- // Don't kill the home process along with tasks from the same package.
- continue;
- }
- if (!proc.pkgList.containsKey(pkg)) {
- // Don't kill process that is not associated with this task.
- continue;
- }
-
- for (int k = 0; k < proc.activities.size(); k++) {
- TaskRecord otherTask = proc.activities.get(k).task;
- if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
- // Don't kill process(es) that has an activity in a different task that is
- // also in recents.
- return;
- }
- }
+ @Override
+ public void startInPlaceAnimationOnFrontMostApplication(Bundle opts)
+ throws RemoteException {
+ final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(opts);
+ final ActivityOptions activityOptions = safeOptions != null
+ ? safeOptions.getOptions(mStackSupervisor)
+ : null;
+ if (activityOptions == null
+ || activityOptions.getAnimationType() != ActivityOptions.ANIM_CUSTOM_IN_PLACE
+ || activityOptions.getCustomInPlaceResId() == 0) {
+ throw new IllegalArgumentException("Expected in-place ActivityOption " +
+ "with valid animation");
+ }
+ mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
+ mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+ activityOptions.getCustomInPlaceResId());
+ mWindowManager.executeAppTransition();
+ }
- if (proc.foregroundServices) {
- // Don't kill process(es) with foreground service.
+ @Override
+ public void removeStack(int stackId) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "removeStack()");
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ Slog.w(TAG, "removeStack: No stack with id=" + stackId);
return;
}
-
- // Add process to kill list.
- procsToKill.add(proc);
- }
- }
-
- // Kill the running processes.
- for (int i = 0; i < procsToKill.size(); i++) {
- ProcessRecord pr = procsToKill.get(i);
- if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
- && pr.curReceiver == null) {
- pr.kill("remove task", true);
- } else {
- // We delay killing processes that are not in the background or running a receiver.
- pr.waitingToKill = "remove task";
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException(
+ "Removing non-standard stack is not allowed.");
+ }
+ mStackSupervisor.removeStack(stack);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
}
- private void removeTasksByPackageNameLocked(String packageName, int userId) {
- // Remove all tasks with activities in the specified package from the list of recent tasks
- for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
- TaskRecord tr = mRecentTasks.get(i);
- if (tr.userId != userId) continue;
-
- ComponentName cn = tr.intent.getComponent();
- if (cn != null && cn.getPackageName().equals(packageName)) {
- // If the package name matches, remove the task.
- removeTaskByIdLocked(tr.taskId, true, REMOVE_FROM_RECENTS);
+ /**
+ * Removes stacks in the input windowing modes from the system if they are of activity type
+ * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
+ */
+ @Override
+ public void removeStacksInWindowingModes(int[] windowingModes) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "removeStacksInWindowingModes()");
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mStackSupervisor.removeStacksInWindowingModes(windowingModes);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
}
- private void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
- int userId) {
-
- for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
- TaskRecord tr = mRecentTasks.get(i);
- if (userId != UserHandle.USER_ALL && tr.userId != userId) {
- continue;
- }
-
- ComponentName cn = tr.intent.getComponent();
- final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
- && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
- if (sameComponent) {
- removeTaskByIdLocked(tr.taskId, false, REMOVE_FROM_RECENTS);
+ @Override
+ public void removeStacksWithActivityTypes(int[] activityTypes) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "removeStacksWithActivityTypes()");
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mStackSupervisor.removeStacksWithActivityTypes(activityTypes);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
}
/**
- * Removes the task with the specified task id.
- *
- * @param taskId Identifier of the task to be removed.
- * @param killProcess Kill any process associated with the task if possible.
- * @param removeFromRecents Whether to also remove the task from recents.
- * @return Returns true if the given task was found and removed.
+ * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
+ * the whitelist
*/
- private boolean removeTaskByIdLocked(int taskId, boolean killProcess,
- boolean removeFromRecents) {
- final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
- taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
- if (tr != null) {
- tr.removeTaskActivitiesLocked();
- cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
- if (tr.isPersistable) {
- notifyTaskPersisterLocked(null, true);
- }
- return true;
- }
- Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
- return false;
+ String getPendingTempWhitelistTagForUidLocked(int uid) {
+ final PendingTempWhitelist ptw = mPendingTempWhitelist.get(uid);
+ return ptw != null ? ptw.tag : null;
+ }
+
+ @VisibleForTesting
+ boolean isActivityStartsLoggingEnabled() {
+ return mConstants.mFlagActivityStartsLoggingEnabled;
}
@Override
- public void removeStack(int stackId) {
- enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS, "removeStack()");
- if (stackId == HOME_STACK_ID) {
- throw new IllegalArgumentException("Removing home stack is not allowed.");
- }
+ public void moveStackToDisplay(int stackId, int displayId) {
+ enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
- final ActivityStack stack = mStackSupervisor.getStack(stackId);
- if (stack == null) {
- return;
- }
- final ArrayList<TaskRecord> tasks = stack.getAllTasks();
- for (int i = tasks.size() - 1; i >= 0; i--) {
- removeTaskByIdLocked(
- tasks.get(i).taskId, true /* killProcess */, REMOVE_FROM_RECENTS);
- }
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
+ + " to displayId=" + displayId);
+ mStackSupervisor.moveStackToDisplayLocked(stackId, displayId, ON_TOP);
} finally {
Binder.restoreCallingIdentity(ident);
}
@Override
public boolean removeTask(int taskId) {
- enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()");
+ enforceCallerIsRecentsOrHasPermission(REMOVE_TASKS, "removeTask()");
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
- return removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);
+ return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS,
+ "remove-task");
} finally {
Binder.restoreCallingIdentity(ident);
}
if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
synchronized(this) {
- moveTaskToFrontLocked(taskId, flags, bOptions);
+ moveTaskToFrontLocked(taskId, flags, SafeActivityOptions.fromBundle(bOptions),
+ false /* fromRecents */);
}
}
- void moveTaskToFrontLocked(int taskId, int flags, Bundle bOptions) {
- ActivityOptions options = ActivityOptions.fromBundle(bOptions);
+ void moveTaskToFrontLocked(int taskId, int flags, SafeActivityOptions options,
+ boolean fromRecents) {
if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
Binder.getCallingUid(), -1, -1, "Task to front")) {
- ActivityOptions.abort(options);
+ SafeActivityOptions.abort(options);
return;
}
final long origId = Binder.clearCallingIdentity();
Slog.d(TAG, "Could not find task for id: "+ taskId);
return;
}
- if (mStackSupervisor.isLockTaskModeViolation(task)) {
- mStackSupervisor.showLockTaskToast();
+ if (mLockTaskController.isLockTaskModeViolation(task)) {
Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode");
return;
}
- final ActivityRecord prev = mStackSupervisor.topRunningActivityLocked();
- if (prev != null && prev.isRecentsActivity()) {
- task.setTaskToReturnTo(ActivityRecord.RECENTS_ACTIVITY_TYPE);
- }
- mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront",
+ ActivityOptions realOptions = options != null
+ ? options.getOptions(mStackSupervisor)
+ : null;
+ mStackSupervisor.findTaskToMoveToFront(task, flags, realOptions, "moveTaskToFront",
false /* forceNonResizable */);
+
+ final ActivityRecord topActivity = task.getTopActivity();
+ if (topActivity != null) {
+
+ // We are reshowing a task, use a starting window to hide the initial draw delay
+ // so the transition can start earlier.
+ topActivity.showStartingWindow(null /* prev */, false /* newTask */,
+ true /* taskSwitch */, fromRecents);
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
- ActivityOptions.abort(options);
+ SafeActivityOptions.abort(options);
}
/**
- * Moves an activity, and all of the other activities within the same task, to the bottom
- * of the history stack. The activity's order within the task is unchanged.
+ * Attempts to move a task backwards in z-order (the order of activities within the task is
+ * unchanged).
+ *
+ * There are several possible results of this call:
+ * - if the task is locked, then we will show the lock toast
+ * - if there is a task behind the provided task, then that task is made visible and resumed as
+ * this task is moved to the back
+ * - otherwise, if there are no other tasks in the stack:
+ * - if this task is in the pinned stack, then we remove the stack completely, which will
+ * have the effect of moving the task to the top or bottom of the fullscreen stack
+ * (depending on whether it is visible)
+ * - otherwise, we simply return home and hide this task
*
* @param token A reference to the activity we wish to move
* @param nonRoot If false then this only works if the activity is the root
int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
if (task != null) {
- if (mStackSupervisor.isLockedTask(task)) {
- mStackSupervisor.showLockTaskToast();
- return false;
- }
return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId);
}
} finally {
}
@Override
- public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
- IActivityContainerCallback callback) throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createActivityContainer()");
- synchronized (this) {
- if (parentActivityToken == null) {
- throw new IllegalArgumentException("parent token must not be null");
- }
- ActivityRecord r = ActivityRecord.forTokenLocked(parentActivityToken);
- if (r == null) {
- return null;
- }
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null");
- }
- return mStackSupervisor.createVirtualActivityContainer(r, callback);
- }
- }
-
- @Override
- public void deleteActivityContainer(IActivityContainer container) throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "deleteActivityContainer()");
- synchronized (this) {
- mStackSupervisor.deleteActivityContainer(container);
- }
- }
-
- @Override
- public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
+ public int createStackOnDisplay(int displayId) throws RemoteException {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
synchronized (this) {
- final int stackId = mStackSupervisor.getNextStackId();
- final ActivityStack stack =
- mStackSupervisor.createStackOnDisplay(stackId, displayId, true /*onTop*/);
- if (stack == null) {
- return null;
+ final ActivityDisplay display =
+ mStackSupervisor.getActivityDisplayOrCreateLocked(displayId);
+ if (display == null) {
+ return INVALID_STACK_ID;
}
- return stack.mActivityContainer;
+ // TODO(multi-display): Have the caller pass in the windowing mode and activity type.
+ final ActivityStack stack = display.createStack(
+ WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
+ ON_TOP);
+ return (stack != null) ? stack.mStackId : INVALID_STACK_ID;
}
}
@Override
public int getActivityDisplayId(IBinder activityToken) throws RemoteException {
synchronized (this) {
- ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
- if (stack != null && stack.mActivityContainer.isAttachedLocked()) {
- return stack.mActivityContainer.getDisplayId();
- }
- return Display.DEFAULT_DISPLAY;
- }
- }
-
- @Override
- public int getActivityStackId(IBinder token) throws RemoteException {
- synchronized (this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack == null) {
- return INVALID_STACK_ID;
+ final ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
+ if (stack != null && stack.mDisplayId != INVALID_DISPLAY) {
+ return stack.mDisplayId;
}
- return stack.mStackId;
+ return DEFAULT_DISPLAY;
}
}
throw new IllegalArgumentException(
"exitFreeformMode: No activity record matching token=" + token);
}
- final ActivityStack stack = r.getStackLocked(token);
- if (stack == null || stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+
+ final ActivityStack stack = r.getStack();
+ if (stack == null || !stack.inFreeformWindowingMode()) {
throw new IllegalStateException(
"exitFreeformMode: You can only go fullscreen from freeform.");
}
- if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
- mStackSupervisor.moveTaskToStackLocked(r.task.taskId, FULLSCREEN_WORKSPACE_STACK_ID,
- ON_TOP, !FORCE_FOCUS, "exitFreeformMode", ANIMATE);
+
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
- public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
- if (stackId == HOME_STACK_ID) {
- throw new IllegalArgumentException(
- "moveTaskToStack: Attempt to move task " + taskId + " to home stack");
+ public void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ setTaskWindowingModeSplitScreenPrimary(taskId, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
+ toTop, ANIMATE, null /* initialBounds */, true /* showRecents */);
+ return;
}
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
synchronized (this) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
- + " to stackId=" + stackId + " toTop=" + toTop);
- if (stackId == DOCKED_STACK_ID) {
- mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
- null /* initialBounds */);
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId);
+ return;
+ }
+
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
+ + " to windowingMode=" + windowingMode + " toTop=" + toTop);
+
+ if (!task.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
+ + " non-standard task " + taskId + " to windowing mode="
+ + windowingMode);
}
- boolean result = mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop,
- !FORCE_FOCUS, "moveTaskToStack", ANIMATE);
- if (result && stackId == DOCKED_STACK_ID) {
- // If task moved to docked stack - show recents if needed.
- mStackSupervisor.moveHomeStackTaskToTop(RECENTS_ACTIVITY_TYPE,
- "moveTaskToDockedStack");
+
+ final ActivityStack stack = task.getStack();
+ if (toTop) {
+ stack.moveToFront("setTaskWindowingMode", task);
}
+ stack.setWindowingMode(windowingMode);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
+ /**
+ * Moves the specified task to the primary-split-screen stack.
+ *
+ * @param taskId Id of task to move.
+ * @param createMode The mode the primary split screen stack should be created in if it doesn't
+ * exist already. See
+ * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
+ * and
+ * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
+ * @param toTop If the task and stack should be moved to the top.
+ * @param animate Whether we should play an animation for the moving the task.
+ * @param initialBounds If the primary stack gets created, it will use these bounds for the
+ * stack. Pass {@code null} to use default bounds.
+ * @param showRecents If the recents activity should be shown on the other side of the task
+ * going into split-screen mode.
+ */
@Override
- public void swapDockedAndFullscreenStack() throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "swapDockedAndFullscreenStack()");
+ public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+ boolean animate, Rect initialBounds, boolean showRecents) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "setTaskWindowingModeSplitScreenPrimary()");
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- final ActivityStack fullscreenStack = mStackSupervisor.getStack(
- FULLSCREEN_WORKSPACE_STACK_ID);
- final TaskRecord topTask = fullscreenStack != null ? fullscreenStack.topTask()
- : null;
- final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
- final ArrayList<TaskRecord> tasks = dockedStack != null ? dockedStack.getAllTasks()
- : null;
- if (topTask == null || tasks == null || tasks.size() == 0) {
- Slog.w(TAG,
- "Unable to swap tasks, either docked or fullscreen stack is empty.");
- return;
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
+ return false;
+ }
+ if (DEBUG_STACK) Slog.d(TAG_STACK,
+ "setTaskWindowingModeSplitScreenPrimary: moving task=" + taskId
+ + " to createMode=" + createMode + " toTop=" + toTop);
+ if (!task.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
+ + " non-standard task " + taskId + " to split-screen windowing mode");
}
- // TODO: App transition
- mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_RELAUNCH, false);
+ mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+ final int windowingMode = task.getWindowingMode();
+ final ActivityStack stack = task.getStack();
+ if (toTop) {
+ stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
+ }
+ stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
+ false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */);
+ return windowingMode != task.getWindowingMode();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
- // Defer the resume so resume/pausing while moving stacks is dangerous.
- mStackSupervisor.moveTaskToStackLocked(topTask.taskId, DOCKED_STACK_ID,
- false /* toTop */, !FORCE_FOCUS, "swapDockedAndFullscreenStack",
- ANIMATE, true /* deferResume */);
- final int size = tasks.size();
- for (int i = 0; i < size; i++) {
- final int id = tasks.get(i).taskId;
- if (id == topTask.taskId) {
- continue;
- }
- mStackSupervisor.moveTaskToStackLocked(id,
- FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */, !FORCE_FOCUS,
- "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */);
+ @Override
+ public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
+ return;
}
- // Because we deferred the resume, to avoid conflicts with stack switches while
- // resuming, we need to do it after all the tasks are moved.
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
+ + " to stackId=" + stackId + " toTop=" + toTop);
- mWindowManager.executeAppTransition();
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ throw new IllegalStateException(
+ "moveTaskToStack: No stack for stackId=" + stackId);
+ }
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
+ + taskId + " to stack " + stackId);
+ }
+ if (stack.inSplitScreenPrimaryWindowingMode()) {
+ mWindowManager.setDockedStackCreateState(
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
+ }
+ task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
+ "moveTaskToStack");
} finally {
Binder.restoreCallingIdentity(ident);
}
}
/**
- * Moves the input task to the docked stack.
- *
- * @param taskId Id of task to move.
- * @param createMode The mode the docked stack should be created in if it doesn't exist
- * already. See
- * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT}
- * and
- * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT}
- * @param toTop If the task and stack should be moved to the top.
- * @param animate Whether we should play an animation for the moving the task
- * @param initialBounds If the docked stack gets created, it will use these bounds for the
- * docked stack. Pass {@code null} to use default bounds.
+ * Dismisses split-screen multi-window mode.
+ * @param toTop If true the current primary split-screen stack will be placed or left on top.
*/
@Override
- public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
- Rect initialBounds, boolean moveHomeStackFront) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
- synchronized (this) {
- long ident = Binder.clearCallingIdentity();
- try {
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
- + " to createMode=" + createMode + " toTop=" + toTop);
- mWindowManager.setDockedStackCreateState(createMode, initialBounds);
- final boolean moved = mStackSupervisor.moveTaskToStackLocked(
- taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack",
- animate, DEFER_RESUME);
- if (moved) {
- if (moveHomeStackFront) {
- mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack");
+ public void dismissSplitScreenMode(boolean toTop) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "dismissSplitScreenMode()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityStack stack =
+ mStackSupervisor.getDefaultDisplay().getSplitScreenPrimaryStack();
+ if (stack == null) {
+ Slog.w(TAG, "dismissSplitScreenMode: primary split-screen stack not found.");
+ return;
+ }
+
+ if (toTop) {
+ // Caller wants the current split-screen primary stack to be the top stack after
+ // it goes fullscreen, so move it to the front.
+ stack.moveToFront("dismissSplitScreenMode");
+ } else if (mStackSupervisor.isFocusedStack(stack)) {
+ // In this case the current split-screen primary stack shouldn't be the top
+ // stack after it goes fullscreen, but it current has focus, so we move the
+ // focus to the top-most split-screen secondary stack next to it.
+ final ActivityStack otherStack = stack.getDisplay().getTopStackInWindowingMode(
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ if (otherStack != null) {
+ otherStack.moveToFront("dismissSplitScreenMode_other");
}
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
- return moved;
- } finally {
- Binder.restoreCallingIdentity(ident);
+
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Dismisses Pip
+ * @param animate True if the dismissal should be animated.
+ * @param animationDuration The duration of the resize animation in milliseconds or -1 if the
+ * default animation duration should be used.
+ */
+ @Override
+ public void dismissPip(boolean animate, int animationDuration) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "dismissPip()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final PinnedActivityStack stack =
+ mStackSupervisor.getDefaultDisplay().getPinnedStack();
+ if (stack == null) {
+ Slog.w(TAG, "dismissPip: pinned stack not found.");
+ return;
+ }
+ if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ throw new IllegalArgumentException("Stack: " + stack
+ + " doesn't support animated resize.");
+ }
+ if (animate) {
+ stack.animateResizePinnedStack(null /* sourceHintBounds */,
+ null /* destBounds */, animationDuration, false /* fromFullscreen */);
+ } else {
+ mStackSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
*/
@Override
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTopActivityToPinnedStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "moveTopActivityToPinnedStack()");
synchronized (this) {
if (!mSupportsPictureInPicture) {
throw new IllegalStateException("moveTopActivityToPinnedStack:"
- + "Device doesn't support picture-in-pciture mode");
+ + "Device doesn't support picture-in-picture mode");
}
long ident = Binder.clearCallingIdentity();
}
@Override
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+ public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode,
boolean preserveWindows, boolean animate, int animationDuration) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
if (animate) {
- if (stackId == PINNED_STACK_ID) {
- mWindowManager.animateResizePinnedStack(bounds, animationDuration);
- } else {
+ final PinnedActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
+ return;
+ }
+ if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) {
throw new IllegalArgumentException("Stack: " + stackId
+ " doesn't support animated resize.");
}
+ stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
+ animationDuration, false /* fromFullscreen */);
} else {
- mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
+ return;
+ }
+ mStackSupervisor.resizeStackLocked(stack, destBounds, null /* tempTaskBounds */,
null /* tempTaskInsetBounds */, preserveWindows,
allowResizeInDockedMode, !DEFER_RESUME);
}
public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
Rect tempDockedTaskInsetBounds,
Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "resizeDockedStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeDockedStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
}
@Override
+ public void setSplitScreenResizing(boolean resizing) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setSplitScreenResizing()");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ mStackSupervisor.setSplitScreenResizing(resizing);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "resizePinnedStack()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePinnedStack()");
final long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
}
}
+ /**
+ * Try to place task to provided position. The final position might be different depending on
+ * current user and stacks state. The task will be moved to target stack if it's currently in
+ * different stack.
+ */
@Override
public void positionTaskInStack(int taskId, int stackId, int position) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
- if (stackId == HOME_STACK_ID) {
- throw new IllegalArgumentException(
- "positionTaskInStack: Attempt to change the position of task "
- + taskId + " in/to home stack");
- }
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- if (DEBUG_STACK) Slog.d(TAG_STACK,
- "positionTaskInStack: positioning task=" + taskId
- + " in stackId=" + stackId + " at position=" + position);
- mStackSupervisor.positionTaskInStackLocked(taskId, stackId, position);
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task="
+ + taskId + " in stackId=" + stackId + " at position=" + position);
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("positionTaskInStack: no task for id="
+ + taskId);
+ }
+
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+
+ if (stack == null) {
+ throw new IllegalArgumentException("positionTaskInStack: no stack for id="
+ + stackId);
+ }
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("positionTaskInStack: Attempt to change"
+ + " the position of task " + taskId + " in/to non-standard stack");
+ }
+
+ // TODO: Have the callers of this API call a separate reparent method if that is
+ // what they intended to do vs. having this method also do reparenting.
+ if (task.getStack() == stack) {
+ // Change position in current stack.
+ stack.positionChildAt(task, position);
+ } else {
+ // Reparent to new stack.
+ task.reparent(stack, position, REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE,
+ !DEFER_RESUME, "positionTaskInStack");
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@Override
public List<StackInfo> getAllStackInfos() {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
}
@Override
- public StackInfo getStackInfo(int stackId) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+ public StackInfo getStackInfo(int windowingMode, int activityType) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- return mStackSupervisor.getStackInfoLocked(stackId);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public boolean isInHomeStack(int taskId) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
- taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
- return tr != null && tr.stack != null && tr.stack.isHomeStack();
+ return mStackSupervisor.getStackInfo(windowingMode, activityType);
}
} finally {
Binder.restoreCallingIdentity(ident);
@Override
public void updateDeviceOwner(String packageName) {
final int callingUid = Binder.getCallingUid();
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ if (callingUid != 0 && callingUid != SYSTEM_UID) {
throw new SecurityException("updateDeviceOwner called from non-system process");
}
synchronized (this) {
@Override
public void updateLockTaskPackages(int userId, String[] packages) {
final int callingUid = Binder.getCallingUid();
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ if (callingUid != 0 && callingUid != SYSTEM_UID) {
enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
"updateLockTaskPackages()");
}
synchronized (this) {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
Arrays.toString(packages));
- mLockTaskPackages.put(userId, packages);
- mStackSupervisor.onLockTaskPackagesUpdatedLocked();
+ mLockTaskController.updateLockTaskPackages(userId, packages);
}
}
+ @Override
+ public void updateLockTaskFeatures(int userId, int flags) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != SYSTEM_UID) {
+ enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
+ "updateLockTaskFeatures()");
+ }
+ synchronized (this) {
+ if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowing features " + userId + ":0x" +
+ Integer.toHexString(flags));
+ mLockTaskController.updateLockTaskFeatures(userId, flags);
+ }
+ }
- void startLockTaskModeLocked(TaskRecord task) {
+ private void startLockTaskModeLocked(@Nullable TaskRecord task, boolean isSystemCaller) {
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
- if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
+ if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
return;
}
- // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
- // is initiated by system after the pinning request was shown and locked mode is initiated
- // by an authorized app directly
+ final ActivityStack stack = mStackSupervisor.getFocusedStack();
+ if (stack == null || task != stack.topTask()) {
+ throw new IllegalArgumentException("Invalid task, not in foreground");
+ }
+
+ // {@code isSystemCaller} is used to distinguish whether this request is initiated by the
+ // system or a specific app.
+ // * System-initiated requests will only start the pinned mode (screen pinning)
+ // * App-initiated requests
+ // - will put the device in fully locked mode (LockTask), if the app is whitelisted
+ // - will start the pinned mode, otherwise
final int callingUid = Binder.getCallingUid();
- boolean isSystemInitiated = callingUid == Process.SYSTEM_UID;
long ident = Binder.clearCallingIdentity();
try {
- if (!isSystemInitiated) {
- task.mLockTaskUid = callingUid;
- if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
- // startLockTask() called by app and task mode is lockTaskModeDefault.
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
- StatusBarManagerInternal statusBarManager =
- LocalServices.getService(StatusBarManagerInternal.class);
- if (statusBarManager != null) {
- statusBarManager.showScreenPinningRequest(task.taskId);
- }
- return;
- }
+ // When a task is locked, dismiss the pinned stack if it exists
+ mStackSupervisor.removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
- final ActivityStack stack = mStackSupervisor.getFocusedStack();
- if (stack == null || task != stack.topTask()) {
- throw new IllegalArgumentException("Invalid task, not in foreground");
- }
- }
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, isSystemInitiated ? "Locking pinned" :
- "Locking fully");
- mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
- ActivityManager.LOCK_TASK_MODE_PINNED :
- ActivityManager.LOCK_TASK_MODE_LOCKED,
- "startLockTask", true);
+ mLockTaskController.startLockTaskMode(task, isSystemCaller, callingUid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
- public void startLockTaskMode(int taskId) {
- synchronized (this) {
- final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
- if (task != null) {
- startLockTaskModeLocked(task);
- }
- }
- }
-
- @Override
- public void startLockTaskMode(IBinder token) {
+ public void startLockTaskModeByToken(IBinder token) {
synchronized (this) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
return;
}
- final TaskRecord task = r.task;
- if (task != null) {
- startLockTaskModeLocked(task);
- }
+ startLockTaskModeLocked(r.getTask(), false /* isSystemCaller */);
}
}
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- startLockTaskMode(taskId);
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+
+ // When starting lock task mode the stack must be in front and focused
+ task.getStack().moveToFront("startSystemLockTaskMode");
+ startLockTaskModeLocked(task, true /* isSystemCaller */);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
@Override
- public void stopLockTaskMode() {
- final TaskRecord lockTask = mStackSupervisor.getLockedTaskLocked();
- if (lockTask == null) {
- // Our work here is done.
- return;
+ public void stopLockTaskModeByToken(IBinder token) {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r == null) {
+ return;
+ }
+ stopLockTaskModeInternal(r.getTask(), false /* isSystemCaller */);
}
+ }
+
+ /**
+ * This API should be called by SystemUI only when user perform certain action to dismiss
+ * lock task mode. We should only dismiss pinned lock task mode in this case.
+ */
+ @Override
+ public void stopSystemLockTaskMode() throws RemoteException {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode");
+ stopLockTaskModeInternal(null, true /* isSystemCaller */);
+ }
+ private void stopLockTaskModeInternal(@Nullable TaskRecord task, boolean isSystemCaller) {
final int callingUid = Binder.getCallingUid();
- final int lockTaskUid = lockTask.mLockTaskUid;
- final int lockTaskModeState = mStackSupervisor.getLockTaskModeState();
- if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_NONE) {
- // Done.
- return;
- } else {
- // Ensure the same caller for startLockTaskMode and stopLockTaskMode.
- // It is possible lockTaskMode was started by the system process because
- // android:lockTaskMode is set to a locking value in the application manifest
- // instead of the app calling startLockTaskMode. In this case
- // {@link TaskRecord.mLockTaskUid} will be 0, so we compare the callingUid to the
- // {@link TaskRecord.effectiveUid} instead. Also caller with
- // {@link MANAGE_ACTIVITY_STACKS} can stop any lock task.
- if (checkCallingPermission(MANAGE_ACTIVITY_STACKS) != PERMISSION_GRANTED
- && callingUid != lockTaskUid
- && (lockTaskUid != 0 || callingUid != lockTask.effectiveUid)) {
- throw new SecurityException("Invalid uid, expected " + lockTaskUid
- + " callingUid=" + callingUid + " effectiveUid=" + lockTask.effectiveUid);
- }
- }
long ident = Binder.clearCallingIdentity();
try {
- Log.d(TAG, "stopLockTaskMode");
- // Stop lock task
synchronized (this) {
- mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
- "stopLockTask", true);
+ mLockTaskController.stopLockTaskMode(task, isSystemCaller, callingUid);
}
+ // Launch in-call UI if a call is ongoing. This is necessary to allow stopping the lock
+ // task and jumping straight into a call in the case of emergency call back.
TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
if (tm != null) {
tm.showInCallScreen(false);
}
}
- /**
- * This API should be called by SystemUI only when user perform certain action to dismiss
- * lock task mode. We should only dismiss pinned lock task mode in this case.
- */
- @Override
- public void stopSystemLockTaskMode() throws RemoteException {
- if (mStackSupervisor.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_PINNED) {
- stopLockTaskMode();
- } else {
- mStackSupervisor.showLockTaskToast();
- }
- }
-
@Override
public boolean isInLockTaskMode() {
- return getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE;
+ return getLockTaskModeState() != LOCK_TASK_MODE_NONE;
}
@Override
public int getLockTaskModeState() {
synchronized (this) {
- return mStackSupervisor.getLockTaskModeState();
+ return mLockTaskController.getLockTaskModeState();
}
}
if (r == null) {
return;
}
- mStackSupervisor.showLockTaskEscapeMessageLocked(r.task);
+ mLockTaskController.showLockTaskToast();
+ }
+ }
+
+ @Override
+ public void setDisablePreviewScreenshots(IBinder token, boolean disable)
+ throws RemoteException {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ Slog.w(TAG, "setDisablePreviewScreenshots: Unable to find activity for token="
+ + token);
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ r.setDisablePreviewScreenshots(disable);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
}
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
- | MATCH_DEBUG_TRIAGED_MISSING)
+ | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
.getList();
} catch (RemoteException ex) {
}
try {
cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
+ | PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
} catch (RemoteException ignored) {
}
if (cpi == null) {
- // TODO: make this an outright failure in a future platform release;
- // until then anonymous content notifications are unprotected
- //return "Failed to find provider " + authority + " for user " + userId;
- return null;
+ return "Failed to find provider " + authority + " for user " + userId
+ + "; expected to find a valid ContentProvider for this authority";
}
ProcessRecord r = null;
boolean checkedGrants = false;
if (checkUser) {
// Looking for cross-user grants before enforcing the typical cross-users permissions
- int tmpTargetUserId = mUserController.unsafeConvertIncomingUserLocked(userId);
+ int tmpTargetUserId = mUserController.unsafeConvertIncomingUser(userId);
if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
if (checkAuthorityGrants(callingUid, cpi, tmpTargetUserId, checkUser)) {
return null;
return null;
}
- String msg;
+ final String suffix;
if (!cpi.exported) {
- msg = "Permission Denial: opening provider " + cpi.name
- + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
- + ", uid=" + callingUid + ") that is not exported from uid "
- + cpi.applicationInfo.uid;
+ suffix = " that is not exported from UID " + cpi.applicationInfo.uid;
+ } else if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(cpi.readPermission)) {
+ suffix = " requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs";
} else {
- msg = "Permission Denial: opening provider " + cpi.name
- + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
- + ", uid=" + callingUid + ") requires "
- + cpi.readPermission + " or " + cpi.writePermission;
+ suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
}
+ final String msg = "Permission Denial: opening provider " + cpi.name
+ + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")" + suffix;
Slog.w(TAG, msg);
return msg;
}
private final long[] mProcessStateStatsLongs = new long[1];
- boolean isProcessAliveLocked(ProcessRecord proc) {
+ private boolean isProcessAliveLocked(ProcessRecord proc) {
+ if (proc.pid <= 0) {
+ if (DEBUG_OOM_ADJ) Slog.d(TAG, "Process hasn't started yet: " + proc);
+ return false;
+ }
if (proc.procStatFile == null) {
proc.procStatFile = "/proc/" + proc.pid + "/stat";
}
mProcessStateStatsLongs[0] = 0;
- if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
+ if (!readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
mProcessStateStatsLongs, null)) {
if (DEBUG_OOM_ADJ) Slog.d(TAG, "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile);
return false;
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
+ boolean providerRunning = false;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
}
}
- boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
+ if (cpr != null && cpr.proc != null) {
+ providerRunning = !cpr.proc.killed;
+
+ // Note if killedByAm is also set, this means the provider process has just been
+ // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
+ // yet. So we need to call appDiedLocked() here and let it clean up.
+ // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
+ // how to test this case.)
+ if (cpr.proc.killed && cpr.proc.killedByAm) {
+ checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)");
+ final long iden = Binder.clearCallingIdentity();
+ try {
+ appDiedLocked(cpr.proc);
+ } finally {
+ Binder.restoreCallingIdentity(iden);
+ }
+ checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)");
+ }
+ }
+
if (providerRunning) {
cpi = cpr.info;
String msg;
holder.provider = null;
return holder;
}
+ // Don't expose providers between normal apps and instant apps
+ try {
+ if (AppGlobals.getPackageManager()
+ .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ }
final long origId = Binder.clearCallingIdentity();
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.verifiedAdj;
- boolean success = updateOomAdjLocked(cpr.proc);
+ boolean success = updateOomAdjLocked(cpr.proc, true);
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
"Attempt to launch content provider before system ready");
}
+ // If system providers are not installed yet we aggressively crash to avoid
+ // creating multiple instance of these providers and then bad things happen!
+ if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
+ && "system".equals(cpi.processName)) {
+ throw new IllegalStateException("Cannot access system provider: '"
+ + cpi.authority + "' before system providers are installed!");
+ }
+
// Make sure that the user who owns this provider is running. If not,
// we don't want to allow it to run.
- if (!mUserController.isUserRunningLocked(userId, 0)) {
+ if (!mUserController.isUserRunning(userId, 0)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
// If permissions need a review before any of the app components can run,
// we return no provider and launch a review activity if the calling app
// is in the foreground.
- if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {
+ if (mPermissionReviewRequired) {
if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
return null;
}
}
}
checkTime(startTime, "getContentProviderImpl: done!");
+
+ grantEphemeralAccessLocked(userId, null /*intent*/,
+ cpi.applicationInfo.uid, UserHandle.getAppId(Binder.getCallingUid()));
}
// Wait for the provider to be published...
+ final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
return null;
}
try {
+ final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
- + " launchingApp=" + cpr.launchingApp);
+ + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
if (conn != null) {
conn.waiting = true;
}
- cpr.wait();
+ cpr.wait(wait);
+ if (cpr.provider == null) {
+ Slog.wtf(TAG, "Timeout waiting for provider "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider "
+ + name
+ + " providerRunning=" + providerRunning);
+ return null;
+ }
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
}
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, cpi.packageName);
return true;
}
+ /**
+ * Returns the PackageManager. Used by classes hosted by {@link ActivityManagerService}. The
+ * PackageManager could be unavailable at construction time and therefore needs to be accessed
+ * on demand.
+ */
+ IPackageManager getPackageManager() {
+ return AppGlobals.getPackageManager();
+ }
+
+ ActivityStartController getActivityStartController() {
+ return mActivityStartController;
+ }
+
+ LockTaskController getLockTaskController() {
+ return mLockTaskController;
+ }
+
+ ClientLifecycleManager getLifecycleManager() {
+ return mLifecycleManager;
+ }
+
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
dst.proc = r;
dst.notifyAll();
}
- updateOomAdjLocked(r);
+ updateOomAdjLocked(r, true);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
// As far as we're concerned, this is just like receiving a
// death notification... just a bit prematurely.
- Slog.i(TAG, "Process " + proc.processName + " (pid " + proc.pid
- + ") early provider death");
+ reportUidInfoMessageLocked(TAG,
+ "Process " + proc.processName + " (pid " + proc.pid
+ + ") early provider death",
+ proc.info.uid);
final long ident = Binder.clearCallingIdentity();
try {
appDiedLocked(proc);
@Override
public void appNotRespondingViaProvider(IBinder connection) {
- enforceCallingPermission(
- android.Manifest.permission.REMOVE_TASKS, "appNotRespondingViaProvider()");
+ enforceCallingPermission(REMOVE_TASKS, "appNotRespondingViaProvider()");
final ContentProviderConnection conn = (ContentProviderConnection) connection;
if (conn == null) {
public final void installSystemProviders() {
List<ProviderInfo> providers;
synchronized (this) {
- ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
+ ProcessRecord app = mProcessNames.get("system", SYSTEM_UID);
providers = generateApplicationProvidersLocked(app);
if (providers != null) {
for (int i=providers.size()-1; i>=0; i--) {
mSystemThread.installSystemProviders(providers);
}
+ synchronized (this) {
+ mSystemProvidersInstalled = true;
+ }
+
+ mConstants.start(mContext.getContentResolver());
mCoreSettingsObserver = new CoreSettingsObserver(this);
mFontScaleSettingObserver = new FontScaleSettingObserver();
+ mDevelopmentSettingsObserver = new DevelopmentSettingsObserver();
+ GlobalSettingsToPropertiesMapper.start(mContext.getContentResolver());
+
+ // Now that the settings provider is published we can consider sending
+ // in a rescue party.
+ RescueParty.onSettingsProviderPublished(mContext);
//mUsageStatsService.monitorPackages();
}
- private void startPersistentApps(int matchFlags) {
+ void startPersistentApps(int matchFlags) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
synchronized (this) {
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName)) {
- addAppLocked(app, false, null /* ABI override */);
+ addAppLocked(app, null, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
* When a user is unlocked, we need to install encryption-unaware providers
* belonging to any running apps.
*/
- private void installEncryptionUnawareProviders(int userId) {
+ void installEncryptionUnawareProviders(int userId) {
// We're only interested in providers that are encryption unaware, and
// we don't care about uninstalled apps, since there's no way they're
// running at this point.
int callingPid = Binder.getCallingPid();
long ident = 0;
boolean clearedIdentity = false;
- synchronized (this) {
- userId = mUserController.unsafeConvertIncomingUserLocked(userId);
- }
+ userId = mUserController.unsafeConvertIncomingUser(userId);
if (canClearIdentity(callingPid, callingUid, userId)) {
clearedIdentity = true;
ident = Binder.clearCallingIdentity();
// GLOBAL MANAGEMENT
// =========================================================
+ @GuardedBy("this")
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
boolean isolated, int isolatedUid) {
String proc = customProcess != null ? customProcess : info.processName;
int uid = info.uid;
if (isolated) {
if (isolatedUid == 0) {
- int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
+ int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
while (true) {
- if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
- || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
- mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+ if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
+ || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
+ mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
}
uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
mNextIsolatedProcessUid++;
// the uid of the isolated process is specified by the caller.
uid = isolatedUid;
}
+ getPackageManagerInternalLocked().addIsolatedUid(uid, info.uid);
// Register the isolated UID with this application so BatteryStats knows to
// attribute resource usage to the application.
// owning application.
mBatteryStatsService.addIsolatedUid(uid, info.uid);
}
- final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
+ final ProcessRecord r = new ProcessRecord(this, stats, info, proc, uid);
if (!mBooted && !mBooting
&& userId == UserHandle.USER_SYSTEM
&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
+ // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
+ r.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
r.persistent = true;
+ r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
+ }
+ if (isolated && isolatedUid != 0) {
+ // Special case for startIsolatedProcess (internal only) - assume the process
+ // is required by the system server to prevent it being killed.
+ r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
}
addProcessNameLocked(r);
return r;
}
- final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
+ private boolean uidOnBackgroundWhitelist(final int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ final int[] whitelist = mBackgroundAppIdWhitelist;
+ final int N = whitelist.length;
+ for (int i = 0; i < N; i++) {
+ if (appId == whitelist[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isBackgroundRestricted(String packageName) {
+ final int callingUid = Binder.getCallingUid();
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ final int packageUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
+ UserHandle.getUserId(callingUid));
+ if (packageUid != callingUid) {
+ throw new IllegalArgumentException("Uid " + callingUid
+ + " cannot query restriction state for package " + packageName);
+ }
+ } catch (RemoteException exc) {
+ // Ignore.
+ }
+ return isBackgroundRestrictedNoCheck(callingUid, packageName);
+ }
+
+ boolean isBackgroundRestrictedNoCheck(final int uid, final String packageName) {
+ final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+ uid, packageName);
+ return mode != AppOpsManager.MODE_ALLOWED;
+ }
+
+ @Override
+ public void backgroundWhitelistUid(final int uid) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the OS may call backgroundWhitelistUid()");
+ }
+
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Adding uid " + uid + " to bg uid whitelist");
+ }
+ synchronized (this) {
+ final int N = mBackgroundAppIdWhitelist.length;
+ int[] newList = new int[N+1];
+ System.arraycopy(mBackgroundAppIdWhitelist, 0, newList, 0, N);
+ newList[N] = UserHandle.getAppId(uid);
+ mBackgroundAppIdWhitelist = newList;
+ }
+ }
+
+ @GuardedBy("this")
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
String abiOverride) {
+ return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */,
+ abiOverride);
+ }
+
+ final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
+ boolean disableHiddenApiChecks, String abiOverride) {
ProcessRecord app;
if (!isolated) {
- app = getProcessRecordLocked(info.processName, info.uid, true);
+ app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
+ info.uid, true);
} else {
app = null;
}
if (app == null) {
- app = newProcessRecordLocked(info, null, isolated, 0);
+ app = newProcessRecordLocked(info, customProcess, isolated, 0);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
- startProcessLocked(app, "added application", app.processName, abiOverride,
- null /* entryPoint */, null /* entryPointArgs */);
+ startProcessLocked(app, "added application",
+ customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
+ abiOverride);
}
return app;
}
}
- public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
+ public ParcelFileDescriptor openContentUri(String uriString) throws RemoteException {
enforceNotIsolatedCaller("openContentUri");
final int userId = UserHandle.getCallingUserId();
+ final Uri uri = Uri.parse(uriString);
String name = uri.getAuthority();
ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null, userId);
ParcelFileDescriptor pfd = null;
return mSleeping;
}
+ void reportGlobalUsageEventLocked(int event) {
+ mUsageStatsService.reportEvent("android", mUserController.getCurrentUserId(), event);
+ int[] profiles = mUserController.getCurrentProfileIds();
+ if (profiles != null) {
+ for (int i = profiles.length - 1; i >= 0; i--) {
+ mUsageStatsService.reportEvent((String)null, profiles[i], event);
+ }
+ }
+ }
+
+ void reportCurWakefulnessUsageEventLocked() {
+ reportGlobalUsageEventLocked(mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE
+ ? UsageEvents.Event.SCREEN_INTERACTIVE
+ : UsageEvents.Event.SCREEN_NON_INTERACTIVE);
+ }
+
+ void reportCurKeyguardUsageEventLocked() {
+ reportGlobalUsageEventLocked(mKeyguardShown
+ ? UsageEvents.Event.KEYGUARD_SHOWN
+ : UsageEvents.Event.KEYGUARD_HIDDEN);
+ }
+
void onWakefulnessChanged(int wakefulness) {
synchronized(this) {
+ boolean wasAwake = mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE;
+ boolean isAwake = wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE;
mWakefulness = wakefulness;
- updateSleepIfNeededLocked();
+
+ if (wasAwake != isAwake) {
+ // Also update state in a special way for running foreground services UI.
+ mServices.updateScreenStateLocked(isAwake);
+ reportCurWakefulnessUsageEventLocked();
+ mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0)
+ .sendToTarget();
+ }
+ updateOomAdjLocked();
}
}
+ @GuardedBy("this")
void finishRunningVoiceLocked() {
if (mRunningVoice != null) {
mRunningVoice = null;
}
void startTimeTrackingFocusedActivityLocked() {
- if (!mSleeping && mCurAppTimeTracker != null && mFocusedActivity != null) {
- mCurAppTimeTracker.start(mFocusedActivity.packageName);
+ final ActivityRecord resumedActivity = mStackSupervisor.getResumedActivityLocked();
+ if (!mSleeping && mCurAppTimeTracker != null && resumedActivity != null) {
+ mCurAppTimeTracker.start(resumedActivity.packageName);
}
}
+ @GuardedBy("this")
void updateSleepIfNeededLocked() {
- if (mSleeping && !shouldSleepLocked()) {
- mSleeping = false;
- startTimeTrackingFocusedActivityLocked();
- mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
- mStackSupervisor.comeOutOfSleepIfNeededLocked();
- sendNotifyVrManagerOfSleepState(false);
- updateOomAdjLocked();
- } else if (!mSleeping && shouldSleepLocked()) {
+ final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
+ final boolean wasSleeping = mSleeping;
+
+ if (!shouldSleep) {
+ // If wasSleeping is true, we need to wake up activity manager state from when
+ // we started sleeping. In either case, we need to apply the sleep tokens, which
+ // will wake up stacks or put them to sleep as appropriate.
+ if (wasSleeping) {
+ mSleeping = false;
+ startTimeTrackingFocusedActivityLocked();
+ mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+ mStackSupervisor.comeOutOfSleepIfNeededLocked();
+ }
+ mStackSupervisor.applySleepTokensLocked(true /* applyToStacks */);
+ if (wasSleeping) {
+ updateOomAdjLocked();
+ }
+ } else if (!mSleeping && shouldSleep) {
mSleeping = true;
if (mCurAppTimeTracker != null) {
mCurAppTimeTracker.stop();
}
mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
mStackSupervisor.goingToSleepLocked();
- sendNotifyVrManagerOfSleepState(true);
+ updateResumedAppTrace(null /* resumed */);
updateOomAdjLocked();
-
- // Initialize the wake times of all processes.
- checkExcessivePowerUsageLocked(false);
- mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
- }
- }
-
- private boolean shouldSleepLocked() {
- // Resume applications while running a voice interactor.
- if (mRunningVoice != null) {
- return false;
- }
-
- // TODO: Transform the lock screen state into a sleep token instead.
- switch (mWakefulness) {
- case PowerManagerInternal.WAKEFULNESS_AWAKE:
- case PowerManagerInternal.WAKEFULNESS_DREAMING:
- case PowerManagerInternal.WAKEFULNESS_DOZING:
- // Pause applications whenever the lock screen is shown or any sleep
- // tokens have been acquired.
- return (mLockScreenShown != LOCK_SCREEN_HIDDEN || !mSleepTokens.isEmpty());
- case PowerManagerInternal.WAKEFULNESS_ASLEEP:
- default:
- // If we're asleep then pause applications unconditionally.
- return true;
}
}
mRecentTasks.notifyTaskPersisterLocked(task, flush);
}
- /** Notifies all listeners when the task stack has changed. */
- void notifyTaskStackChangedLocked() {
- mHandler.sendEmptyMessage(LOG_STACK_STATE);
- mHandler.removeMessages(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
- Message nmsg = mHandler.obtainMessage(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
- mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
- }
-
- /** Notifies all listeners when an Activity is pinned. */
- void notifyActivityPinnedLocked() {
- mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
- mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG).sendToTarget();
- }
-
/**
- * Notifies all listeners when an attempt was made to start an an activity that is already
- * running in the pinned stack and the activity was not actually started, but the task is
- * either brought to the front or a new Intent is delivered to it.
+ * Notifies all listeners when the pinned stack animation starts.
*/
- void notifyPinnedActivityRestartAttemptLocked() {
- mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
- mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG).sendToTarget();
+ @Override
+ public void notifyPinnedStackAnimationStarted() {
+ mTaskChangeNotificationController.notifyPinnedStackAnimationStarted();
}
- /** Notifies all listeners when the pinned stack animation ends. */
+ /**
+ * Notifies all listeners when the pinned stack animation ends.
+ */
@Override
public void notifyPinnedStackAnimationEnded() {
- synchronized (this) {
- mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
- mHandler.obtainMessage(
- NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG).sendToTarget();
- }
+ mTaskChangeNotificationController.notifyPinnedStackAnimationEnded();
}
@Override
synchronized(this) {
mShuttingDown = true;
+ mStackSupervisor.prepareForShutdownLocked();
updateEventDispatchingLocked();
timedout = mStackSupervisor.shutdownLocked(timeout);
}
Binder.restoreCallingIdentity(origId);
}
- private String lockScreenShownToString() {
- switch (mLockScreenShown) {
- case LOCK_SCREEN_HIDDEN: return "LOCK_SCREEN_HIDDEN";
- case LOCK_SCREEN_LEAVING: return "LOCK_SCREEN_LEAVING";
- case LOCK_SCREEN_SHOWN: return "LOCK_SCREEN_SHOWN";
- default: return "Unknown=" + mLockScreenShown;
- }
- }
-
- void logLockScreen(String msg) {
- if (DEBUG_LOCKSCREEN) Slog.d(TAG_LOCKSCREEN, Debug.getCallers(2) + ":" + msg
- + " mLockScreenShown=" + lockScreenShownToString() + " mWakefulness="
- + PowerManagerInternal.wakefulnessToString(mWakefulness)
- + " mSleeping=" + mSleeping);
- }
-
+ @GuardedBy("this")
void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) {
Slog.d(TAG, "<<< startRunningVoiceLocked()");
mVoiceWakeLock.setWorkSource(new WorkSource(targetUid));
mWindowManager.setEventDispatching(mBooted && !mShuttingDown);
}
- public void setLockScreenShown(boolean showing, boolean occluded) {
+ @Override
+ public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
+ int secondaryDisplayShowing) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
synchronized(this) {
long ident = Binder.clearCallingIdentity();
+ if (mKeyguardShown != keyguardShowing) {
+ mKeyguardShown = keyguardShowing;
+ reportCurKeyguardUsageEventLocked();
+ }
try {
- if (DEBUG_LOCKSCREEN) logLockScreen(" showing=" + showing + " occluded=" + occluded);
- mLockScreenShown = (showing && !occluded) ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN;
- if (showing && occluded) {
- // The lock screen is currently showing, but is occluded by a window that can
- // show on top of the lock screen. In this can we want to dismiss the docked
- // stack since it will be complicated/risky to try to put the activity on top
- // of the lock screen in the right fullscreen configuration.
- mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
- mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
- }
-
- updateSleepIfNeededLocked();
+ mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
+ secondaryDisplayShowing);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
+
+ mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, keyguardShowing ? 1 : 0, 0)
+ .sendToTarget();
}
@Override
}
synchronized (this) {
- if (mStackSupervisor.isUserLockedProfile(userId)) {
- final long ident = Binder.clearCallingIdentity();
- try {
- final int currentUserId = mUserController.getCurrentUserIdLocked();
-
- // Drop locked freeform tasks out into the fullscreen stack.
- // TODO: Redact the tasks in place. It's much better to keep them on the screen
- // where they were before, but in an obscured state.
- mStackSupervisor.moveProfileTasksFromFreeformToFullscreenStackLocked(userId);
-
- if (mUserController.isLockScreenDisabled(currentUserId)) {
- // If there is no device lock, we will show the profile's credential page.
- mActivityStarter.showConfirmDeviceCredential(userId);
- } else {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mUserController.shouldConfirmCredentials(userId)) {
+ if (mKeyguardController.isKeyguardLocked()) {
// Showing launcher to avoid user entering credential twice.
+ final int currentUserId = mUserController.getCurrentUserId();
startHomeActivityLocked(currentUserId, "notifyLockedProfile");
}
- } finally {
- Binder.restoreCallingIdentity(ident);
+ mStackSupervisor.lockAllProfileTasks(userId);
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
}
@Override
- public void startConfirmDeviceCredentialIntent(Intent intent) {
+ public void startConfirmDeviceCredentialIntent(Intent intent, Bundle options) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
- mActivityStarter.startConfirmCredentialIntent(intent);
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
+ FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+ FLAG_ACTIVITY_TASK_ON_HOME);
+ ActivityOptions activityOptions = options != null
+ ? new ActivityOptions(options)
+ : ActivityOptions.makeBasic();
+ activityOptions.setLaunchTaskId(
+ mStackSupervisor.getHomeActivity().getTask().taskId);
+ mContext.startActivityAsUser(intent, activityOptions.toBundle(),
+ UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(ident);
}
@Override
public void stopAppSwitches() {
- if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("viewquires permission "
- + android.Manifest.permission.STOP_APP_SWITCHES);
- }
-
+ enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches");
synchronized(this) {
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
mDidAppSwitch = false;
- mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
- Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
- mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
+ mActivityStartController.schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
}
}
public void resumeAppSwitches() {
- if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.STOP_APP_SWITCHES);
- }
-
+ enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches");
synchronized(this) {
// Note that we don't execute any pending app switches... we will
// let those wait until either the timeout, or the next start
}
}
+ boolean checkAllowAppSwitchUid(int uid) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid));
+ if (types != null) {
+ for (int i = types.size() - 1; i >= 0; i--) {
+ if (types.valueAt(i).intValue() == uid) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
return true;
}
- int perm = checkComponentPermission(
- android.Manifest.permission.STOP_APP_SWITCHES, sourcePid,
- sourceUid, -1, true);
+ if (mRecentTasks.isCallerRecents(sourceUid)) {
+ return true;
+ }
+
+ int perm = checkComponentPermission(STOP_APP_SWITCHES, sourcePid, sourceUid, -1, true);
if (perm == PackageManager.PERMISSION_GRANTED) {
return true;
}
+ if (checkAllowAppSwitchUid(sourceUid)) {
+ return true;
+ }
// If the actual IPC caller is different from the logical source, then
// also see if they are allowed to control app switches.
if (callingUid != -1 && callingUid != sourceUid) {
- perm = checkComponentPermission(
- android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
- callingUid, -1, true);
+ perm = checkComponentPermission(STOP_APP_SWITCHES, callingPid, callingUid, -1, true);
if (perm == PackageManager.PERMISSION_GRANTED) {
return true;
}
+ if (checkAllowAppSwitchUid(callingUid)) {
+ return true;
+ }
}
Slog.w(TAG, name + " request from " + sourceUid + " stopped");
}
}
+ /**
+ * Set or remove an agent to be run whenever an app with the given process name starts.
+ *
+ * This method will not check whether the given process name matches a debuggable app. That
+ * would require scanning all current packages, and a rescan when new packages are installed
+ * or updated.
+ *
+ * Instead, do the check when an application is started and matched to a stored agent.
+ *
+ * @param packageName the process name of the app.
+ * @param agent the agent string to be used, or null to remove any previously set agent.
+ */
+ @Override
+ public void setAgentApp(@NonNull String packageName, @Nullable String agent) {
+ synchronized (this) {
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission.
+ if (checkCallingPermission(
+ android.Manifest.permission.SET_ACTIVITY_WATCHER) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ if (agent == null) {
+ if (mAppAgentMap != null) {
+ mAppAgentMap.remove(packageName);
+ if (mAppAgentMap.isEmpty()) {
+ mAppAgentMap = null;
+ }
+ }
+ } else {
+ if (mAppAgentMap == null) {
+ mAppAgentMap = new HashMap<>();
+ }
+ if (mAppAgentMap.size() >= 100) {
+ // Limit the size of the map, to avoid OOMEs.
+ Slog.e(TAG, "App agent map has too many entries, cannot add " + packageName
+ + "/" + agent);
+ return;
+ }
+ mAppAgentMap.put(packageName, agent);
+ }
+ }
+ }
+
void setTrackAllocationApp(ApplicationInfo app, String processName) {
synchronized (this) {
boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
}
}
mProfileApp = processName;
- mProfileFile = profilerInfo.profileFile;
- if (mProfileFd != null) {
- try {
- mProfileFd.close();
- } catch (IOException e) {
+
+ if (mProfilerInfo != null) {
+ if (mProfilerInfo.profileFd != null) {
+ try {
+ mProfilerInfo.profileFd.close();
+ } catch (IOException e) {
+ }
}
- mProfileFd = null;
}
- mProfileFd = profilerInfo.profileFd;
- mSamplingInterval = profilerInfo.samplingInterval;
- mAutoStopProfiler = profilerInfo.autoStopProfiler;
+ mProfilerInfo = new ProfilerInfo(profilerInfo);
mProfileType = 0;
}
}
}
@Override
- public void setLenientBackgroundCheck(boolean enabled) {
- enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
- "setLenientBackgroundCheck()");
-
- long ident = Binder.clearCallingIdentity();
- try {
- Settings.Global.putInt(
- mContext.getContentResolver(),
- Settings.Global.LENIENT_BACKGROUND_CHECK, enabled ? 1 : 0);
-
- synchronized (this) {
- mLenientBackgroundCheck = enabled;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
public void setActivityController(IActivityController controller, boolean imAMonkey) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"setActivityController()");
synchronized (this) {
synchronized (mPidsSelfLocked) {
final int callingPid = Binder.getCallingPid();
- ProcessRecord precessRecord = mPidsSelfLocked.get(callingPid);
- if (precessRecord == null) {
+ ProcessRecord proc = mPidsSelfLocked.get(callingPid);
+ if (proc == null) {
throw new SecurityException("Unknown process: " + callingPid);
}
- if (precessRecord.instrumentationUiAutomationConnection == null) {
+ if (proc.instr == null || proc.instr.mUiAutomationConnection == null) {
throw new SecurityException("Only an instrumentation process "
+ "with a UiAutomation can call setUserIsMonkey");
}
}
}
+ /**
+ * @deprecated This method is only used by a few internal components and it will soon be
+ * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
+ * No new code should be calling it.
+ */
+ @Deprecated
+ @Override
public void requestBugReport(int bugreportType) {
- String service = null;
+ String extraOptions = null;
switch (bugreportType) {
case ActivityManager.BUGREPORT_OPTION_FULL:
- service = "bugreport";
+ // Default options.
break;
case ActivityManager.BUGREPORT_OPTION_INTERACTIVE:
- service = "bugreportplus";
+ extraOptions = "bugreportplus";
break;
case ActivityManager.BUGREPORT_OPTION_REMOTE:
- service = "bugreportremote";
+ extraOptions = "bugreportremote";
break;
case ActivityManager.BUGREPORT_OPTION_WEAR:
- service = "bugreportwear";
+ extraOptions = "bugreportwear";
break;
case ActivityManager.BUGREPORT_OPTION_TELEPHONY:
- service = "bugreportelefony";
+ extraOptions = "bugreporttelephony";
break;
+ case ActivityManager.BUGREPORT_OPTION_WIFI:
+ extraOptions = "bugreportwifi";
+ break;
+ default:
+ throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
+ + bugreportType);
}
- if (service == null) {
- throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
- + bugreportType);
- }
+ // Always log caller, even if it does not have permission to dump.
+ String type = extraOptions == null ? "bugreport" : extraOptions;
+ Slog.i(TAG, type + " requested by UID " + Binder.getCallingUid());
+
enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport");
- SystemProperties.set("ctl.start", service);
+ if (extraOptions != null) {
+ SystemProperties.set("dumpstate.options", extraOptions);
+ }
+ SystemProperties.set("ctl.start", "bugreport");
+ }
+
+ /**
+ * @deprecated This method is only used by a few internal components and it will soon be
+ * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
+ * No new code should be calling it.
+ */
+ @Deprecated
+ private void requestBugReportWithDescription(String shareTitle, String shareDescription,
+ int bugreportType) {
+ if (!TextUtils.isEmpty(shareTitle)) {
+ if (shareTitle.length() > MAX_BUGREPORT_TITLE_SIZE) {
+ String errorStr = "shareTitle should be less than " +
+ MAX_BUGREPORT_TITLE_SIZE + " characters";
+ throw new IllegalArgumentException(errorStr);
+ } else {
+ if (!TextUtils.isEmpty(shareDescription)) {
+ int length;
+ try {
+ length = shareDescription.getBytes("UTF-8").length;
+ } catch (UnsupportedEncodingException e) {
+ String errorStr = "shareDescription: UnsupportedEncodingException";
+ throw new IllegalArgumentException(errorStr);
+ }
+ if (length > SystemProperties.PROP_VALUE_MAX) {
+ String errorStr = "shareTitle should be less than " +
+ SystemProperties.PROP_VALUE_MAX + " bytes";
+ throw new IllegalArgumentException(errorStr);
+ } else {
+ SystemProperties.set("dumpstate.options.description", shareDescription);
+ }
+ }
+ SystemProperties.set("dumpstate.options.title", shareTitle);
+ }
+ }
+
+ Slog.d(TAG, "Bugreport notification title " + shareTitle
+ + " description " + shareDescription);
+ requestBugReport(bugreportType);
}
+ /**
+ * @deprecated This method is only used by a few internal components and it will soon be
+ * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
+ * No new code should be calling it.
+ */
+ @Deprecated
+ @Override
+ public void requestTelephonyBugReport(String shareTitle, String shareDescription) {
+ requestBugReportWithDescription(shareTitle, shareDescription,
+ ActivityManager.BUGREPORT_OPTION_TELEPHONY);
+ }
+
+ /**
+ * @deprecated This method is only used by a few internal components and it will soon be
+ * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
+ * No new code should be calling it.
+ */
+ @Deprecated
+ @Override
+ public void requestWifiBugReport(String shareTitle, String shareDescription) {
+ requestBugReportWithDescription(shareTitle, shareDescription,
+ ActivityManager.BUGREPORT_OPTION_WIFI);
+ }
+
+
public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
return r != null ? getInputDispatchingTimeoutLocked(r.app) : KEY_DISPATCHING_TIMEOUT;
}
public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
- if (r != null && (r.instrumentationClass != null || r.usingWrapper)) {
+ if (r != null && (r.instr != null || r.usingWrapper)) {
return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
}
return KEY_DISPATCHING_TIMEOUT;
timeout = getInputDispatchingTimeoutLocked(proc);
}
- if (!inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
+ if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
return -1;
}
return false;
}
- if (mDidDexOpt) {
- // Give more time since we were dexopting.
- mDidDexOpt = false;
- return false;
- }
-
- if (proc.instrumentationClass != null) {
+ if (proc.instr != null) {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", annotation);
public Bundle getAssistContextExtras(int requestType) {
PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
null, null, true /* focused */, true /* newSessionId */,
- UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+ UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT, 0);
if (pae == null) {
return null;
}
public boolean isAssistDataAllowedOnCurrentActivity() {
int userId;
synchronized (this) {
- userId = mUserController.getCurrentUserIdLocked();
- ActivityRecord activity = getFocusedStack().topActivity();
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack == null || focusedStack.isActivityTypeAssistant()) {
+ return false;
+ }
+
+ final ActivityRecord activity = focusedStack.getTopActivity();
if (activity == null) {
return false;
}
userId = activity.userId;
}
- DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- return (dpm == null) || (!dpm.getScreenCaptureDisabled(null, userId));
+ return !DevicePolicyCache.getInstance().getScreenCaptureDisabled(userId);
}
@Override
try {
synchronized (this) {
ActivityRecord caller = ActivityRecord.forTokenLocked(token);
- ActivityRecord top = getFocusedStack().topActivity();
+ ActivityRecord top = getFocusedStack().getTopActivity();
if (top != caller) {
Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
+ " is not current top " + top);
return false;
}
}
- AssistUtils utils = new AssistUtils(mContext);
- return utils.showSessionForActiveService(args,
- VoiceInteractionSession.SHOW_SOURCE_APPLICATION, null, token);
+ return mAssistUtils.showSessionForActiveService(args, SHOW_SOURCE_APPLICATION, null,
+ token);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
- public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
- Bundle receiverExtras,
- IBinder activityToken, boolean focused, boolean newSessionId) {
+ public boolean requestAssistContextExtras(int requestType, IAssistDataReceiver receiver,
+ Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId) {
return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
- activityToken, focused, newSessionId,
- UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
- != null;
+ activityToken, focused, newSessionId, UserHandle.getCallingUserId(), null,
+ PENDING_ASSIST_EXTRAS_LONG_TIMEOUT, 0) != null;
+ }
+
+ @Override
+ public boolean requestAutofillData(IAssistDataReceiver receiver, Bundle receiverExtras,
+ IBinder activityToken, int flags) {
+ return enqueueAssistContext(ActivityManager.ASSIST_CONTEXT_AUTOFILL, null, null,
+ receiver, receiverExtras, activityToken, true, true, UserHandle.getCallingUserId(),
+ null, PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT, flags) != null;
}
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
- IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken,
- boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout) {
+ IAssistDataReceiver receiver, Bundle receiverExtras, IBinder activityToken,
+ boolean focused, boolean newSessionId, int userHandle, Bundle args, long timeout,
+ int flags) {
enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
"enqueueAssistContext()");
+
synchronized (this) {
- ActivityRecord activity = getFocusedStack().topActivity();
+ ActivityRecord activity = getFocusedStack().getTopActivity();
if (activity == null) {
Slog.w(TAG, "getAssistContextExtras failed: no top activity");
return null;
+ " couldn't be found");
return null;
}
+ if (activity.app == null || activity.app.thread == null) {
+ Slog.w(TAG, "enqueueAssistContext failed: no process for " + activity);
+ return null;
+ }
}
PendingAssistExtras pae;
}
extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
+
pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
userHandle);
+ pae.isHome = activity.isActivityTypeHome();
+
// Increment the sessionId if necessary
if (newSessionId) {
mViSessionId++;
}
try {
- activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
- requestType, mViSessionId);
+ activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType,
+ mViSessionId, flags);
mPendingAssistExtras.add(pae);
mUiHandler.postDelayed(pae, timeout);
} catch (RemoteException e) {
}
void pendingAssistExtrasTimedOut(PendingAssistExtras pae) {
- IResultReceiver receiver;
+ IAssistDataReceiver receiver;
synchronized (this) {
mPendingAssistExtras.remove(pae);
receiver = pae.receiver;
// Caller wants result sent back to them.
Bundle sendBundle = new Bundle();
// At least return the receiver extras
- sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
- pae.receiverExtras);
+ sendBundle.putBundle(ASSIST_KEY_RECEIVER_EXTRAS, pae.receiverExtras);
try {
- pae.receiver.send(0, sendBundle);
+ pae.receiver.onHandleAssistData(sendBundle);
} catch (RemoteException e) {
}
}
}
}
+ /** Called from an app when assist data is ready. */
+ @Override
public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
AssistContent content, Uri referrer) {
PendingAssistExtras pae = (PendingAssistExtras)token;
if (referrer != null) {
pae.extras.putParcelable(Intent.EXTRA_REFERRER, referrer);
}
+ if (structure != null) {
+ structure.setHomeActivity(pae.isHome);
+ }
pae.haveResult = true;
pae.notifyAll();
if (pae.intent == null && pae.receiver == null) {
return;
}
}
-
// We are now ready to launch the assist activity.
- IResultReceiver sendReceiver = null;
+ IAssistDataReceiver sendReceiver = null;
Bundle sendBundle = null;
synchronized (this) {
buildAssistBundleLocked(pae, extras);
// Timed out.
return;
}
+
if ((sendReceiver=pae.receiver) != null) {
// Caller wants result sent back to them.
sendBundle = new Bundle();
- sendBundle.putBundle(VoiceInteractionSession.KEY_DATA, pae.extras);
- sendBundle.putParcelable(VoiceInteractionSession.KEY_STRUCTURE, pae.structure);
- sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
- sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
- pae.receiverExtras);
+ sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
+ sendBundle.putParcelable(ASSIST_KEY_STRUCTURE, pae.structure);
+ sendBundle.putParcelable(ASSIST_KEY_CONTENT, pae.content);
+ sendBundle.putBundle(ASSIST_KEY_RECEIVER_EXTRAS, pae.receiverExtras);
}
}
if (sendReceiver != null) {
try {
- sendReceiver.send(0, sendBundle);
+ sendReceiver.onHandleAssistData(sendBundle);
} catch (RemoteException e) {
}
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
- pae.intent.replaceExtras(pae.extras);
- pae.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_SINGLE_TOP
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- closeSystemDialogs("assist");
- try {
- mContext.startActivityAsUser(pae.intent, new UserHandle(pae.userHandle));
- } catch (ActivityNotFoundException e) {
- Slog.w(TAG, "No activity to handle assist action.", e);
+ if (TextUtils.equals(pae.intent.getAction(),
+ android.service.voice.VoiceInteractionService.SERVICE_INTERFACE)) {
+ pae.intent.putExtras(pae.extras);
+ mContext.startServiceAsUser(pae.intent, new UserHandle(pae.userHandle));
+ } else {
+ pae.intent.replaceExtras(pae.extras);
+ pae.intent.setFlags(FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ closeSystemDialogs("assist");
+
+ try {
+ mContext.startActivityAsUser(pae.intent, new UserHandle(pae.userHandle));
+ } catch (ActivityNotFoundException e) {
+ Slog.w(TAG, "No activity to handle assist action.", e);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
Bundle args) {
return enqueueAssistContext(requestType, intent, hint, null, null, null,
- true /* focused */, true /* newSessionId */,
- userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+ true /* focused */, true /* newSessionId */, userHandle, args,
+ PENDING_ASSIST_EXTRAS_TIMEOUT, 0) != null;
}
public void registerProcessObserver(IProcessObserver observer) {
}
@Override
- public void registerUidObserver(IUidObserver observer, int which) {
- enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
- "registerUidObserver()");
+ public int getUidProcessState(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "getUidProcessState");
+ }
+
+ synchronized (this) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ return uidRec != null ? uidRec.curProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+ }
+ }
+
+ @Override
+ public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
+ String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "registerUidObserver");
+ }
synchronized (this) {
- mUidObservers.register(observer, which);
+ mUidObservers.register(observer, new UidObserverRegistration(Binder.getCallingUid(),
+ callingPackage, which, cutpoint));
}
}
}
@Override
+ public boolean isUidActive(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "isUidActive");
+ }
+ synchronized (this) {
+ return isUidActiveLocked(uid);
+ }
+ }
+
+ boolean isUidActiveLocked(int uid) {
+ final UidRecord uidRecord = mActiveUids.get(uid);
+ return uidRecord != null && !uidRecord.setIdle;
+ }
+
+ @Override
public boolean convertFromTranslucent(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
}
final boolean translucentChanged = r.changeWindowTranslucency(true);
if (translucentChanged) {
- r.task.stack.releaseBackgroundResources(r);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
mWindowManager.setAppFullscreen(token, true);
}
@Override
- public boolean convertToTranslucent(IBinder token, ActivityOptions options) {
+ public boolean convertToTranslucent(IBinder token, Bundle options) {
+ SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options);
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
if (r == null) {
return false;
}
- int index = r.task.mActivities.lastIndexOf(r);
+ final TaskRecord task = r.getTask();
+ int index = task.mActivities.lastIndexOf(r);
if (index > 0) {
- ActivityRecord under = r.task.mActivities.get(index - 1);
- under.returningOptions = options;
+ ActivityRecord under = task.mActivities.get(index - 1);
+ under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
}
final boolean translucentChanged = r.changeWindowTranslucency(false);
if (translucentChanged) {
- r.task.stack.convertActivityToTranslucent(r);
+ r.getStack().convertActivityToTranslucent(r);
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.setAppFullscreen(token, false);
}
@Override
- public boolean requestVisibleBehind(IBinder token, boolean visible) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r != null) {
- return mStackSupervisor.requestVisibleBehindLocked(r, visible);
- }
- }
- return false;
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
- public boolean isBackgroundVisibleBehind(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- final ActivityStack stack = ActivityRecord.getStackLocked(token);
- final boolean visible = stack == null ? false : stack.hasVisibleBehindActivity();
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
- "isBackgroundVisibleBehind: stack=" + stack + " visible=" + visible);
- return visible;
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
- public ActivityOptions getActivityOptions(IBinder token) {
+ public Bundle getActivityOptions(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- final ActivityOptions activityOptions = r.pendingOptions;
- r.pendingOptions = null;
- return activityOptions;
+ final ActivityOptions activityOptions = r.takeOptionsLocked();
+ return activityOptions == null ? null : activityOptions.toBundle();
}
return null;
}
r.immersive = immersive;
// update associated state if we're frontmost
- if (r == mFocusedActivity) {
+ if (r == mStackSupervisor.getResumedActivityLocked()) {
if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
applyUpdateLockStateLocked(r);
}
}
}
+ @Override
public void setVrThread(int tid) {
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
- throw new UnsupportedOperationException("VR mode not supported on this device!");
+ enforceSystemHasVrFeature();
+ synchronized (this) {
+ synchronized (mPidsSelfLocked) {
+ final int pid = Binder.getCallingPid();
+ final ProcessRecord proc = mPidsSelfLocked.get(pid);
+ mVrController.setVrThreadLocked(tid, pid, proc);
+ }
}
+ }
+ @Override
+ public void setPersistentVrThread(int tid) {
+ if (checkCallingPermission(permission.RESTRICTED_VR_ACCESS) != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: setPersistentVrThread() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + permission.RESTRICTED_VR_ACCESS;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ enforceSystemHasVrFeature();
synchronized (this) {
- ProcessRecord proc;
synchronized (mPidsSelfLocked) {
final int pid = Binder.getCallingPid();
- proc = mPidsSelfLocked.get(pid);
-
- if (proc != null && mInVrMode && tid >= 0) {
- // ensure the tid belongs to the process
- if (!Process.isThreadInProcess(pid, tid)) {
- throw new IllegalArgumentException("VR thread does not belong to process");
- }
-
- // reset existing VR thread to CFS if this thread still exists and belongs to
- // the calling process
- if (proc.vrThreadTid != 0
- && Process.isThreadInProcess(pid, proc.vrThreadTid)) {
- try {
- Process.setThreadScheduler(proc.vrThreadTid, Process.SCHED_OTHER, 0);
- } catch (IllegalArgumentException e) {
- // Ignore this. Only occurs in race condition where previous VR thread
- // was destroyed during this method call.
- }
- }
+ final ProcessRecord proc = mPidsSelfLocked.get(pid);
+ mVrController.setPersistentVrThreadLocked(tid, pid, proc);
+ }
+ }
+ }
- proc.vrThreadTid = tid;
+ /**
+ * Schedule the given thread a normal scheduling priority.
+ *
+ * @param tid the tid of the thread to adjust the scheduling of.
+ * @param suppressLogs {@code true} if any error logging should be disabled.
+ *
+ * @return {@code true} if this succeeded.
+ */
+ static boolean scheduleAsRegularPriority(int tid, boolean suppressLogs) {
+ try {
+ Process.setThreadScheduler(tid, Process.SCHED_OTHER, 0);
+ return true;
+ } catch (IllegalArgumentException e) {
+ if (!suppressLogs) {
+ Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);
+ }
+ } catch (SecurityException e) {
+ if (!suppressLogs) {
+ Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
+ }
+ }
+ return false;
+ }
- // promote to FIFO now if the tid is non-zero
- try {
- if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
- proc.vrThreadTid > 0) {
- Process.setThreadScheduler(proc.vrThreadTid,
- Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
- }
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Failed to set scheduling policy, thread does"
- + " not exist:\n" + e);
- }
- }
+ /**
+ * Schedule the given thread an FIFO scheduling priority.
+ *
+ * @param tid the tid of the thread to adjust the scheduling of.
+ * @param suppressLogs {@code true} if any error logging should be disabled.
+ *
+ * @return {@code true} if this succeeded.
+ */
+ static boolean scheduleAsFifoPriority(int tid, boolean suppressLogs) {
+ try {
+ Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+ return true;
+ } catch (IllegalArgumentException e) {
+ if (!suppressLogs) {
+ Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);
+ }
+ } catch (SecurityException e) {
+ if (!suppressLogs) {
+ Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
}
}
+ return false;
+ }
+
+ /**
+ * Check that we have the features required for VR-related API calls, and throw an exception if
+ * not.
+ */
+ private void enforceSystemHasVrFeature() {
+ if (!mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+ throw new UnsupportedOperationException("VR mode not supported on this device!");
+ }
}
@Override
public void setRenderThread(int tid) {
synchronized (this) {
ProcessRecord proc;
+ int pid = Binder.getCallingPid();
+ if (pid == Process.myPid()) {
+ demoteSystemServerRenderThread(tid);
+ return;
+ }
synchronized (mPidsSelfLocked) {
- int pid = Binder.getCallingPid();
proc = mPidsSelfLocked.get(pid);
if (proc != null && proc.renderThreadTid == 0 && tid > 0) {
// ensure the tid belongs to the process
- if (!Process.isThreadInProcess(pid, tid)) {
+ if (!isThreadInProcess(pid, tid)) {
throw new IllegalArgumentException(
"Render thread does not belong to process");
}
if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band");
if (mUseFifoUiScheduling) {
- Process.setThreadScheduler(proc.renderThreadTid,
- Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+ setThreadScheduler(proc.renderThreadTid,
+ SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
} else {
- Process.setThreadPriority(proc.renderThreadTid, -10);
+ setThreadPriority(proc.renderThreadTid, TOP_APP_PRIORITY_BOOST);
}
}
} else {
}
}
+ /**
+ * We only use RenderThread in system_server to store task snapshots to the disk, which should
+ * happen in the background. Thus, demote render thread from system_server to a lower priority.
+ *
+ * @param tid the tid of the RenderThread
+ */
+ private void demoteSystemServerRenderThread(int tid) {
+ setThreadPriority(tid, Process.THREAD_PRIORITY_BACKGROUND);
+ }
+
@Override
public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
- throw new UnsupportedOperationException("VR mode not supported on this device!");
- }
+ enforceSystemHasVrFeature();
final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
return err;
}
- synchronized(this) {
- r.requestedVrComponent = (enabled) ? packageName : null;
+ // Clear the binder calling uid since this path may call moveToTask().
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ r.requestedVrComponent = (enabled) ? packageName : null;
- // Update associated state if this activity is currently focused
- if (r == mFocusedActivity) {
- applyUpdateVrModeLocked(r);
+ // Update associated state if this activity is currently focused
+ if (r == mStackSupervisor.getResumedActivityLocked()) {
+ applyUpdateVrModeLocked(r);
+ }
+ return 0;
}
- return 0;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@Override
public boolean isVrModePackageEnabled(ComponentName packageName) {
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
- throw new UnsupportedOperationException("VR mode not supported on this device!");
- }
+ enforceSystemHasVrFeature();
final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
}
}
+ /**
+ * @return whether the system should disable UI modes incompatible with VR mode.
+ */
+ boolean shouldDisableNonVrUiLocked() {
+ return mVrController.shouldDisableNonVrUiLocked();
+ }
+
@Override
public boolean isTopOfTask(IBinder token) {
synchronized (this) {
if (r == null) {
throw new IllegalArgumentException();
}
- return r.task.getTopActivity() == r;
+ return r.getTask().getTopActivity() == r;
}
}
return;
}
if (pr.hasTopUi != hasTopUi) {
- Slog.i(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + pid);
+ if (DEBUG_OOM_ADJ) {
+ Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + pid);
+ }
pr.hasTopUi = hasTopUi;
changed = true;
}
}
if (changed) {
- updateOomAdjLocked(pr);
+ updateOomAdjLocked(pr, true);
}
}
} finally {
}
}
+ void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
+ if (pid == Process.myPid()) {
+ Slog.wtf(TAG, "system can't run remote animation");
+ return;
+ }
+ synchronized (ActivityManagerService.this) {
+ final ProcessRecord pr;
+ synchronized (mPidsSelfLocked) {
+ pr = mPidsSelfLocked.get(pid);
+ if (pr == null) {
+ Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid);
+ return;
+ }
+ }
+ if (pr.runningRemoteAnimation == runningRemoteAnimation) {
+ return;
+ }
+ pr.runningRemoteAnimation = runningRemoteAnimation;
+ if (DEBUG_OOM_ADJ) {
+ Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation
+ + " for pid=" + pid);
+ }
+ updateOomAdjLocked(pr, true);
+ }
+ }
+
public final void enterSafeMode() {
synchronized(this) {
// It only makes sense to do this before the system is ready
Context.WINDOW_SERVICE)).addView(v, lp);
}
- public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag) {
- if (sender != null && !(sender instanceof PendingIntentRecord)) {
- return;
+ @Override
+ public void noteWakeupAlarm(IIntentSender sender, WorkSource workSource, int sourceUid,
+ String sourcePkg, String tag) {
+ if (workSource != null && workSource.isEmpty()) {
+ workSource = null;
}
- final PendingIntentRecord rec = (PendingIntentRecord)sender;
- final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- if (mBatteryStatsService.isOnBattery()) {
- mBatteryStatsService.enforceCallingPermission();
- int MY_UID = Binder.getCallingUid();
- final int uid;
- if (sender == null) {
- uid = sourceUid;
- } else {
- uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+
+ if (sourceUid <= 0 && workSource == null) {
+ // Try and derive a UID to attribute things to based on the caller.
+ if (sender != null) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
}
- BatteryStatsImpl.Uid.Pkg pkg =
- stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
- sourcePkg != null ? sourcePkg : rec.key.packageName);
- pkg.noteWakeupAlarmLocked(tag);
+
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ final int callerUid = Binder.getCallingUid();
+ sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
+ } else {
+ // TODO(narayan): Should we throw an exception in this case ? It means that we
+ // haven't been able to derive a UID to attribute things to.
+ return;
}
}
+
+ if (DEBUG_POWER) {
+ Slog.w(TAG, "noteWakupAlarm[ sourcePkg=" + sourcePkg + ", sourceUid=" + sourceUid
+ + ", workSource=" + workSource + ", tag=" + tag + "]");
+ }
+
+ mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
}
- public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag) {
- if (sender != null && !(sender instanceof PendingIntentRecord)) {
- return;
+ @Override
+ public void noteAlarmStart(IIntentSender sender, WorkSource workSource, int sourceUid,
+ String tag) {
+ if (workSource != null && workSource.isEmpty()) {
+ workSource = null;
}
- final PendingIntentRecord rec = (PendingIntentRecord)sender;
- final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- mBatteryStatsService.enforceCallingPermission();
- int MY_UID = Binder.getCallingUid();
- final int uid;
- if (sender == null) {
- uid = sourceUid;
+
+ if (sourceUid <= 0 && workSource == null) {
+ // Try and derive a UID to attribute things to based on the caller.
+ if (sender != null) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ final int callerUid = Binder.getCallingUid();
+ sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
} else {
- uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+ // TODO(narayan): Should we throw an exception in this case ? It means that we
+ // haven't been able to derive a UID to attribute things to.
+ return;
}
- mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
}
+
+ if (DEBUG_POWER) {
+ Slog.w(TAG, "noteAlarmStart[sourceUid=" + sourceUid + ", workSource=" + workSource +
+ ", tag=" + tag + "]");
+ }
+
+ mBatteryStatsService.noteAlarmStart(tag, workSource, sourceUid);
}
- public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag) {
- if (sender != null && !(sender instanceof PendingIntentRecord)) {
- return;
+ @Override
+ public void noteAlarmFinish(IIntentSender sender, WorkSource workSource, int sourceUid,
+ String tag) {
+ if (workSource != null && workSource.isEmpty()) {
+ workSource = null;
}
- final PendingIntentRecord rec = (PendingIntentRecord)sender;
- final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- mBatteryStatsService.enforceCallingPermission();
- int MY_UID = Binder.getCallingUid();
- final int uid;
- if (sender == null) {
- uid = sourceUid;
+
+ if (sourceUid <= 0 && workSource == null) {
+ // Try and derive a UID to attribute things to based on the caller.
+ if (sender != null) {
+ if (!(sender instanceof PendingIntentRecord)) {
+ return;
+ }
+
+ final PendingIntentRecord rec = (PendingIntentRecord) sender;
+ final int callerUid = Binder.getCallingUid();
+ sourceUid = rec.uid == callerUid ? SYSTEM_UID : rec.uid;
} else {
- uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+ // TODO(narayan): Should we throw an exception in this case ? It means that we
+ // haven't been able to derive a UID to attribute things to.
+ return;
}
- mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
}
+
+ if (DEBUG_POWER) {
+ Slog.w(TAG, "noteAlarmFinish[sourceUid=" + sourceUid + ", workSource=" + workSource +
+ ", tag=" + tag + "]");
+ }
+
+ mBatteryStatsService.noteAlarmFinish(tag, workSource, sourceUid);
}
public boolean killPids(int[] pids, String pReason, boolean secure) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (Binder.getCallingUid() != SYSTEM_UID) {
throw new SecurityException("killPids only available to the system");
}
String reason = (pReason == null) ? "Unknown" : pReason;
@Override
public boolean killProcessesBelowForeground(String reason) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (Binder.getCallingUid() != SYSTEM_UID) {
throw new SecurityException("killProcessesBelowForeground() only available to system");
}
}
private boolean killProcessesBelowAdj(int belowAdj, String reason) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (Binder.getCallingUid() != SYSTEM_UID) {
throw new SecurityException("killProcessesBelowAdj() only available to system");
}
Log.i(TAG, "Shutting down activity manager...");
shutdown(10000);
Log.i(TAG, "Shutdown complete, restarting!");
- Process.killProcess(Process.myPid());
+ killProcess(myPid());
System.exit(10);
}
};
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord proc = mLruProcesses.get(i);
if (proc.notCachedSinceIdle) {
- if (proc.setProcState != ActivityManager.PROCESS_STATE_TOP_SLEEPING
- && proc.setProcState >= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+ if (proc.setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
if (doKilling && proc.initialIdlePss != 0
&& proc.lastPss > ((proc.initialIdlePss*3)/2)) {
}
}
} else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME
- && proc.setProcState > ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ && proc.setProcState >= ActivityManager.PROCESS_STATE_PERSISTENT) {
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
- proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
+ proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, null,
mTestPssMode, isSleepingLocked(), now);
}
}
-
- mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
- mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
}
}
.setPackage("android")
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
broadcastIntent(null, intent, null, null, 0, null, null, null,
- android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL);
+ OP_NONE, null, false, false, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
|| Settings.Global.getInt(
resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
- final boolean supportsPictureInPicture =
- mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
- final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow();
+ final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow(mContext);
+ final boolean supportsPictureInPicture = supportsMultiWindow &&
+ mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+ final boolean supportsSplitScreenMultiWindow =
+ ActivityManager.supportsSplitScreenMultiWindow(mContext);
+ final boolean supportsMultiDisplay = mContext.getPackageManager()
+ .hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
- final boolean lenientBackgroundCheck =
- Settings.Global.getInt(resolver, LENIENT_BACKGROUND_CHECK, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
+ final long waitForNetworkTimeoutMs = Settings.Global.getLong(resolver,
+ NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS);
final boolean supportsLeanbackOnly =
mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY);
+ mHiddenApiBlacklist.registerObserver();
// Transfer any global setting for forcing RTL layout, into a System Property
SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
- mLenientBackgroundCheck = lenientBackgroundCheck;
mSupportsLeanbackOnly = supportsLeanbackOnly;
mForceResizableActivities = forceResizable;
- mWindowManager.setForceResizableTasks(mForceResizableActivities);
- if (supportsMultiWindow || forceResizable) {
+ final boolean multiWindowFormEnabled = freeformWindowManagement
+ || supportsSplitScreenMultiWindow
+ || supportsPictureInPicture
+ || supportsMultiDisplay;
+ if ((supportsMultiWindow || forceResizable) && multiWindowFormEnabled) {
mSupportsMultiWindow = true;
- mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
- mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+ mSupportsFreeformWindowManagement = freeformWindowManagement;
+ mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
+ mSupportsPictureInPicture = supportsPictureInPicture;
+ mSupportsMultiDisplay = supportsMultiDisplay;
} else {
mSupportsMultiWindow = false;
mSupportsFreeformWindowManagement = false;
+ mSupportsSplitScreenMultiWindow = false;
mSupportsPictureInPicture = false;
+ mSupportsMultiDisplay = false;
}
- // This happens before any activities are started, so we can
- // change mConfiguration in-place.
+ mWindowManager.setForceResizableTasks(mForceResizableActivities);
+ mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
+ // This happens before any activities are started, so we can change global configuration
+ // in-place.
updateConfigurationLocked(configuration, null, true);
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Initial config: " + mConfiguration);
+ final Configuration globalConfig = getGlobalConfiguration();
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
// Load resources only after the current configuration has been set.
final Resources res = mContext.getResources();
- mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
mThumbnailWidth = res.getDimensionPixelSize(
com.android.internal.R.dimen.thumbnail_width);
mThumbnailHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.thumbnail_height);
- mDefaultPinnedStackBounds = Rect.unflattenFromString(res.getString(
- com.android.internal.R.string.config_defaultPictureInPictureBounds));
mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
com.android.internal.R.string.config_appsNotReportingCrashes));
- if ((mConfiguration.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
+ mUserController.mUserSwitchUiEnabled = !res.getBoolean(
+ com.android.internal.R.bool.config_customUserSwitchUi);
+ mUserController.mMaxRunningUsers = res.getInteger(
+ com.android.internal.R.integer.config_multiuserMaxRunningUsers);
+
+ if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
mFullscreenThumbnailScale = (float) res
.getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
- (float) mConfiguration.screenWidthDp;
+ (float) globalConfig.screenWidthDp;
} else {
mFullscreenThumbnailScale = res.getFraction(
com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
}
+ mWaitForNetworkTimeoutMs = waitForNetworkTimeoutMs;
}
}
- public boolean testIsSystemReady() {
- // no need to synchronize(this) just to read & return the value
- return mSystemReady;
- }
-
- public void systemReady(final Runnable goingCallback) {
+ public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
+ traceLog.traceBegin("PhaseActivityManagerReady");
synchronized(this) {
if (mSystemReady) {
// If we're done calling all the receivers, run the next "boot phase" passed in
return;
}
+ mHasHeavyWeightFeature = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_CANT_SAVE_STATE);
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
-
+ mAssistUtils = new AssistUtils(mContext);
+ mVrController.onSystemReady();
// Make sure we have the current profile info, since it is needed for security checks.
mUserController.onSystemReady();
mRecentTasks.onSystemReadyLocked();
mSystemReady = true;
}
+ try {
+ sTheRealBuildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
+ .getSerial();
+ } catch (RemoteException e) {}
+
ArrayList<ProcessRecord> procsToKill = null;
synchronized(mPidsSelfLocked) {
for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
}
retrieveSettings();
- final int currentUserId;
+ final int currentUserId = mUserController.getCurrentUserId();
synchronized (this) {
- currentUserId = mUserController.getCurrentUserIdLocked();
readGrantedUriPermissionsLocked();
}
- if (goingCallback != null) goingCallback.run();
+ final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
+ if (pmi != null) {
+ pmi.registerLowPowerModeObserver(ServiceType.FORCE_BACKGROUND_CHECK,
+ state -> updateForceBackgroundCheck(state.batterySaverEnabled));
+ updateForceBackgroundCheck(
+ pmi.getLowPowerState(ServiceType.FORCE_BACKGROUND_CHECK).batterySaverEnabled);
+ } else {
+ Slog.wtf(TAG, "PowerManagerInternal not found.");
+ }
+ if (goingCallback != null) goingCallback.run();
+ traceLog.traceBegin("ActivityManagerStartApps");
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
Integer.toString(currentUserId), currentUserId);
mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
// Start up initial activity.
mBooting = true;
- // Enable home activity for system user, so that the system can always boot
- if (UserManager.isSplitSystemUser()) {
+ // Enable home activity for system user, so that the system can always boot. We don't
+ // do this when the system user is not setup since the setup wizard should be the one
+ // to handle home activity in this case.
+ if (UserManager.isSplitSystemUser() &&
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0) != 0) {
ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
try {
AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, Process.SYSTEM_UID,
+ null, null, 0, null, null, null, OP_NONE,
+ null, false, false, MY_PID, SYSTEM_UID,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
throws RemoteException {
}
}, 0, null, null,
- new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
+ null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
} catch (Throwable t) {
Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
Binder.restoreCallingIdentity(ident);
}
mStackSupervisor.resumeFocusedStackTopActivityLocked();
- mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
+ mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
+
+ BinderInternal.nSetBinderProxyCountWatermarks(6000,5500);
+ BinderInternal.nSetBinderProxyCountEnabled(true);
+ BinderInternal.setBinderProxyCountCallback(
+ new BinderInternal.BinderProxyLimitListener() {
+ @Override
+ public void onLimitReached(int uid) {
+ Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+ + Process.myUid());
+ if (uid == Process.SYSTEM_UID) {
+ Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
+ } else {
+ killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+ "Too many Binders sent to SYSTEM");
+ }
+ }
+ }, mHandler);
+
+ traceLog.traceEnd(); // ActivityManagerStartApps
+ traceLog.traceEnd(); // PhaseActivityManagerReady
+ }
+ }
+
+ private void updateForceBackgroundCheck(boolean enabled) {
+ synchronized (this) {
+ if (mForceBackgroundCheck != enabled) {
+ mForceBackgroundCheck = enabled;
+
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Force background check " + (enabled ? "enabled" : "disabled"));
+ }
+
+ if (mForceBackgroundCheck) {
+ // Stop background services for idle UIDs.
+ doStopUidForIdleUidsLocked();
+ }
+ }
}
}
* @param app object of the crashing app, null for the system server
* @param crashInfo describing the exception
*/
- public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
+ public void handleApplicationCrash(IBinder app,
+ ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app, "Crash");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
crashInfo.throwFileName,
crashInfo.throwLineNumber);
+ StatsLog.write(StatsLog.APP_CRASH_OCCURRED,
+ Binder.getCallingUid(),
+ eventType,
+ processName,
+ Binder.getCallingPid(),
+ (r != null && r.info != null) ? r.info.packageName : "",
+ (r != null && r.info != null) ? (r.info.isInstantApp()
+ ? StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE
+ : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE)
+ : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+ r != null ? (r.isInterestingToUserLocked()
+ ? StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND
+ : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND)
+ : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
+ );
+
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
mAppErrors.crashApplication(r, crashInfo);
IBinder app,
int violationMask,
StrictMode.ViolationInfo info) {
- ProcessRecord r = findAppProcess(app, "StrictMode");
- if (r == null) {
- return;
- }
+ // We're okay if the ProcessRecord is missing; it probably means that
+ // we're reporting a violation from the system process itself.
+ final ProcessRecord r = findAppProcess(app, "StrictMode");
if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
(process.info.flags & (ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
final String processName = process == null ? "unknown" : process.processName;
- final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode";
final DropBoxManager dbox = (DropBoxManager)
mContext.getSystemService(Context.DROPBOX_SERVICE);
// Exit early if the dropbox isn't configured to accept this report type.
+ final String dropboxTag = processClass(process) + "_strictmode";
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
- boolean bufferWasEmpty;
- boolean needsFlush;
- final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024);
+ final StringBuilder sb = new StringBuilder(1024);
synchronized (sb) {
- bufferWasEmpty = sb.length() == 0;
appendDropBoxProcessHeaders(process, processName, sb);
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
sb.append("System-App: ").append(isSystemApp).append("\n");
}
}
sb.append("\n");
- if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
- sb.append(info.crashInfo.stackTrace);
- sb.append("\n");
- }
- if (info.message != null) {
- sb.append(info.message);
+ sb.append(info.getStackTrace());
+ sb.append("\n");
+ if (info.getViolationDetails() != null) {
+ sb.append(info.getViolationDetails());
sb.append("\n");
}
-
- // Only buffer up to ~64k. Various logging bits truncate
- // things at 128k.
- needsFlush = (sb.length() > 64 * 1024);
- }
-
- // Flush immediately if the buffer's grown too large, or this
- // is a non-system app. Non-system apps are isolated with a
- // different tag & policy and not batched.
- //
- // Batching is useful during internal testing with
- // StrictMode settings turned up high. Without batching,
- // thousands of separate files could be created on boot.
- if (!isSystemApp || needsFlush) {
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- String report;
- synchronized (sb) {
- report = sb.toString();
- sb.delete(0, sb.length());
- sb.trimToSize();
- }
- if (report.length() != 0) {
- dbox.addText(dropboxTag, report);
- }
- }
- }.start();
- return;
- }
-
- // System app batching:
- if (!bufferWasEmpty) {
- // An existing dropbox-writing thread is outstanding, so
- // we don't need to start it up. The existing thread will
- // catch the buffer appends we just did.
- return;
}
- // Worker thread to both batch writes and to avoid blocking the caller on I/O.
- // (After this point, we shouldn't access AMS internal data structures.)
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- // 5 second sleep to let stacks arrive and be batched together
- try {
- Thread.sleep(5000); // 5 seconds
- } catch (InterruptedException e) {}
-
- String errorReport;
- synchronized (mStrictModeBuffer) {
- errorReport = mStrictModeBuffer.toString();
- if (errorReport.length() == 0) {
- return;
- }
- mStrictModeBuffer.delete(0, mStrictModeBuffer.length());
- mStrictModeBuffer.trimToSize();
- }
- dbox.addText(dropboxTag, errorReport);
- }
- }.start();
+ final String res = sb.toString();
+ IoThread.getHandler().post(() -> {
+ dbox.addText(dropboxTag, res);
+ });
}
/**
* @return true if the process should exit immediately (WTF is fatal)
*/
public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system,
- final ApplicationErrorReport.CrashInfo crashInfo) {
+ final ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final ProcessRecord r = handleApplicationWtfInner(callingUid, callingPid, app, tag,
crashInfo);
- if (r != null && r.pid != Process.myPid() &&
- Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.WTF_IS_FATAL, 0) != 0) {
+ final boolean isFatal = Build.IS_ENG || Settings.Global
+ .getInt(mContext.getContentResolver(), Settings.Global.WTF_IS_FATAL, 0) != 0;
+ final boolean isSystem = (r == null) || r.persistent;
+
+ if (isFatal && !isSystem) {
mAppErrors.crashApplication(r, crashInfo);
return true;
} else {
EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
+ StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName,
+ callingPid);
+
addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);
return r;
// concurrently during execution of this method)
synchronized (this) {
sb.append("Process: ").append(processName).append("\n");
+ sb.append("PID: ").append(process.pid).append("\n");
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
try {
PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId());
if (pi != null) {
- sb.append(" v").append(pi.versionCode);
+ sb.append(" v").append(pi.getLongVersionCode());
if (pi.versionName != null) {
sb.append(" (").append(pi.versionName).append(")");
}
}
sb.append("\n");
}
+ if (process.info.isInstantApp()) {
+ sb.append("Instant-App: true\n");
+ }
}
}
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
- final String dropboxTag = processClass(process) + "_" + eventType;
- final DropBoxManager dbox = (DropBoxManager)
- mContext.getSystemService(Context.DROPBOX_SERVICE);
+ // Bail early if not published yet
+ if (ServiceManager.getService(Context.DROPBOX_SERVICE) == null) return;
+ final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
// Exit early if the dropbox isn't configured to accept this report type.
+ final String dropboxTag = processClass(process) + "_" + eventType;
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
// Rate-limit how often we're willing to do the heavy lifting below to
if (process == null) {
// If process is null, we are being called from some internal code
// and may be about to die -- run this synchronously.
- worker.run();
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try {
+ worker.run();
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
} else {
worker.start();
}
}
static int procStateToImportance(int procState, int memAdj,
- ActivityManager.RunningAppProcessInfo currApp) {
- int imp = ActivityManager.RunningAppProcessInfo.procStateToImportance(procState);
+ ActivityManager.RunningAppProcessInfo currApp,
+ int clientTargetSdk) {
+ int imp = ActivityManager.RunningAppProcessInfo.procStateToImportanceForTargetSdk(
+ procState, clientTargetSdk);
if (imp == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
currApp.lru = memAdj;
} else {
}
private void fillInProcMemInfo(ProcessRecord app,
- ActivityManager.RunningAppProcessInfo outInfo) {
+ ActivityManager.RunningAppProcessInfo outInfo,
+ int clientTargetSdk) {
outInfo.pid = app.pid;
outInfo.uid = app.info.uid;
if (mHeavyWeightProcess == app) {
outInfo.lastTrimLevel = app.trimMemoryLevel;
int adj = app.curAdj;
int procState = app.curProcState;
- outInfo.importance = procStateToImportance(procState, adj, outInfo);
+ outInfo.importance = procStateToImportance(procState, adj, outInfo, clientTargetSdk);
outInfo.importanceReasonCode = app.adjTypeCode;
outInfo.processState = app.curProcState;
}
enforceNotIsolatedCaller("getRunningAppProcesses");
final int callingUid = Binder.getCallingUid();
+ final int clientTargetSdk = mPackageManagerInt.getUidTargetSdkVersion(callingUid);
// Lazy instantiation of list
List<ActivityManager.RunningAppProcessInfo> runList = null;
ActivityManager.RunningAppProcessInfo currApp =
new ActivityManager.RunningAppProcessInfo(app.processName,
app.pid, app.getPackageList());
- fillInProcMemInfo(app, currApp);
+ fillInProcMemInfo(app, currApp, clientTargetSdk);
if (app.adjSource instanceof ProcessRecord) {
currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
currApp.importanceReasonImportance =
}
@Override
- public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) {
+ public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outState) {
+ if (outState == null) {
+ throw new IllegalArgumentException("outState is null");
+ }
enforceNotIsolatedCaller("getMyMemoryState");
+
+ final int callingUid = Binder.getCallingUid();
+ final int clientTargetSdk = mPackageManagerInt.getUidTargetSdkVersion(callingUid);
+
synchronized (this) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(Binder.getCallingPid());
}
- fillInProcMemInfo(proc, outInfo);
+ if (proc != null) {
+ fillInProcMemInfo(proc, outState, clientTargetSdk);
+ }
}
}
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
- FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
(new ActivityManagerShellCommand(this, false)).exec(
- this, in, out, err, args, resultReceiver);
+ this, in, out, err, args, callback, resultReceiver);
+ }
+
+ SleepToken acquireSleepToken(String tag, int displayId) {
+ synchronized (this) {
+ final SleepToken token = mStackSupervisor.createSleepTokenLocked(tag, displayId);
+ updateSleepIfNeededLocked();
+ return token;
+ }
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump ActivityManager from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " without permission "
- + android.Manifest.permission.DUMP);
- return;
- }
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
+ }
+
+ /**
+ * Wrapper function to print out debug data filtered by specified arguments.
+ */
+ private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
boolean dumpAll = false;
boolean dumpClient = false;
boolean dumpCheckin = false;
boolean dumpCheckinFormat = false;
+ boolean dumpNormalPriority = false;
+ boolean dumpVisibleStacksOnly = false;
+ boolean dumpFocusedStackOnly = false;
String dumpPackage = null;
int opti = 0;
dumpAll = true;
} else if ("-c".equals(opt)) {
dumpClient = true;
+ } else if ("-v".equals(opt)) {
+ dumpVisibleStacksOnly = true;
+ } else if ("-f".equals(opt)) {
+ dumpFocusedStackOnly = true;
} else if ("-p".equals(opt)) {
if (opti < args.length) {
dumpPackage = args[opti];
dumpCheckin = dumpCheckinFormat = true;
} else if ("-C".equals(opt)) {
dumpCheckinFormat = true;
+ } else if ("--normal-priority".equals(opt)) {
+ dumpNormalPriority = true;
} else if ("-h".equals(opt)) {
ActivityManagerShellCommand.dumpHelp(pw, true);
return;
}
long origId = Binder.clearCallingIdentity();
- boolean more = false;
- // Is the caller requesting to dump a particular piece of data?
- if (opti < args.length) {
- String cmd = args[opti];
+
+ if (useProto) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ String cmd = opti < args.length ? args[opti] : "";
opti++;
+
if ("activities".equals(cmd) || "a".equals(cmd)) {
+ // output proto is ActivityManagerServiceDumpActivitiesProto
synchronized (this) {
- dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
+ writeActivitiesToProtoLocked(proto);
}
- } else if ("recents".equals(cmd) || "r".equals(cmd)) {
+ } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
+ // output proto is ActivityManagerServiceDumpBroadcastsProto
synchronized (this) {
- dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
+ writeBroadcastsToProtoLocked(proto);
}
- } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
+ } else if ("provider".equals(cmd)) {
String[] newArgs;
String name;
if (opti >= args.length) {
name = null;
newArgs = EMPTY_STRING_ARRAY;
} else {
- dumpPackage = args[opti];
+ name = args[opti];
opti++;
newArgs = new String[args.length - opti];
if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
args.length - opti);
}
+ if (!dumpProviderProto(fd, pw, name, newArgs)) {
+ pw.println("No providers match: " + name);
+ pw.println("Use -h for help.");
+ }
+ } else if ("service".equals(cmd)) {
+ // output proto is ActivityManagerServiceDumpServicesProto
+ mServices.writeToProto(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
+ } else if ("processes".equals(cmd) || "p".equals(cmd)) {
+ if (opti < args.length) {
+ dumpPackage = args[opti];
+ opti++;
+ }
+ // output proto is ProcessProto
synchronized (this) {
- dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage);
+ writeProcessesToProtoLocked(proto, dumpPackage);
}
- } else if ("broadcast-stats".equals(cmd)) {
- String[] newArgs;
- String name;
+ } else {
+ // default option, dump everything, output is ActivityManagerServiceProto
+ synchronized (this) {
+ long activityToken = proto.start(ActivityManagerServiceProto.ACTIVITIES);
+ writeActivitiesToProtoLocked(proto);
+ proto.end(activityToken);
+
+ long broadcastToken = proto.start(ActivityManagerServiceProto.BROADCASTS);
+ writeBroadcastsToProtoLocked(proto);
+ proto.end(broadcastToken);
+
+ long serviceToken = proto.start(ActivityManagerServiceProto.SERVICES);
+ mServices.writeToProto(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
+ proto.end(serviceToken);
+
+ long processToken = proto.start(ActivityManagerServiceProto.PROCESSES);
+ writeProcessesToProtoLocked(proto, dumpPackage);
+ proto.end(processToken);
+ }
+ }
+ proto.flush();
+ Binder.restoreCallingIdentity(origId);
+ return;
+ }
+
+ int dumpAppId = getAppId(dumpPackage);
+ boolean more = false;
+ // Is the caller requesting to dump a particular piece of data?
+ if (opti < args.length) {
+ String cmd = args[opti];
+ opti++;
+ if ("activities".equals(cmd) || "a".equals(cmd)) {
+ synchronized (this) {
+ dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
+ }
+ } else if ("lastanr".equals(cmd)) {
+ synchronized (this) {
+ dumpLastANRLocked(pw);
+ }
+ } else if ("starter".equals(cmd)) {
+ synchronized (this) {
+ dumpActivityStarterLocked(pw, dumpPackage);
+ }
+ } else if ("containers".equals(cmd)) {
+ synchronized (this) {
+ dumpActivityContainersLocked(pw);
+ }
+ } else if ("recents".equals(cmd) || "r".equals(cmd)) {
+ synchronized (this) {
+ if (mRecentTasks != null) {
+ mRecentTasks.dump(pw, true /* dumpAll */, dumpPackage);
+ }
+ }
+ } else if ("binder-proxies".equals(cmd)) {
if (opti >= args.length) {
- name = null;
- newArgs = EMPTY_STRING_ARRAY;
+ dumpBinderProxiesCounts(pw, BinderInternal.nGetBinderProxyPerUidCounts(),
+ "Counts of Binder Proxies held by SYSTEM");
} else {
+ String uid = args[opti];
+ opti++;
+ // Ensure Binder Proxy Count is as up to date as possible
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid)));
+ }
+ } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
+ if (opti < args.length) {
+ dumpPackage = args[opti];
+ opti++;
+ }
+ synchronized (this) {
+ dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage);
+ }
+ } else if ("broadcast-stats".equals(cmd)) {
+ if (opti < args.length) {
dumpPackage = args[opti];
opti++;
- newArgs = new String[args.length - opti];
- if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
- args.length - opti);
}
synchronized (this) {
if (dumpCheckinFormat) {
}
}
} else if ("intents".equals(cmd) || "i".equals(cmd)) {
- String[] newArgs;
- String name;
- if (opti >= args.length) {
- name = null;
- newArgs = EMPTY_STRING_ARRAY;
- } else {
+ if (opti < args.length) {
dumpPackage = args[opti];
opti++;
- newArgs = new String[args.length - opti];
- if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
- args.length - opti);
}
synchronized (this) {
dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage);
}
} else if ("processes".equals(cmd) || "p".equals(cmd)) {
- String[] newArgs;
- String name;
- if (opti >= args.length) {
- name = null;
- newArgs = EMPTY_STRING_ARRAY;
- } else {
+ if (opti < args.length) {
dumpPackage = args[opti];
opti++;
- newArgs = new String[args.length - opti];
- if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
- args.length - opti);
}
synchronized (this) {
- dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage);
+ dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage, dumpAppId);
}
} else if ("oom".equals(cmd) || "o".equals(cmd)) {
synchronized (this) {
synchronized (this) {
dumpAssociationsLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
}
+ } else if ("settings".equals(cmd)) {
+ synchronized (this) {
+ mConstants.dump(pw);
+ }
} else if ("services".equals(cmd) || "s".equals(cmd)) {
if (dumpClient) {
ActiveServices.ServiceDumper dumper;
LockGuard.dump(fd, pw, args);
} else {
// Dumping a single activity?
- if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
+ if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll, dumpVisibleStacksOnly,
+ dumpFocusedStackOnly)) {
ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
- int res = shell.exec(this, null, fd, null, args, new ResultReceiver(null));
+ int res = shell.exec(this, null, fd, null, args, null,
+ new ResultReceiver(null));
if (res < 0) {
pw.println("Bad activity command, or no activities match: " + cmd);
pw.println("Use -h for help.");
} else if (dumpClient) {
ActiveServices.ServiceDumper sdumper;
synchronized (this) {
+ mConstants.dump(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ if (mRecentTasks != null) {
+ mRecentTasks.dump(pw, dumpAll, dumpPackage);
+ }
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpLastANRLocked(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpActivityStarterLocked(pw, dumpPackage);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpActivityContainersLocked(pw);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
}
} else {
synchronized (this) {
+ mConstants.dump(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpRecentsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ if (mRecentTasks != null) {
+ mRecentTasks.dump(pw, dumpAll, dumpPackage);
+ }
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+ dumpLastANRLocked(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpActivityStarterLocked(pw, dumpPackage);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpActivityContainersLocked(pw);
+ // Activities section is dumped as part of the Critical priority dump. Exclude the
+ // section if priority is Normal.
+ if (!dumpNormalPriority){
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+ }
if (mAssociations.size() > 0) {
pw.println();
if (dumpAll) {
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
}
}
Binder.restoreCallingIdentity(origId);
}
+ private void writeActivitiesToProtoLocked(ProtoOutputStream proto) {
+ // The output proto of "activity --proto activities" is ActivityManagerServiceDumpActivitiesProto
+ mStackSupervisor.writeToProto(proto, ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR);
+ }
+
+ private void dumpLastANRLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
+ if (mLastANRState == null) {
+ pw.println(" <no ANR has occurred since boot>");
+ } else {
+ pw.println(mLastANRState);
+ }
+ }
+
+ private void dumpActivityContainersLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
+ mStackSupervisor.dumpChildrenNames(pw, " ");
+ pw.println(" ");
+ }
+
+ private void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
+ pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
+ mActivityStartController.dump(pw, "", dumpPackage);
+ }
+
void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
- pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
+ dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
+ "ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
+ }
+
+ void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, boolean dumpClient, String dumpPackage, String header) {
+ pw.println(header);
boolean printedAnything = mStackSupervisor.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient,
dumpPackage);
boolean needSep = printedAnything;
- boolean printed = ActivityStackSupervisor.printThisActivity(pw, mFocusedActivity,
- dumpPackage, needSep, " mFocusedActivity: ");
+ boolean printed = ActivityStackSupervisor.printThisActivity(pw,
+ mStackSupervisor.getResumedActivityLocked(),
+ dumpPackage, needSep, " ResumedActivity: ");
if (printed) {
printedAnything = true;
needSep = false;
if (needSep) {
pw.println();
}
- needSep = true;
printedAnything = true;
mStackSupervisor.dump(pw, " ");
}
}
}
- void dumpRecentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage) {
- pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
-
- boolean printedAnything = false;
-
- if (mRecentTasks != null && mRecentTasks.size() > 0) {
- boolean printedHeader = false;
-
- final int N = mRecentTasks.size();
- for (int i=0; i<N; i++) {
- TaskRecord tr = mRecentTasks.get(i);
- if (dumpPackage != null) {
- if (tr.realActivity == null ||
- !dumpPackage.equals(tr.realActivity)) {
- continue;
- }
- }
- if (!printedHeader) {
- pw.println(" Recent tasks:");
- printedHeader = true;
- printedAnything = true;
- }
- pw.print(" * Recent #"); pw.print(i); pw.print(": ");
- pw.println(tr);
- if (dumpAll) {
- mRecentTasks.get(i).dump(pw, " ");
- }
- }
- }
-
- if (!printedAnything) {
- pw.println(" (nothing)");
- }
- }
-
void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)");
if (dumpPackage != null) {
IPackageManager pm = AppGlobals.getPackageManager();
try {
- dumpUid = pm.getPackageUid(dumpPackage, MATCH_UNINSTALLED_PACKAGES, 0);
+ dumpUid = pm.getPackageUid(dumpPackage, MATCH_ANY_USER, 0);
} catch (RemoteException e) {
}
}
pw.print(" ");
for (int i=0; i<ass.mStateTimes.length; i++) {
long amt = ass.mStateTimes[i];
- if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) {
amt += now - ass.mLastStateUptime;
}
if (amt != 0) {
i + ActivityManager.MIN_PROCESS_STATE));
pw.print("=");
TimeUtils.formatDuration(amt, pw);
- if (ass.mLastState-ActivityManager.MIN_PROCESS_STATE == i) {
+ if ((ass.mLastState-ActivityManager.MIN_PROCESS_STATE) == i) {
pw.print("*");
}
}
}
}
- boolean dumpUids(PrintWriter pw, String dumpPackage, SparseArray<UidRecord> uids,
- String header, boolean needSep) {
- boolean printed = false;
- int whichAppId = -1;
+ private int getAppId(String dumpPackage) {
if (dumpPackage != null) {
try {
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
dumpPackage, 0);
- whichAppId = UserHandle.getAppId(info.uid);
+ return UserHandle.getAppId(info.uid);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
+ return -1;
+ }
+
+ boolean dumpUids(PrintWriter pw, String dumpPackage, int dumpAppId, SparseArray<UidRecord> uids,
+ String header, boolean needSep) {
+ boolean printed = false;
for (int i=0; i<uids.size(); i++) {
UidRecord uidRec = uids.valueAt(i);
- if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+ if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != dumpAppId) {
continue;
}
if (!printed) {
return printed;
}
+ boolean dumpBinderProxiesCounts(PrintWriter pw, SparseIntArray counts, String header) {
+ if(counts != null) {
+ pw.println(header);
+ for (int i = 0; i < counts.size(); i++) {
+ final int uid = counts.keyAt(i);
+ final int binderCount = counts.valueAt(i);
+ pw.print(" UID ");
+ pw.print(uid);
+ pw.print(", binder count = ");
+ pw.print(binderCount);
+ pw.print(", package(s)= ");
+ final String[] pkgNames = mContext.getPackageManager().getPackagesForUid(uid);
+ if (pkgNames != null) {
+ for (int j = 0; j < pkgNames.length; j++) {
+ pw.print(pkgNames[j]);
+ pw.print("; ");
+ }
+ } else {
+ pw.print("NO PACKAGE NAME FOUND");
+ }
+ pw.println();
+ }
+ pw.println();
+ return true;
+ }
+ return false;
+ }
+
+ @GuardedBy("this")
void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage) {
+ int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
boolean needSep = false;
- boolean printedAnything = false;
int numPers = 0;
pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
if (!needSep) {
pw.println(" All known processes:");
needSep = true;
- printedAnything = true;
}
pw.print(r.persistent ? " *PERS*" : " *APP*");
pw.print(" UID "); pw.print(procs.keyAt(ia));
pw.println();
}
pw.println(" Isolated process list (sorted by uid):");
- printedAnything = true;
printed = true;
needSep = true;
}
- pw.println(String.format("%sIsolated #%2d: %s",
- " ", i, r.toString()));
+ pw.print(" Isolated #"); pw.print(i); pw.print(": ");
+ pw.println(r);
+ }
+ }
+
+ if (mActiveInstrumentation.size() > 0) {
+ boolean printed = false;
+ for (int i=0; i<mActiveInstrumentation.size(); i++) {
+ ActiveInstrumentation ai = mActiveInstrumentation.get(i);
+ if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
+ && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Active instrumentation:");
+ printed = true;
+ needSep = true;
+ }
+ pw.print(" Instrumentation #"); pw.print(i); pw.print(": ");
+ pw.println(ai);
+ ai.dump(pw, " ");
}
}
if (mActiveUids.size() > 0) {
- if (dumpUids(pw, dumpPackage, mActiveUids, "UID states:", needSep)) {
- printedAnything = needSep = true;
+ if (dumpUids(pw, dumpPackage, dumpAppId, mActiveUids, "UID states:", needSep)) {
+ needSep = true;
}
}
- if (mValidateUids.size() > 0) {
- if (dumpUids(pw, dumpPackage, mValidateUids, "UID validation:", needSep)) {
- printedAnything = needSep = true;
+ if (dumpAll) {
+ if (mValidateUids.size() > 0) {
+ if (dumpUids(pw, dumpPackage, dumpAppId, mValidateUids, "UID validation:",
+ needSep)) {
+ needSep = true;
+ }
}
}
pw.println("):");
dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false, dumpPackage);
needSep = true;
- printedAnything = true;
}
if (dumpAll || dumpPackage != null) {
needSep = true;
pw.println(" PID mappings:");
printed = true;
- printedAnything = true;
}
pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
}
}
- if (mForegroundProcesses.size() > 0) {
+ if (mImportantProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
boolean printed = false;
- for (int i=0; i<mForegroundProcesses.size(); i++) {
+ for (int i = 0; i< mImportantProcesses.size(); i++) {
ProcessRecord r = mPidsSelfLocked.get(
- mForegroundProcesses.valueAt(i).pid);
+ mImportantProcesses.valueAt(i).pid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
needSep = true;
pw.println(" Foreground Processes:");
printed = true;
- printedAnything = true;
}
- pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
- pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
+ pw.print(" PID #"); pw.print(mImportantProcesses.keyAt(i));
+ pw.print(": "); pw.println(mImportantProcesses.valueAt(i));
}
}
}
if (mPersistentStartingProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
- printedAnything = true;
pw.println(" Persisent processes that are starting:");
dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
"Starting Norm", "Restarting PERS", dumpPackage);
if (mRemovedProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
- printedAnything = true;
pw.println(" Processes that are being removed:");
dumpProcessList(pw, this, mRemovedProcesses, " ",
"Removed Norm", "Removed PERS", dumpPackage);
if (mProcessesOnHold.size() > 0) {
if (needSep) pw.println();
needSep = true;
- printedAnything = true;
pw.println(" Processes that are on old until the system is ready:");
dumpProcessList(pw, this, mProcessesOnHold, " ",
"OnHold Norm", "OnHold PERS", dumpPackage);
}
- needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
+ needSep = dumpProcessesToGc(pw, needSep, dumpPackage);
needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage);
- if (needSep) {
- printedAnything = true;
- }
if (dumpPackage == null) {
pw.println();
}
pw.println(" mPreviousProcess: " + mPreviousProcess);
}
- if (dumpAll) {
+ if (dumpAll && (mPreviousProcess == null || dumpPackage == null
+ || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
StringBuilder sb = new StringBuilder(128);
sb.append(" mPreviousProcessVisibleTime: ");
TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
}
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
}
+ if (dumpAll && mPendingStarts.size() > 0) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" mPendingStarts: ");
+ for (int i = 0, len = mPendingStarts.size(); i < len; ++i ) {
+ pw.println(" " + mPendingStarts.keyAt(i) + ": " + mPendingStarts.valueAt(i));
+ }
+ }
if (dumpPackage == null) {
- pw.println(" mConfiguration: " + mConfiguration);
+ pw.println(" mGlobalConfiguration: " + getGlobalConfiguration());
+ mStackSupervisor.dumpDisplayConfigs(pw, " ");
}
if (dumpAll) {
- pw.println(" mConfigWillChange: " + getFocusedStack().mConfigWillChange);
+ if (dumpPackage == null) {
+ pw.println(" mConfigWillChange: " + getFocusedStack().mConfigWillChange);
+ }
if (mCompatModePackages.getPackages().size() > 0) {
boolean printed = false;
for (Map.Entry<String, Integer> entry
pw.print(mode); pw.println();
}
}
+ final int NI = mUidObservers.getRegisteredCallbackCount();
+ boolean printed = false;
+ for (int i=0; i<NI; i++) {
+ final UidObserverRegistration reg = (UidObserverRegistration)
+ mUidObservers.getRegisteredCallbackCookie(i);
+ if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
+ if (!printed) {
+ pw.println(" mUidObservers:");
+ printed = true;
+ }
+ pw.print(" "); UserHandle.formatUid(pw, reg.uid);
+ pw.print(" "); pw.print(reg.pkg); pw.print(":");
+ if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) {
+ pw.print(" IDLE");
+ }
+ if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
+ pw.print(" ACT" );
+ }
+ if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) {
+ pw.print(" GONE");
+ }
+ if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
+ pw.print(" STATE");
+ pw.print(" (cut="); pw.print(reg.cutpoint);
+ pw.print(")");
+ }
+ pw.println();
+ if (reg.lastProcStates != null) {
+ final int NJ = reg.lastProcStates.size();
+ for (int j=0; j<NJ; j++) {
+ pw.print(" Last ");
+ UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j));
+ pw.print(": "); pw.println(reg.lastProcStates.valueAt(j));
+ }
+ }
+ }
+ }
+ pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
+ pw.println(" mDeviceIdleExceptIdleWhitelist="
+ + Arrays.toString(mDeviceIdleExceptIdleWhitelist));
+ pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
+ if (mPendingTempWhitelist.size() > 0) {
+ pw.println(" mPendingTempWhitelist:");
+ for (int i = 0; i < mPendingTempWhitelist.size(); i++) {
+ PendingTempWhitelist ptw = mPendingTempWhitelist.valueAt(i);
+ pw.print(" ");
+ UserHandle.formatUid(pw, ptw.targetUid);
+ pw.print(": ");
+ TimeUtils.formatDuration(ptw.duration, pw);
+ pw.print(" ");
+ pw.println(ptw.tag);
+ }
+ }
}
if (dumpPackage == null) {
pw.println(" mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness));
- pw.println(" mSleepTokens=" + mSleepTokens);
- pw.println(" mSleeping=" + mSleeping + " mLockScreenShown="
- + lockScreenShownToString());
+ pw.println(" mSleepTokens=" + mStackSupervisor.mSleepTokens);
+ pw.println(" mSleeping=" + mSleeping);
pw.println(" mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
if (mRunningVoice != null) {
pw.println(" mRunningVoice=" + mRunningVoice);
pw.println(" mVoiceWakeLock" + mVoiceWakeLock);
}
+ pw.println(" mVrController=" + mVrController);
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
pw.println(" mTrackAllocationApp=" + mTrackAllocationApp);
}
}
- if (mProfileApp != null || mProfileProc != null || mProfileFile != null
- || mProfileFd != null) {
+ if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
+ (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
if (needSep) {
pw.println();
needSep = false;
}
pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
- pw.println(" mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
- pw.println(" mSamplingInterval=" + mSamplingInterval + " mAutoStopProfiler="
- + mAutoStopProfiler);
- pw.println(" mProfileType=" + mProfileType);
+ if (mProfilerInfo != null) {
+ pw.println(" mProfileFile=" + mProfilerInfo.profileFile + " mProfileFd=" +
+ mProfilerInfo.profileFd);
+ pw.println(" mSamplingInterval=" + mProfilerInfo.samplingInterval +
+ " mAutoStopProfiler=" + mProfilerInfo.autoStopProfiler +
+ " mStreamingOutput=" + mProfilerInfo.streamingOutput);
+ pw.println(" mProfileType=" + mProfileType);
+ }
}
}
if (mNativeDebuggingApp != null) {
pw.println(" mNativeDebuggingApp=" + mNativeDebuggingApp);
}
}
+ if (mAllowAppSwitchUids.size() > 0) {
+ boolean printed = false;
+ for (int i = 0; i < mAllowAppSwitchUids.size(); i++) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.valueAt(i);
+ for (int j = 0; j < types.size(); j++) {
+ if (dumpPackage == null ||
+ UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ if (!printed) {
+ pw.println(" mAllowAppSwitchUids:");
+ printed = true;
+ }
+ pw.print(" User ");
+ pw.print(mAllowAppSwitchUids.keyAt(i));
+ pw.print(": Type ");
+ pw.print(types.keyAt(j));
+ pw.print(" = ");
+ UserHandle.formatUid(pw, types.valueAt(j).intValue());
+ pw.println();
+ }
+ }
+ }
+ }
if (dumpPackage == null) {
- if (mAlwaysFinishActivities || mLenientBackgroundCheck) {
- pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
- + " mLenientBackgroundCheck=" + mLenientBackgroundCheck);
+ if (mAlwaysFinishActivities) {
+ pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities);
}
if (mController != null) {
pw.println(" mController=" + mController
pw.println(" mBooting=" + mBooting
+ " mCallFinishBooting=" + mCallFinishBooting
+ " mBootAnimationComplete=" + mBootAnimationComplete);
- pw.print(" mLastPowerCheckRealtime=");
- TimeUtils.formatDuration(mLastPowerCheckRealtime, pw);
- pw.println("");
pw.print(" mLastPowerCheckUptime=");
TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
pw.println("");
pw.print(" mLowRamSinceLastIdle=");
TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw);
pw.println();
+ pw.println();
+ pw.print(" mUidChangeDispatchCount=");
+ pw.print(mUidChangeDispatchCount);
+ pw.println();
+
+ pw.println(" Slow UID dispatches:");
+ final int N = mUidObservers.beginBroadcast();
+ for (int i = 0; i < N; i++) {
+ UidObserverRegistration r =
+ (UidObserverRegistration) mUidObservers.getBroadcastCookie(i);
+ pw.print(" ");
+ pw.print(mUidObservers.getBroadcastItem(i).getClass().getTypeName());
+ pw.print(": ");
+ pw.print(r.mSlowDispatchCount);
+ pw.print(" / Max ");
+ pw.print(r.mMaxDispatchTime);
+ pw.println("ms");
+ }
+ mUidObservers.finishBroadcast();
+
+ pw.println();
+ pw.println(" ServiceManager statistics:");
+ ServiceManager.sStatLogger.dump(pw, " ");
+ pw.println();
}
}
+ pw.println(" mForceBackgroundCheck=" + mForceBackgroundCheck);
+ }
- if (!printedAnything) {
- pw.println(" (nothing)");
+ @GuardedBy("this")
+ void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
+ int numPers = 0;
+
+ final int NP = mProcessNames.getMap().size();
+ for (int ip=0; ip<NP; ip++) {
+ SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
+ final int NA = procs.size();
+ for (int ia = 0; ia<NA; ia++) {
+ ProcessRecord r = procs.valueAt(ia);
+ if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS);
+ if (r.persistent) {
+ numPers++;
+ }
+ }
+ }
+
+ for (int i=0; i<mIsolatedProcesses.size(); i++) {
+ ProcessRecord r = mIsolatedProcesses.valueAt(i);
+ if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS);
+ }
+
+ for (int i=0; i<mActiveInstrumentation.size(); i++) {
+ ActiveInstrumentation ai = mActiveInstrumentation.get(i);
+ if (dumpPackage != null && !ai.mClass.getPackageName().equals(dumpPackage)
+ && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
+ continue;
+ }
+ ai.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
+ }
+
+ int whichAppId = getAppId(dumpPackage);
+ for (int i=0; i<mActiveUids.size(); i++) {
+ UidRecord uidRec = mActiveUids.valueAt(i);
+ if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+ continue;
+ }
+ uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
+ }
+
+ for (int i=0; i<mValidateUids.size(); i++) {
+ UidRecord uidRec = mValidateUids.valueAt(i);
+ if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+ continue;
+ }
+ uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
+ }
+
+ if (mLruProcesses.size() > 0) {
+ long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS);
+ int total = mLruProcesses.size();
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.SIZE, total);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT, total-mLruProcessActivityStart);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_SVC_AT, total-mLruProcessServiceStart);
+ writeProcessOomListToProto(proto, ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, this,
+ mLruProcesses,false, dumpPackage);
+ proto.end(lruToken);
+ }
+
+ if (dumpPackage != null) {
+ synchronized (mPidsSelfLocked) {
+ for (int i=0; i<mPidsSelfLocked.size(); i++) {
+ ProcessRecord r = mPidsSelfLocked.valueAt(i);
+ if (!r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PIDS_SELF_LOCKED);
+ }
+ }
+ }
+
+ if (mImportantProcesses.size() > 0) {
+ synchronized (mPidsSelfLocked) {
+ for (int i=0; i<mImportantProcesses.size(); i++) {
+ ImportanceToken it = mImportantProcesses.valueAt(i);
+ ProcessRecord r = mPidsSelfLocked.get(it.pid);
+ if (dumpPackage != null && (r == null
+ || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ it.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.IMPORTANT_PROCS);
+ }
+ }
+ }
+
+ for (int i=0; i<mPersistentStartingProcesses.size(); i++) {
+ ProcessRecord r = mPersistentStartingProcesses.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+ continue;
+ }
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PERSISTENT_STARTING_PROCS);
+ }
+
+ for (int i=0; i<mRemovedProcesses.size(); i++) {
+ ProcessRecord r = mRemovedProcesses.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+ continue;
+ }
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.REMOVED_PROCS);
+ }
+
+ for (int i=0; i<mProcessesOnHold.size(); i++) {
+ ProcessRecord r = mProcessesOnHold.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+ continue;
+ }
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ON_HOLD_PROCS);
+ }
+
+ writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS, dumpPackage);
+ mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS, dumpPackage);
+
+ if (dumpPackage == null) {
+ mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
+ getGlobalConfiguration().writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GLOBAL_CONFIGURATION);
+ proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, getFocusedStack().mConfigWillChange);
+ }
+
+ if (mHomeProcess != null && (dumpPackage == null
+ || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+ mHomeProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
+ }
+
+ if (mPreviousProcess != null && (dumpPackage == null
+ || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+ mPreviousProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
+ }
+
+ if (mHeavyWeightProcess != null && (dumpPackage == null
+ || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) {
+ mHeavyWeightProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
+ }
+
+ for (Map.Entry<String, Integer> entry : mCompatModePackages.getPackages().entrySet()) {
+ String pkg = entry.getKey();
+ int mode = entry.getValue();
+ if (dumpPackage == null || dumpPackage.equals(pkg)) {
+ long compatToken = proto.start(ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE, pkg);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE, mode);
+ proto.end(compatToken);
+ }
+ }
+
+ final int NI = mUidObservers.getRegisteredCallbackCount();
+ for (int i=0; i<NI; i++) {
+ final UidObserverRegistration reg = (UidObserverRegistration)
+ mUidObservers.getRegisteredCallbackCookie(i);
+ if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
+ reg.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
+ }
+ }
+
+ for (int v : mDeviceIdleWhitelist) {
+ proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_WHITELIST, v);
+ }
+
+ for (int v : mDeviceIdleTempWhitelist) {
+ proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_TEMP_WHITELIST, v);
+ }
+
+ if (mPendingTempWhitelist.size() > 0) {
+ for (int i=0; i < mPendingTempWhitelist.size(); i++) {
+ mPendingTempWhitelist.valueAt(i).writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.PENDING_TEMP_WHITELIST);
+ }
+ }
+
+ if (dumpPackage == null) {
+ final long sleepToken = proto.start(ActivityManagerServiceDumpProcessesProto.SLEEP_STATUS);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.WAKEFULNESS,
+ PowerManagerInternal.wakefulnessToProtoEnum(mWakefulness));
+ for (SleepToken st : mStackSupervisor.mSleepTokens) {
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEP_TOKENS, st.toString());
+ }
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEPING, mSleeping);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SHUTTING_DOWN, mShuttingDown);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.TEST_PSS_MODE, mTestPssMode);
+ proto.end(sleepToken);
+
+ if (mRunningVoice != null) {
+ final long vrToken = proto.start(ActivityManagerServiceDumpProcessesProto.RUNNING_VOICE);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Voice.SESSION, mRunningVoice.toString());
+ mVoiceWakeLock.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.Voice.WAKELOCK);
+ proto.end(vrToken);
+ }
+
+ mVrController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER);
+ }
+
+ if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
+ || mOrigWaitForDebugger) {
+ if (dumpPackage == null || dumpPackage.equals(mDebugApp)
+ || dumpPackage.equals(mOrigDebugApp)) {
+ final long debugAppToken = proto.start(ActivityManagerServiceDumpProcessesProto.DEBUG);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.DEBUG_APP, mDebugApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.ORIG_DEBUG_APP, mOrigDebugApp);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.DEBUG_TRANSIENT, mDebugTransient);
+ proto.write(ActivityManagerServiceDumpProcessesProto.DebugApp.ORIG_WAIT_FOR_DEBUGGER, mOrigWaitForDebugger);
+ proto.end(debugAppToken);
+ }
+ }
+
+ if (mCurAppTimeTracker != null) {
+ mCurAppTimeTracker.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER, true);
+ }
+
+ if (mMemWatchProcesses.getMap().size() > 0) {
+ final long token = proto.start(ActivityManagerServiceDumpProcessesProto.MEM_WATCH_PROCESSES);
+ ArrayMap<String, SparseArray<Pair<Long, String>>> procs = mMemWatchProcesses.getMap();
+ for (int i=0; i<procs.size(); i++) {
+ final String proc = procs.keyAt(i);
+ final SparseArray<Pair<Long, String>> uids = procs.valueAt(i);
+ final long ptoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.PROCS);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.NAME, proc);
+ for (int j=0; j<uids.size(); j++) {
+ final long utoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MEM_STATS);
+ Pair<Long, String> val = uids.valueAt(j);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MemStats.UID, uids.keyAt(j));
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MemStats.SIZE,
+ DebugUtils.sizeValueToString(val.first, new StringBuilder()));
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Process.MemStats.REPORT_TO, val.second);
+ proto.end(utoken);
+ }
+ proto.end(ptoken);
+ }
+
+ final long dtoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.DUMP);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PROC_NAME, mMemWatchDumpProcName);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.FILE, mMemWatchDumpFile);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PID, mMemWatchDumpPid);
+ proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.UID, mMemWatchDumpUid);
+ proto.end(dtoken);
+
+ proto.end(token);
+ }
+
+ if (mTrackAllocationApp != null) {
+ if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
+ proto.write(ActivityManagerServiceDumpProcessesProto.TRACK_ALLOCATION_APP, mTrackAllocationApp);
+ }
+ }
+
+ if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
+ (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
+ if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
+ final long token = proto.start(ActivityManagerServiceDumpProcessesProto.PROFILE);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME, mProfileApp);
+ mProfileProc.writeToProto(proto,ActivityManagerServiceDumpProcessesProto.Profile.PROC);
+ if (mProfilerInfo != null) {
+ mProfilerInfo.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.Profile.INFO);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE, mProfileType);
+ }
+ proto.end(token);
+ }
+ }
+
+ if (dumpPackage == null || dumpPackage.equals(mNativeDebuggingApp)) {
+ proto.write(ActivityManagerServiceDumpProcessesProto.NATIVE_DEBUGGING_APP, mNativeDebuggingApp);
+ }
+
+ if (dumpPackage == null) {
+ proto.write(ActivityManagerServiceDumpProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
+ if (mController != null) {
+ final long token = proto.start(ActivityManagerServiceDumpProcessesProto.CONTROLLER);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mController.toString());
+ proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mControllerIsAMonkey);
+ proto.end(token);
+ }
+ proto.write(ActivityManagerServiceDumpProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PROCESSES_READY, mProcessesReady);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SYSTEM_READY, mSystemReady);
+ proto.write(ActivityManagerServiceDumpProcessesProto.BOOTED, mBooted);
+ proto.write(ActivityManagerServiceDumpProcessesProto.FACTORY_TEST, mFactoryTest);
+ proto.write(ActivityManagerServiceDumpProcessesProto.BOOTING, mBooting);
+ proto.write(ActivityManagerServiceDumpProcessesProto.CALL_FINISH_BOOTING, mCallFinishBooting);
+ proto.write(ActivityManagerServiceDumpProcessesProto.BOOT_ANIMATION_COMPLETE, mBootAnimationComplete);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LAST_POWER_CHECK_UPTIME_MS, mLastPowerCheckUptime);
+ mStackSupervisor.mGoingToSleep.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GOING_TO_SLEEP);
+ mStackSupervisor.mLaunchingActivity.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mLruSeq);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
+ proto.write(ActivityManagerServiceDumpProcessesProto.NEW_NUM_SERVICE_PROCS, mNewNumServiceProcs);
+ proto.write(ActivityManagerServiceDumpProcessesProto.ALLOW_LOWER_MEM_LEVEL, mAllowLowerMemLevel);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LAST_MEMORY_LEVEL, mLastMemoryLevel);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LAST_NUM_PROCESSES, mLastNumProcesses);
+ long now = SystemClock.uptimeMillis();
+ ProtoUtils.toDuration(proto, ActivityManagerServiceDumpProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
+ }
+
+ }
+
+ void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
+ if (mProcessesToGc.size() > 0) {
+ long now = SystemClock.uptimeMillis();
+ for (int i=0; i<mProcessesToGc.size(); i++) {
+ ProcessRecord r = mProcessesToGc.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+ continue;
+ }
+ final long token = proto.start(fieldId);
+ r.writeToProto(proto, ProcessToGcProto.PROC);
+ proto.write(ProcessToGcProto.REPORT_LOW_MEMORY, r.reportLowMemory);
+ proto.write(ProcessToGcProto.NOW_UPTIME_MS, now);
+ proto.write(ProcessToGcProto.LAST_GCED_MS, r.lastRequestedGc);
+ proto.write(ProcessToGcProto.LAST_LOW_MEMORY_MS, r.lastLowMemory);
+ proto.end(token);
+ }
}
}
- boolean dumpProcessesToGc(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean needSep, boolean dumpAll, String dumpPackage) {
+ boolean dumpProcessesToGc(PrintWriter pw, boolean needSep, String dumpPackage) {
if (mProcessesToGc.size() > 0) {
boolean printed = false;
long now = SystemClock.uptimeMillis();
needSep = true;
}
- dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null);
+ dumpProcessesToGc(pw, needSep, null);
pw.println();
pw.println(" mHomeProcess: " + mHomeProcess);
return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
}
+ /**
+ * Similar to the dumpProvider, but only dumps the first matching provider.
+ * The provider is responsible for dumping as proto.
+ */
+ protected boolean dumpProviderProto(FileDescriptor fd, PrintWriter pw, String name,
+ String[] args) {
+ return mProviderMap.dumpProviderProto(fd, pw, name, args);
+ }
+
static class ItemMatcher {
ArrayList<ComponentName> components;
ArrayList<String> strings;
* - the cmd arg isn't the flattened component name of an existing activity:
* dump all activity whose component contains the cmd as a substring
* - A hex number of the ActivityRecord object instance.
+ *
+ * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
+ * @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
- int opti, boolean dumpAll) {
+ int opti, boolean dumpAll, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) {
ArrayList<ActivityRecord> activities;
synchronized (this) {
- activities = mStackSupervisor.getDumpActivitiesLocked(name);
+ activities = mStackSupervisor.getDumpActivitiesLocked(name, dumpVisibleStacksOnly,
+ dumpFocusedStackOnly);
}
if (activities.size() <= 0) {
}
needSep = true;
synchronized (this) {
- if (lastTask != r.task) {
- lastTask = r.task;
+ final TaskRecord task = r.getTask();
+ if (lastTask != task) {
+ lastTask = task;
pw.print("TASK "); pw.print(lastTask.affinity);
- pw.print(" id="); pw.println(lastTask.taskId);
+ pw.print(" id="); pw.print(lastTask.taskId);
+ pw.print(" userId="); pw.println(lastTask.userId);
if (dumpAll) {
lastTask.dump(pw, " ");
}
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+ r.app.thread.dumpActivity(tp.getWriteFd(),
r.appToken, innerPrefix, args);
tp.go(fd);
} finally {
}
}
- void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage) {
- boolean needSep = false;
- boolean onlyHistory = false;
- boolean printedAnything = false;
-
- if ("history".equals(dumpPackage)) {
- if (opti < args.length && "-s".equals(args[opti])) {
+ void writeBroadcastsToProtoLocked(ProtoOutputStream proto) {
+ if (mRegisteredReceivers.size() > 0) {
+ Iterator it = mRegisteredReceivers.values().iterator();
+ while (it.hasNext()) {
+ ReceiverList r = (ReceiverList)it.next();
+ r.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_LIST);
+ }
+ }
+ mReceiverResolver.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_RESOLVER);
+ for (BroadcastQueue q : mBroadcastQueues) {
+ q.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
+ }
+ for (int user=0; user<mStickyBroadcasts.size(); user++) {
+ long token = proto.start(ActivityManagerServiceDumpBroadcastsProto.STICKY_BROADCASTS);
+ proto.write(StickyBroadcastProto.USER, mStickyBroadcasts.keyAt(user));
+ for (Map.Entry<String, ArrayList<Intent>> ent
+ : mStickyBroadcasts.valueAt(user).entrySet()) {
+ long actionToken = proto.start(StickyBroadcastProto.ACTIONS);
+ proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey());
+ for (Intent intent : ent.getValue()) {
+ intent.writeToProto(proto, StickyBroadcastProto.StickyAction.INTENTS,
+ false, true, true, false);
+ }
+ proto.end(actionToken);
+ }
+ proto.end(token);
+ }
+
+ long handlerToken = proto.start(ActivityManagerServiceDumpBroadcastsProto.HANDLER);
+ proto.write(ActivityManagerServiceDumpBroadcastsProto.MainHandler.HANDLER, mHandler.toString());
+ mHandler.getLooper().writeToProto(proto,
+ ActivityManagerServiceDumpBroadcastsProto.MainHandler.LOOPER);
+ proto.end(handlerToken);
+ }
+
+ void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage) {
+ boolean needSep = false;
+ boolean onlyHistory = false;
+ boolean printedAnything = false;
+
+ if ("history".equals(dumpPackage)) {
+ if (opti < args.length && "-s".equals(args[opti])) {
dumpAll = false;
}
onlyHistory = true;
}
}
+ @GuardedBy("this")
void dumpPermissionsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
boolean needSep = false;
if (dumpPackage != null) {
try {
dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage,
- MATCH_UNINSTALLED_PACKAGES, 0);
+ MATCH_ANY_USER, 0);
} catch (NameNotFoundException e) {
dumpUid = -1;
}
pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
if (mIntentSenderRecords.size() > 0) {
- Iterator<WeakReference<PendingIntentRecord>> it
+ // Organize these by package name, so they are easier to read.
+ final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
+ final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
+ final Iterator<WeakReference<PendingIntentRecord>> it
= mIntentSenderRecords.values().iterator();
while (it.hasNext()) {
WeakReference<PendingIntentRecord> ref = it.next();
- PendingIntentRecord rec = ref != null ? ref.get(): null;
- if (dumpPackage != null && (rec == null
- || !dumpPackage.equals(rec.key.packageName))) {
+ PendingIntentRecord rec = ref != null ? ref.get() : null;
+ if (rec == null) {
+ weakRefs.add(ref);
continue;
}
+ if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
+ continue;
+ }
+ ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
+ if (list == null) {
+ list = new ArrayList<>();
+ byPackage.put(rec.key.packageName, list);
+ }
+ list.add(rec);
+ }
+ for (int i = 0; i < byPackage.size(); i++) {
+ ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
printed = true;
- if (rec != null) {
- pw.print(" * "); pw.println(rec);
+ pw.print(" * "); pw.print(byPackage.keyAt(i));
+ pw.print(": "); pw.print(intents.size()); pw.println(" items");
+ for (int j = 0; j < intents.size(); j++) {
+ pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
if (dumpAll) {
- rec.dump(pw, " ");
+ intents.get(j).dump(pw, " ");
}
- } else {
- pw.print(" * "); pw.println(ref);
+ }
+ }
+ if (weakRefs.size() > 0) {
+ printed = true;
+ pw.println(" * WEAK REFS:");
+ for (int i = 0; i < weakRefs.size(); i++) {
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
}
}
}
return numPers;
}
- private static final boolean dumpProcessOomList(PrintWriter pw,
- ActivityManagerService service, List<ProcessRecord> origList,
- String prefix, String normalLabel, String persistentLabel,
- boolean inclDetails, String dumpPackage) {
-
+ private static final ArrayList<Pair<ProcessRecord, Integer>>
+ sortProcessOomList(List<ProcessRecord> origList, String dumpPackage) {
ArrayList<Pair<ProcessRecord, Integer>> list
= new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
for (int i=0; i<origList.size(); i++) {
list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i));
}
- if (list.size() <= 0) {
- return false;
- }
-
Comparator<Pair<ProcessRecord, Integer>> comparator
= new Comparator<Pair<ProcessRecord, Integer>>() {
@Override
};
Collections.sort(list, comparator);
+ return list;
+ }
+
+ private static final boolean writeProcessOomListToProto(ProtoOutputStream proto, long fieldId,
+ ActivityManagerService service, List<ProcessRecord> origList,
+ boolean inclDetails, String dumpPackage) {
+ ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
+ if (list.isEmpty()) return false;
+
+ final long curUptime = SystemClock.uptimeMillis();
+
+ for (int i = list.size() - 1; i >= 0; i--) {
+ ProcessRecord r = list.get(i).first;
+ long token = proto.start(fieldId);
+ String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
+ proto.write(ProcessOomProto.PERSISTENT, r.persistent);
+ proto.write(ProcessOomProto.NUM, (origList.size()-1)-list.get(i).second);
+ proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
+ int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN;
+ switch (r.setSchedGroup) {
+ case ProcessList.SCHED_GROUP_BACKGROUND:
+ schedGroup = ProcessOomProto.SCHED_GROUP_BACKGROUND;
+ break;
+ case ProcessList.SCHED_GROUP_DEFAULT:
+ schedGroup = ProcessOomProto.SCHED_GROUP_DEFAULT;
+ break;
+ case ProcessList.SCHED_GROUP_TOP_APP:
+ schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP;
+ break;
+ case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
+ schedGroup = ProcessOomProto.SCHED_GROUP_TOP_APP_BOUND;
+ break;
+ }
+ if (schedGroup != ProcessOomProto.SCHED_GROUP_UNKNOWN) {
+ proto.write(ProcessOomProto.SCHED_GROUP, schedGroup);
+ }
+ if (r.foregroundActivities) {
+ proto.write(ProcessOomProto.ACTIVITIES, true);
+ } else if (r.foregroundServices) {
+ proto.write(ProcessOomProto.SERVICES, true);
+ }
+ proto.write(ProcessOomProto.STATE, ProcessList.makeProcStateProtoEnum(r.curProcState));
+ proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.trimMemoryLevel);
+ r.writeToProto(proto, ProcessOomProto.PROC);
+ proto.write(ProcessOomProto.ADJ_TYPE, r.adjType);
+ if (r.adjSource != null || r.adjTarget != null) {
+ if (r.adjTarget instanceof ComponentName) {
+ ComponentName cn = (ComponentName) r.adjTarget;
+ cn.writeToProto(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME);
+ } else if (r.adjTarget != null) {
+ proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, r.adjTarget.toString());
+ }
+ if (r.adjSource instanceof ProcessRecord) {
+ ProcessRecord p = (ProcessRecord) r.adjSource;
+ p.writeToProto(proto, ProcessOomProto.ADJ_SOURCE_PROC);
+ } else if (r.adjSource != null) {
+ proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, r.adjSource.toString());
+ }
+ }
+ if (inclDetails) {
+ long detailToken = proto.start(ProcessOomProto.DETAIL);
+ proto.write(ProcessOomProto.Detail.MAX_ADJ, r.maxAdj);
+ proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.curRawAdj);
+ proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, r.setRawAdj);
+ proto.write(ProcessOomProto.Detail.CUR_ADJ, r.curAdj);
+ proto.write(ProcessOomProto.Detail.SET_ADJ, r.setAdj);
+ proto.write(ProcessOomProto.Detail.CURRENT_STATE,
+ ProcessList.makeProcStateProtoEnum(r.curProcState));
+ proto.write(ProcessOomProto.Detail.SET_STATE,
+ ProcessList.makeProcStateProtoEnum(r.setProcState));
+ proto.write(ProcessOomProto.Detail.LAST_PSS, DebugUtils.sizeValueToString(
+ r.lastPss*1024, new StringBuilder()));
+ proto.write(ProcessOomProto.Detail.LAST_SWAP_PSS, DebugUtils.sizeValueToString(
+ r.lastSwapPss*1024, new StringBuilder()));
+ proto.write(ProcessOomProto.Detail.LAST_CACHED_PSS, DebugUtils.sizeValueToString(
+ r.lastCachedPss*1024, new StringBuilder()));
+ proto.write(ProcessOomProto.Detail.CACHED, r.cached);
+ proto.write(ProcessOomProto.Detail.EMPTY, r.empty);
+ proto.write(ProcessOomProto.Detail.HAS_ABOVE_CLIENT, r.hasAboveClient);
+
+ if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+ if (r.lastCpuTime != 0) {
+ long uptimeSince = curUptime - service.mLastPowerCheckUptime;
+ long timeUsed = r.curCpuTime - r.lastCpuTime;
+ long cpuTimeToken = proto.start(ProcessOomProto.Detail.SERVICE_RUN_TIME);
+ proto.write(ProcessOomProto.Detail.CpuRunTime.OVER_MS, uptimeSince);
+ proto.write(ProcessOomProto.Detail.CpuRunTime.USED_MS, timeUsed);
+ proto.write(ProcessOomProto.Detail.CpuRunTime.ULTILIZATION,
+ (100.0*timeUsed)/uptimeSince);
+ proto.end(cpuTimeToken);
+ }
+ }
+ proto.end(detailToken);
+ }
+ proto.end(token);
+ }
+
+ return true;
+ }
+
+ private static final boolean dumpProcessOomList(PrintWriter pw,
+ ActivityManagerService service, List<ProcessRecord> origList,
+ String prefix, String normalLabel, String persistentLabel,
+ boolean inclDetails, String dumpPackage) {
+
+ ArrayList<Pair<ProcessRecord, Integer>> list = sortProcessOomList(origList, dumpPackage);
+ if (list.isEmpty()) return false;
- final long curRealtime = SystemClock.elapsedRealtime();
- final long realtimeSince = curRealtime - service.mLastPowerCheckRealtime;
final long curUptime = SystemClock.uptimeMillis();
final long uptimeSince = curUptime - service.mLastPowerCheckUptime;
case ProcessList.SCHED_GROUP_TOP_APP:
schedGroup = 'T';
break;
+ case ProcessList.SCHED_GROUP_RESTRICTED:
+ schedGroup = 'R';
+ break;
default:
schedGroup = '?';
break;
pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
if (r.setProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
- if (r.lastWakeTime != 0) {
- long wtime;
- BatteryStatsImpl stats = service.mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- wtime = stats.getProcessWakeTime(r.info.uid,
- r.pid, curRealtime);
- }
- long timeUsed = wtime - r.lastWakeTime;
- pw.print(prefix);
- pw.print(" ");
- pw.print("keep awake over ");
- TimeUtils.formatDuration(realtimeSince, pw);
- pw.print(" used ");
- TimeUtils.formatDuration(timeUsed, pw);
- pw.print(" (");
- pw.print((timeUsed*100)/realtimeSince);
- pw.println("%)");
- }
if (r.lastCpuTime != 0) {
long timeUsed = r.curCpuTime - r.lastCpuTime;
pw.print(prefix);
}
for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord proc = mLruProcesses.get(i);
- if (proc.pid == pid) {
+ if (proc.pid > 0 && proc.pid == pid) {
procs.add(proc);
} else if (allPkgs && proc.pkgList != null
&& proc.pkgList.containsKey(args[start])) {
try {
TransferPipe tp = new TransferPipe();
try {
- r.thread.dumpGfxInfo(tp.getWriteFd().getFileDescriptor(), args);
+ r.thread.dumpGfxInfo(tp.getWriteFd(), args);
tp.go(fd);
} finally {
tp.kill();
try {
TransferPipe tp = new TransferPipe();
try {
- r.thread.dumpDbInfo(tp.getWriteFd().getFileDescriptor(), args);
+ r.thread.dumpDbInfo(tp.getWriteFd(), args);
tp.go(fd);
} finally {
tp.kill();
}
}
+ private static void sortMemItems(List<MemItem> items) {
+ Collections.sort(items, new Comparator<MemItem>() {
+ @Override
+ public int compare(MemItem lhs, MemItem rhs) {
+ if (lhs.pss < rhs.pss) {
+ return 1;
+ } else if (lhs.pss > rhs.pss) {
+ return -1;
+ }
+ return 0;
+ }
+ });
+ }
+
static final void dumpMemItems(PrintWriter pw, String prefix, String tag,
ArrayList<MemItem> items, boolean sort, boolean isCompact, boolean dumpSwapPss) {
if (sort && !isCompact) {
- Collections.sort(items, new Comparator<MemItem>() {
- @Override
- public int compare(MemItem lhs, MemItem rhs) {
- if (lhs.pss < rhs.pss) {
- return 1;
- } else if (lhs.pss > rhs.pss) {
- return -1;
- }
- return 0;
- }
- });
+ sortMemItems(items);
}
for (int i=0; i<items.size(); i++) {
}
}
+ static final void dumpMemItems(ProtoOutputStream proto, long fieldId, String tag,
+ ArrayList<MemItem> items, boolean sort, boolean dumpSwapPss) {
+ if (sort) {
+ sortMemItems(items);
+ }
+
+ for (int i=0; i<items.size(); i++) {
+ MemItem mi = items.get(i);
+ final long token = proto.start(fieldId);
+
+ proto.write(MemInfoDumpProto.MemItem.TAG, tag);
+ proto.write(MemInfoDumpProto.MemItem.LABEL, mi.shortLabel);
+ proto.write(MemInfoDumpProto.MemItem.IS_PROC, mi.isProc);
+ proto.write(MemInfoDumpProto.MemItem.ID, mi.id);
+ proto.write(MemInfoDumpProto.MemItem.HAS_ACTIVITIES, mi.hasActivities);
+ proto.write(MemInfoDumpProto.MemItem.PSS_KB, mi.pss);
+ if (dumpSwapPss) {
+ proto.write(MemInfoDumpProto.MemItem.SWAP_PSS_KB, mi.swapPss);
+ }
+ if (mi.subitems != null) {
+ dumpMemItems(proto, MemInfoDumpProto.MemItem.SUB_ITEMS, mi.shortLabel, mi.subitems,
+ true, dumpSwapPss);
+ }
+ proto.end(token);
+ }
+ }
+
// These are in KB.
static final long[] DUMP_MEM_BUCKETS = new long[] {
5*1024, 7*1024, 10*1024, 15*1024, 20*1024, 30*1024, 40*1024, 80*1024,
private final long[] getKsmInfo() {
long[] longOut = new long[4];
final int[] SINGLE_LONG_FORMAT = new int[] {
- Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+ PROC_SPACE_TERM| PROC_OUT_LONG
};
long[] longTmp = new long[1];
- Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+ readProcFile("/sys/kernel/mm/ksm/pages_shared",
SINGLE_LONG_FORMAT, null, longTmp, null);
longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
longTmp[0] = 0;
- Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+ readProcFile("/sys/kernel/mm/ksm/pages_sharing",
SINGLE_LONG_FORMAT, null, longTmp, null);
longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
longTmp[0] = 0;
- Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+ readProcFile("/sys/kernel/mm/ksm/pages_unshared",
SINGLE_LONG_FORMAT, null, longTmp, null);
longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
longTmp[0] = 0;
- Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+ readProcFile("/sys/kernel/mm/ksm/pages_volatile",
SINGLE_LONG_FORMAT, null, longTmp, null);
longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
return longOut;
return stringifySize(size * 1024, 1024);
}
- // Update this version number in case you change the 'compact' format
+ // Update this version number if you change the 'compact' format.
private static final int MEMINFO_COMPACT_VERSION = 1;
- final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
- boolean dumpDetails = false;
- boolean dumpFullDetails = false;
- boolean dumpDalvik = false;
- boolean dumpSummaryOnly = false;
- boolean dumpUnreachable = false;
- boolean oomOnly = false;
- boolean isCompact = false;
- boolean localOnly = false;
- boolean packages = false;
- boolean isCheckinRequest = false;
- boolean dumpSwapPss = false;
+ private static class MemoryUsageDumpOptions {
+ boolean dumpDetails;
+ boolean dumpFullDetails;
+ boolean dumpDalvik;
+ boolean dumpSummaryOnly;
+ boolean dumpUnreachable;
+ boolean oomOnly;
+ boolean isCompact;
+ boolean localOnly;
+ boolean packages;
+ boolean isCheckinRequest;
+ boolean dumpSwapPss;
+ boolean dumpProto;
+ }
+
+ final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
+ String[] args, boolean brief, PrintWriter categoryPw, boolean asProto) {
+ MemoryUsageDumpOptions opts = new MemoryUsageDumpOptions();
+ opts.dumpDetails = false;
+ opts.dumpFullDetails = false;
+ opts.dumpDalvik = false;
+ opts.dumpSummaryOnly = false;
+ opts.dumpUnreachable = false;
+ opts.oomOnly = false;
+ opts.isCompact = false;
+ opts.localOnly = false;
+ opts.packages = false;
+ opts.isCheckinRequest = false;
+ opts.dumpSwapPss = false;
+ opts.dumpProto = asProto;
int opti = 0;
while (opti < args.length) {
}
opti++;
if ("-a".equals(opt)) {
- dumpDetails = true;
- dumpFullDetails = true;
- dumpDalvik = true;
- dumpSwapPss = true;
+ opts.dumpDetails = true;
+ opts.dumpFullDetails = true;
+ opts.dumpDalvik = true;
+ opts.dumpSwapPss = true;
} else if ("-d".equals(opt)) {
- dumpDalvik = true;
+ opts.dumpDalvik = true;
} else if ("-c".equals(opt)) {
- isCompact = true;
+ opts.isCompact = true;
} else if ("-s".equals(opt)) {
- dumpDetails = true;
- dumpSummaryOnly = true;
+ opts.dumpDetails = true;
+ opts.dumpSummaryOnly = true;
} else if ("-S".equals(opt)) {
- dumpSwapPss = true;
+ opts.dumpSwapPss = true;
} else if ("--unreachable".equals(opt)) {
- dumpUnreachable = true;
+ opts.dumpUnreachable = true;
} else if ("--oom".equals(opt)) {
- oomOnly = true;
+ opts.oomOnly = true;
} else if ("--local".equals(opt)) {
- localOnly = true;
+ opts.localOnly = true;
} else if ("--package".equals(opt)) {
- packages = true;
+ opts.packages = true;
} else if ("--checkin".equals(opt)) {
- isCheckinRequest = true;
+ opts.isCheckinRequest = true;
+ } else if ("--proto".equals(opt)) {
+ opts.dumpProto = true;
} else if ("-h".equals(opt)) {
pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]");
pw.println(" --package: interpret process arg as package, dumping all");
pw.println(" processes that have loaded that package.");
pw.println(" --checkin: dump data for a checkin");
+ pw.println(" --proto: dump data to proto");
pw.println("If [process] is specified it can be the name or ");
pw.println("pid of a specific process to dump.");
return;
}
}
+ String[] innerArgs = new String[args.length-opti];
+ System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
+
+ ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, opts.packages, args);
+ if (opts.dumpProto) {
+ dumpApplicationMemoryUsage(fd, opts, innerArgs, brief, procs);
+ } else {
+ dumpApplicationMemoryUsage(fd, pw, prefix, opts, innerArgs, brief, procs, categoryPw);
+ }
+ }
+
+ private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
+ MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief,
+ ArrayList<ProcessRecord> procs, PrintWriter categoryPw) {
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
final long[] tmpLong = new long[1];
- ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, packages, args);
if (procs == null) {
// No Java processes. Maybe they want to print a native process.
- if (args != null && args.length > opti
- && args[opti].charAt(0) != '-') {
- ArrayList<ProcessCpuTracker.Stats> nativeProcs
- = new ArrayList<ProcessCpuTracker.Stats>();
- updateCpuStatsNow();
- int findPid = -1;
- try {
- findPid = Integer.parseInt(args[opti]);
- } catch (NumberFormatException e) {
- }
- synchronized (mProcessCpuTracker) {
- final int N = mProcessCpuTracker.countStats();
- for (int i=0; i<N; i++) {
- ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
- if (st.pid == findPid || (st.baseName != null
- && st.baseName.equals(args[opti]))) {
- nativeProcs.add(st);
- }
+ String proc = "N/A";
+ if (innerArgs.length > 0) {
+ proc = innerArgs[0];
+ if (proc.charAt(0) != '-') {
+ ArrayList<ProcessCpuTracker.Stats> nativeProcs
+ = new ArrayList<ProcessCpuTracker.Stats>();
+ updateCpuStatsNow();
+ int findPid = -1;
+ try {
+ findPid = Integer.parseInt(innerArgs[0]);
+ } catch (NumberFormatException e) {
}
- }
- if (nativeProcs.size() > 0) {
- dumpApplicationMemoryUsageHeader(pw, uptime, realtime, isCheckinRequest,
- isCompact);
- Debug.MemoryInfo mi = null;
- for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
- final ProcessCpuTracker.Stats r = nativeProcs.get(i);
- final int pid = r.pid;
- if (!isCheckinRequest && dumpDetails) {
- pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **");
- }
- if (mi == null) {
- mi = new Debug.MemoryInfo();
- }
- if (dumpDetails || (!brief && !oomOnly)) {
- Debug.getMemoryInfo(pid, mi);
- } else {
- mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
- mi.dalvikPrivateDirty = (int)tmpLong[0];
+ synchronized (mProcessCpuTracker) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.pid == findPid || (st.baseName != null
+ && st.baseName.equals(innerArgs[0]))) {
+ nativeProcs.add(st);
+ }
}
- ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, pid, r.baseName, 0, 0, 0, 0, 0, 0);
- if (isCheckinRequest) {
- pw.println();
+ }
+ if (nativeProcs.size() > 0) {
+ dumpApplicationMemoryUsageHeader(pw, uptime, realtime,
+ opts.isCheckinRequest, opts.isCompact);
+ Debug.MemoryInfo mi = null;
+ for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
+ final ProcessCpuTracker.Stats r = nativeProcs.get(i);
+ final int pid = r.pid;
+ if (!opts.isCheckinRequest && opts.dumpDetails) {
+ pw.println("\n** MEMINFO in pid " + pid + " [" + r.baseName + "] **");
+ }
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
+ Debug.getMemoryInfo(pid, mi);
+ } else {
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
+ }
+ ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest,
+ opts.dumpFullDetails, opts.dumpDalvik, opts.dumpSummaryOnly,
+ pid, r.baseName, 0, 0, 0, 0, 0, 0);
+ if (opts.isCheckinRequest) {
+ pw.println();
+ }
}
+ return;
}
- return;
}
}
- pw.println("No process found for: " + args[opti]);
+ pw.println("No process found for: " + proc);
return;
}
- if (!brief && !oomOnly && (procs.size() == 1 || isCheckinRequest || packages)) {
- dumpDetails = true;
+ if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) {
+ opts.dumpDetails = true;
}
- dumpApplicationMemoryUsageHeader(pw, uptime, realtime, isCheckinRequest, isCompact);
-
- String[] innerArgs = new String[args.length-opti];
- System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
+ dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest, opts.isCompact);
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
long nativeSwapPss = 0;
long dalvikPss = 0;
long dalvikSwapPss = 0;
- long[] dalvikSubitemPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ long[] dalvikSubitemPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
- long[] dalvikSubitemSwapPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ long[] dalvikSubitemSwapPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
long otherPss = 0;
long otherSwapPss = 0;
hasActivities = r.activities.size() > 0;
}
if (thread != null) {
- if (!isCheckinRequest && dumpDetails) {
+ if (!opts.isCheckinRequest && opts.dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
}
if (mi == null) {
mi = new Debug.MemoryInfo();
}
- if (dumpDetails || (!brief && !oomOnly)) {
+ final int reportType;
+ final long startTime;
+ final long endTime;
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
+ reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
+ startTime = SystemClock.currentThreadTimeMillis();
Debug.getMemoryInfo(pid, mi);
+ endTime = SystemClock.currentThreadTimeMillis();
hasSwapPss = mi.hasSwappedOutPss;
} else {
+ reportType = ProcessStats.ADD_PSS_EXTERNAL;
+ startTime = SystemClock.currentThreadTimeMillis();
mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
+ endTime = SystemClock.currentThreadTimeMillis();
mi.dalvikPrivateDirty = (int)tmpLong[0];
}
- if (dumpDetails) {
- if (localOnly) {
- ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0);
- if (isCheckinRequest) {
+ if (opts.dumpDetails) {
+ if (opts.localOnly) {
+ ActivityThread.dumpMemInfoTable(pw, mi, opts.isCheckinRequest, opts.dumpFullDetails,
+ opts.dumpDalvik, opts.dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0);
+ if (opts.isCheckinRequest) {
pw.println();
}
} else {
+ pw.flush();
try {
- pw.flush();
- thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
- dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs);
+ TransferPipe tp = new TransferPipe();
+ try {
+ thread.dumpMemInfo(tp.getWriteFd(),
+ mi, opts.isCheckinRequest, opts.dumpFullDetails,
+ opts.dumpDalvik, opts.dumpSummaryOnly, opts.dumpUnreachable, innerArgs);
+ tp.go(fd, opts.dumpUnreachable ? 30000 : 5000);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ if (!opts.isCheckinRequest) {
+ pw.println("Got IoException! " + e);
+ pw.flush();
+ }
} catch (RemoteException e) {
- if (!isCheckinRequest) {
- pw.println("Got RemoteException!");
+ if (!opts.isCheckinRequest) {
+ pw.println("Got RemoteException! " + e);
pw.flush();
}
}
final long myTotalPss = mi.getTotalPss();
final long myTotalUss = mi.getTotalUss();
+ final long myTotalRss = mi.getTotalRss();
final long myTotalSwapPss = mi.getTotalSwappedOutPss();
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
- r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true, r.pkgList);
+ r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
+ reportType, endTime-startTime, r.pkgList);
}
}
- if (!isCheckinRequest && mi != null) {
+ if (!opts.isCheckinRequest && mi != null) {
totalPss += myTotalPss;
totalSwapPss += myTotalSwapPss;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
long nativeProcTotalPss = 0;
- if (!isCheckinRequest && procs.size() > 1 && !packages) {
+ if (!opts.isCheckinRequest && procs.size() > 1 && !opts.packages) {
// If we are showing aggregations, also look for native processes to
// include so that our aggregations are more accurate.
updateCpuStatsNow();
if (mi == null) {
mi = new Debug.MemoryInfo();
}
- if (!brief && !oomOnly) {
+ if (!brief && !opts.oomOnly) {
Debug.getMemoryInfo(st.pid, mi);
} else {
mi.nativePss = (int)Debug.getPss(st.pid, tmpLong, null);
final long myTotalPss = mi.getTotalPss();
final long myTotalSwapPss = mi.getTotalSwappedOutPss();
totalPss += myTotalPss;
+ totalSwapPss += myTotalSwapPss;
nativeProcTotalPss += myTotalPss;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1));
- final MemItem dalvikItem =
- new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, -2);
- if (dalvikSubitemPss.length > 0) {
- dalvikItem.subitems = new ArrayList<MemItem>();
- for (int j=0; j<dalvikSubitemPss.length; j++) {
- final String name = Debug.MemoryInfo.getOtherLabel(
- Debug.MemoryInfo.NUM_OTHER_STATS + j);
- dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
- dalvikSubitemSwapPss[j], j));
- }
- }
- catMems.add(dalvikItem);
+ final int dalvikId = -2;
+ catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikId));
catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j));
}
+ if (dalvikSubitemPss.length > 0) {
+ // Add dalvik subitems.
+ for (MemItem memItem : catMems) {
+ int memItemStart = 0, memItemEnd = 0;
+ if (memItem.id == dalvikId) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DALVIK_OTHER) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DEX) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_ART) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_ART_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_ART_END;
+ } else {
+ continue; // No subitems, continue.
+ }
+ memItem.subitems = new ArrayList<MemItem>();
+ for (int j=memItemStart; j<=memItemEnd; j++) {
+ final String name = Debug.MemoryInfo.getOtherLabel(
+ Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
+ dalvikSubitemSwapPss[j], j));
+ }
+ }
+ }
ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
for (int j=0; j<oomPss.length; j++) {
if (oomPss[j] != 0) {
- String label = isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
+ String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
: DUMP_MEM_OOM_LABEL[j];
MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j],
DUMP_MEM_OOM_ADJ[j]);
}
}
- dumpSwapPss = dumpSwapPss && hasSwapPss && totalSwapPss != 0;
- if (!brief && !oomOnly && !isCompact) {
+ opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && totalSwapPss != 0;
+ if (!brief && !opts.oomOnly && !opts.isCompact) {
pw.println();
pw.println("Total PSS by process:");
- dumpMemItems(pw, " ", "proc", procMems, true, isCompact, dumpSwapPss);
+ dumpMemItems(pw, " ", "proc", procMems, true, opts.isCompact, opts.dumpSwapPss);
pw.println();
}
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.println("Total PSS by OOM adjustment:");
}
- dumpMemItems(pw, " ", "oom", oomMems, false, isCompact, dumpSwapPss);
- if (!brief && !oomOnly) {
+ dumpMemItems(pw, " ", "oom", oomMems, false, opts.isCompact, opts.dumpSwapPss);
+ if (!brief && !opts.oomOnly) {
PrintWriter out = categoryPw != null ? categoryPw : pw;
- if (!isCompact) {
+ if (!opts.isCompact) {
out.println();
out.println("Total PSS by category:");
}
- dumpMemItems(out, " ", "cat", catMems, true, isCompact, dumpSwapPss);
+ dumpMemItems(out, " ", "cat", catMems, true, opts.isCompact, opts.dumpSwapPss);
}
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.println();
}
MemInfoReader memInfo = new MemInfoReader();
}
}
if (!brief) {
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.print("Total RAM: "); pw.print(stringifyKBSize(memInfo.getTotalSizeKb()));
pw.print(" (status ");
switch (mLastMemoryLevel) {
long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss
+ memInfo.getKernelUsedSizeKb())); pw.print(" (");
pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + ");
}
if (!brief) {
if (memInfo.getZramTotalSizeKb() != 0) {
- if (!isCompact) {
+ if (!opts.isCompact) {
pw.print(" ZRAM: ");
pw.print(stringifyKBSize(memInfo.getZramTotalSizeKb()));
pw.print(" physical used for ");
}
}
final long[] ksm = getKsmInfo();
- if (!isCompact) {
+ if (!opts.isCompact) {
if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
|| ksm[KSM_VOLATILE] != 0) {
pw.print(" KSM: "); pw.print(stringifyKBSize(ksm[KSM_SHARING]));
}
}
- private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
- long memtrack, String name) {
- sb.append(" ");
- sb.append(ProcessList.makeOomAdjString(oomAdj));
- sb.append(' ');
- sb.append(ProcessList.makeProcStateString(procState));
- sb.append(' ');
- ProcessList.appendRamKb(sb, pss);
- sb.append(": ");
- sb.append(name);
- if (memtrack > 0) {
- sb.append(" (");
- sb.append(stringifyKBSize(memtrack));
- sb.append(" memtrack)");
- }
- }
+ private final void dumpApplicationMemoryUsage(FileDescriptor fd,
+ MemoryUsageDumpOptions opts, String[] innerArgs, boolean brief,
+ ArrayList<ProcessRecord> procs) {
+ final long uptimeMs = SystemClock.uptimeMillis();
+ final long realtimeMs = SystemClock.elapsedRealtime();
+ final long[] tmpLong = new long[1];
- private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
- appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.memtrack, mi.name);
- sb.append(" (pid ");
- sb.append(mi.pid);
- sb.append(") ");
- sb.append(mi.adjType);
- sb.append('\n');
- if (mi.adjReason != null) {
- sb.append(" ");
- sb.append(mi.adjReason);
- sb.append('\n');
- }
- }
+ if (procs == null) {
+ // No Java processes. Maybe they want to print a native process.
+ String proc = "N/A";
+ if (innerArgs.length > 0) {
+ proc = innerArgs[0];
+ if (proc.charAt(0) != '-') {
+ ArrayList<ProcessCpuTracker.Stats> nativeProcs
+ = new ArrayList<ProcessCpuTracker.Stats>();
+ updateCpuStatsNow();
+ int findPid = -1;
+ try {
+ findPid = Integer.parseInt(innerArgs[0]);
+ } catch (NumberFormatException e) {
+ }
+ synchronized (mProcessCpuTracker) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.pid == findPid || (st.baseName != null
+ && st.baseName.equals(innerArgs[0]))) {
+ nativeProcs.add(st);
+ }
+ }
+ }
+ if (nativeProcs.size() > 0) {
+ ProtoOutputStream proto = new ProtoOutputStream(fd);
- void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
- final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
- infoMap.put(mi.pid, mi);
- }
- updateCpuStatsNow();
- long[] memtrackTmp = new long[1];
- final List<ProcessCpuTracker.Stats> stats;
- // Get a list of Stats that have vsize > 0
- synchronized (mProcessCpuTracker) {
- stats = mProcessCpuTracker.getStats((st) -> {
- return st.vsize > 0;
- });
- }
- final int statsCount = stats.size();
- for (int i = 0; i < statsCount; i++) {
- ProcessCpuTracker.Stats st = stats.get(i);
- long pss = Debug.getPss(st.pid, null, memtrackTmp);
- if (pss > 0) {
- if (infoMap.indexOfKey(st.pid) < 0) {
- ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
- ProcessList.NATIVE_ADJ, -1, "native", null);
- mi.pss = pss;
- mi.memtrack = memtrackTmp[0];
- memInfos.add(mi);
+ proto.write(MemInfoDumpProto.UPTIME_DURATION_MS, uptimeMs);
+ proto.write(MemInfoDumpProto.ELAPSED_REALTIME_MS, realtimeMs);
+ Debug.MemoryInfo mi = null;
+ for (int i = nativeProcs.size() - 1 ; i >= 0 ; i--) {
+ final ProcessCpuTracker.Stats r = nativeProcs.get(i);
+ final int pid = r.pid;
+ final long nToken = proto.start(MemInfoDumpProto.NATIVE_PROCESSES);
+
+ proto.write(MemInfoDumpProto.ProcessMemory.PID, pid);
+ proto.write(MemInfoDumpProto.ProcessMemory.PROCESS_NAME, r.baseName);
+
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
+ Debug.getMemoryInfo(pid, mi);
+ } else {
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
+ }
+ ActivityThread.dumpMemInfoTable(proto, mi, opts.dumpDalvik,
+ opts.dumpSummaryOnly, 0, 0, 0, 0, 0, 0);
+
+ proto.end(nToken);
+ }
+
+ proto.flush();
+ return;
+ }
}
}
+ Log.d(TAG, "No process found for: " + innerArgs[0]);
+ return;
}
- long totalPss = 0;
- long totalMemtrack = 0;
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
- if (mi.pss == 0) {
- mi.pss = Debug.getPss(mi.pid, null, memtrackTmp);
- mi.memtrack = memtrackTmp[0];
+ if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) {
+ opts.dumpDetails = true;
+ }
+
+ ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ proto.write(MemInfoDumpProto.UPTIME_DURATION_MS, uptimeMs);
+ proto.write(MemInfoDumpProto.ELAPSED_REALTIME_MS, realtimeMs);
+
+ ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+ final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
+ long nativePss = 0;
+ long nativeSwapPss = 0;
+ long dalvikPss = 0;
+ long dalvikSwapPss = 0;
+ long[] dalvikSubitemPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ EmptyArray.LONG;
+ long[] dalvikSubitemSwapPss = opts.dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ EmptyArray.LONG;
+ long otherPss = 0;
+ long otherSwapPss = 0;
+ long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+ long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+
+ long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
+ long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
+ ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
+ new ArrayList[DUMP_MEM_OOM_LABEL.length];
+
+ long totalPss = 0;
+ long totalSwapPss = 0;
+ long cachedPss = 0;
+ long cachedSwapPss = 0;
+ boolean hasSwapPss = false;
+
+ Debug.MemoryInfo mi = null;
+ for (int i = procs.size() - 1 ; i >= 0 ; i--) {
+ final ProcessRecord r = procs.get(i);
+ final IApplicationThread thread;
+ final int pid;
+ final int oomAdj;
+ final boolean hasActivities;
+ synchronized (this) {
+ thread = r.thread;
+ pid = r.pid;
+ oomAdj = r.getSetAdjWithServices();
+ hasActivities = r.activities.size() > 0;
+ }
+ if (thread == null) {
+ continue;
+ }
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ final int reportType;
+ final long startTime;
+ final long endTime;
+ if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
+ reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
+ startTime = SystemClock.currentThreadTimeMillis();
+ Debug.getMemoryInfo(pid, mi);
+ endTime = SystemClock.currentThreadTimeMillis();
+ hasSwapPss = mi.hasSwappedOutPss;
+ } else {
+ reportType = ProcessStats.ADD_PSS_EXTERNAL;
+ startTime = SystemClock.currentThreadTimeMillis();
+ mi.dalvikPss = (int) Debug.getPss(pid, tmpLong, null);
+ endTime = SystemClock.currentThreadTimeMillis();
+ mi.dalvikPrivateDirty = (int) tmpLong[0];
+ }
+ if (opts.dumpDetails) {
+ if (opts.localOnly) {
+ final long aToken = proto.start(MemInfoDumpProto.APP_PROCESSES);
+ final long mToken = proto.start(MemInfoDumpProto.AppData.PROCESS_MEMORY);
+ proto.write(MemInfoDumpProto.ProcessMemory.PID, pid);
+ proto.write(MemInfoDumpProto.ProcessMemory.PROCESS_NAME, r.processName);
+ ActivityThread.dumpMemInfoTable(proto, mi, opts.dumpDalvik,
+ opts.dumpSummaryOnly, 0, 0, 0, 0, 0, 0);
+ proto.end(mToken);
+ proto.end(aToken);
+ } else {
+ try {
+ ByteTransferPipe tp = new ByteTransferPipe();
+ try {
+ thread.dumpMemInfoProto(tp.getWriteFd(),
+ mi, opts.dumpFullDetails, opts.dumpDalvik, opts.dumpSummaryOnly,
+ opts.dumpUnreachable, innerArgs);
+ proto.write(MemInfoDumpProto.APP_PROCESSES, tp.get());
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Got IOException!", e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Got RemoteException!", e);
+ }
+ }
+ }
+
+ final long myTotalPss = mi.getTotalPss();
+ final long myTotalUss = mi.getTotalUss();
+ final long myTotalRss = mi.getTotalRss();
+ final long myTotalSwapPss = mi.getTotalSwappedOutPss();
+
+ synchronized (this) {
+ if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
+ // Record this for posterity if the process has been stable.
+ r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
+ reportType, endTime-startTime, r.pkgList);
+ }
+ }
+
+ if (!opts.isCheckinRequest && mi != null) {
+ totalPss += myTotalPss;
+ totalSwapPss += myTotalSwapPss;
+ MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
+ (hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
+ myTotalSwapPss, pid, hasActivities);
+ procMems.add(pssItem);
+ procMemsMap.put(pid, pssItem);
+
+ nativePss += mi.nativePss;
+ nativeSwapPss += mi.nativeSwappedOutPss;
+ dalvikPss += mi.dalvikPss;
+ dalvikSwapPss += mi.dalvikSwappedOutPss;
+ for (int j=0; j<dalvikSubitemPss.length; j++) {
+ dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikSubitemSwapPss[j] +=
+ mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ }
+ otherPss += mi.otherPss;
+ otherSwapPss += mi.otherSwappedOutPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ mem = mi.getOtherSwappedOutPss(j);
+ miscSwapPss[j] += mem;
+ otherSwapPss -= mem;
+ }
+
+ if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ cachedPss += myTotalPss;
+ cachedSwapPss += myTotalSwapPss;
+ }
+
+ for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
+ if (oomIndex == (oomPss.length - 1)
+ || (oomAdj >= DUMP_MEM_OOM_ADJ[oomIndex]
+ && oomAdj < DUMP_MEM_OOM_ADJ[oomIndex + 1])) {
+ oomPss[oomIndex] += myTotalPss;
+ oomSwapPss[oomIndex] += myTotalSwapPss;
+ if (oomProcs[oomIndex] == null) {
+ oomProcs[oomIndex] = new ArrayList<MemItem>();
+ }
+ oomProcs[oomIndex].add(pssItem);
+ break;
+ }
+ }
+ }
+ }
+
+ long nativeProcTotalPss = 0;
+
+ if (procs.size() > 1 && !opts.packages) {
+ // If we are showing aggregations, also look for native processes to
+ // include so that our aggregations are more accurate.
+ updateCpuStatsNow();
+ mi = null;
+ synchronized (mProcessCpuTracker) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (!brief && !opts.oomOnly) {
+ Debug.getMemoryInfo(st.pid, mi);
+ } else {
+ mi.nativePss = (int)Debug.getPss(st.pid, tmpLong, null);
+ mi.nativePrivateDirty = (int)tmpLong[0];
+ }
+
+ final long myTotalPss = mi.getTotalPss();
+ final long myTotalSwapPss = mi.getTotalSwappedOutPss();
+ totalPss += myTotalPss;
+ nativeProcTotalPss += myTotalPss;
+
+ MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
+ st.name, myTotalPss, mi.getSummaryTotalSwapPss(), st.pid, false);
+ procMems.add(pssItem);
+
+ nativePss += mi.nativePss;
+ nativeSwapPss += mi.nativeSwappedOutPss;
+ dalvikPss += mi.dalvikPss;
+ dalvikSwapPss += mi.dalvikSwappedOutPss;
+ for (int j=0; j<dalvikSubitemPss.length; j++) {
+ dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikSubitemSwapPss[j] +=
+ mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ }
+ otherPss += mi.otherPss;
+ otherSwapPss += mi.otherSwappedOutPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ mem = mi.getOtherSwappedOutPss(j);
+ miscSwapPss[j] += mem;
+ otherSwapPss -= mem;
+ }
+ oomPss[0] += myTotalPss;
+ oomSwapPss[0] += myTotalSwapPss;
+ if (oomProcs[0] == null) {
+ oomProcs[0] = new ArrayList<MemItem>();
+ }
+ oomProcs[0].add(pssItem);
+ }
+ }
+ }
+
+ ArrayList<MemItem> catMems = new ArrayList<MemItem>();
+
+ catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1));
+ final int dalvikId = -2;
+ catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, dalvikId));
+ catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3));
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ String label = Debug.MemoryInfo.getOtherLabel(j);
+ catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j));
+ }
+ if (dalvikSubitemPss.length > 0) {
+ // Add dalvik subitems.
+ for (MemItem memItem : catMems) {
+ int memItemStart = 0, memItemEnd = 0;
+ if (memItem.id == dalvikId) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DALVIK_OTHER) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DALVIK_OTHER_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_DEX) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_DEX_END;
+ } else if (memItem.id == Debug.MemoryInfo.OTHER_ART) {
+ memItemStart = Debug.MemoryInfo.OTHER_DVK_STAT_ART_START;
+ memItemEnd = Debug.MemoryInfo.OTHER_DVK_STAT_ART_END;
+ } else {
+ continue; // No subitems, continue.
+ }
+ memItem.subitems = new ArrayList<MemItem>();
+ for (int j=memItemStart; j<=memItemEnd; j++) {
+ final String name = Debug.MemoryInfo.getOtherLabel(
+ Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ memItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
+ dalvikSubitemSwapPss[j], j));
+ }
+ }
+ }
+
+ ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
+ for (int j=0; j<oomPss.length; j++) {
+ if (oomPss[j] != 0) {
+ String label = opts.isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
+ : DUMP_MEM_OOM_LABEL[j];
+ MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j],
+ DUMP_MEM_OOM_ADJ[j]);
+ item.subitems = oomProcs[j];
+ oomMems.add(item);
+ }
+ }
+
+ opts.dumpSwapPss = opts.dumpSwapPss && hasSwapPss && totalSwapPss != 0;
+ if (!opts.oomOnly) {
+ dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_PROCESS, "proc",
+ procMems, true, opts.dumpSwapPss);
+ }
+ dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_OOM_ADJUSTMENT, "oom",
+ oomMems, false, opts.dumpSwapPss);
+ if (!brief && !opts.oomOnly) {
+ dumpMemItems(proto, MemInfoDumpProto.TOTAL_PSS_BY_CATEGORY, "cat",
+ catMems, true, opts.dumpSwapPss);
+ }
+ MemInfoReader memInfo = new MemInfoReader();
+ memInfo.readMemInfo();
+ if (nativeProcTotalPss > 0) {
+ synchronized (this) {
+ final long cachedKb = memInfo.getCachedSizeKb();
+ final long freeKb = memInfo.getFreeSizeKb();
+ final long zramKb = memInfo.getZramTotalSizeKb();
+ final long kernelKb = memInfo.getKernelUsedSizeKb();
+ EventLogTags.writeAmMeminfo(cachedKb*1024, freeKb*1024, zramKb*1024,
+ kernelKb*1024, nativeProcTotalPss*1024);
+ mProcessStats.addSysMemUsageLocked(cachedKb, freeKb, zramKb, kernelKb,
+ nativeProcTotalPss);
+ }
+ }
+ if (!brief) {
+ proto.write(MemInfoDumpProto.TOTAL_RAM_KB, memInfo.getTotalSizeKb());
+ proto.write(MemInfoDumpProto.STATUS, mLastMemoryLevel);
+ proto.write(MemInfoDumpProto.CACHED_PSS_KB, cachedPss);
+ proto.write(MemInfoDumpProto.CACHED_KERNEL_KB, memInfo.getCachedSizeKb());
+ proto.write(MemInfoDumpProto.FREE_KB, memInfo.getFreeSizeKb());
+ }
+ long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
+ - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+ - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
+ proto.write(MemInfoDumpProto.USED_PSS_KB, totalPss - cachedPss);
+ proto.write(MemInfoDumpProto.USED_KERNEL_KB, memInfo.getKernelUsedSizeKb());
+ proto.write(MemInfoDumpProto.LOST_RAM_KB, lostRAM);
+ if (!brief) {
+ if (memInfo.getZramTotalSizeKb() != 0) {
+ proto.write(MemInfoDumpProto.TOTAL_ZRAM_KB, memInfo.getZramTotalSizeKb());
+ proto.write(MemInfoDumpProto.ZRAM_PHYSICAL_USED_IN_SWAP_KB,
+ memInfo.getSwapTotalSizeKb() - memInfo.getSwapFreeSizeKb());
+ proto.write(MemInfoDumpProto.TOTAL_ZRAM_SWAP_KB, memInfo.getSwapTotalSizeKb());
+ }
+ final long[] ksm = getKsmInfo();
+ proto.write(MemInfoDumpProto.KSM_SHARING_KB, ksm[KSM_SHARING]);
+ proto.write(MemInfoDumpProto.KSM_SHARED_KB, ksm[KSM_SHARED]);
+ proto.write(MemInfoDumpProto.KSM_UNSHARED_KB, ksm[KSM_UNSHARED]);
+ proto.write(MemInfoDumpProto.KSM_VOLATILE_KB, ksm[KSM_VOLATILE]);
+
+ proto.write(MemInfoDumpProto.TUNING_MB, ActivityManager.staticGetMemoryClass());
+ proto.write(MemInfoDumpProto.TUNING_LARGE_MB, ActivityManager.staticGetLargeMemoryClass());
+ proto.write(MemInfoDumpProto.OOM_KB,
+ mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ) / 1024);
+ proto.write(MemInfoDumpProto.RESTORE_LIMIT_KB,
+ mProcessList.getCachedRestoreThresholdKb());
+
+ proto.write(MemInfoDumpProto.IS_LOW_RAM_DEVICE, ActivityManager.isLowRamDeviceStatic());
+ proto.write(MemInfoDumpProto.IS_HIGH_END_GFX, ActivityManager.isHighEndGfx());
+ }
+ }
+
+ proto.flush();
+ }
+
+ private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
+ long memtrack, String name) {
+ sb.append(" ");
+ sb.append(ProcessList.makeOomAdjString(oomAdj));
+ sb.append(' ');
+ sb.append(ProcessList.makeProcStateString(procState));
+ sb.append(' ');
+ ProcessList.appendRamKb(sb, pss);
+ sb.append(": ");
+ sb.append(name);
+ if (memtrack > 0) {
+ sb.append(" (");
+ sb.append(stringifyKBSize(memtrack));
+ sb.append(" memtrack)");
+ }
+ }
+
+ private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
+ appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.memtrack, mi.name);
+ sb.append(" (pid ");
+ sb.append(mi.pid);
+ sb.append(") ");
+ sb.append(mi.adjType);
+ sb.append('\n');
+ if (mi.adjReason != null) {
+ sb.append(" ");
+ sb.append(mi.adjReason);
+ sb.append('\n');
+ }
+ }
+
+ void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
+ final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ infoMap.put(mi.pid, mi);
+ }
+ updateCpuStatsNow();
+ long[] memtrackTmp = new long[1];
+ final List<ProcessCpuTracker.Stats> stats;
+ // Get a list of Stats that have vsize > 0
+ synchronized (mProcessCpuTracker) {
+ stats = mProcessCpuTracker.getStats((st) -> {
+ return st.vsize > 0;
+ });
+ }
+ final int statsCount = stats.size();
+ for (int i = 0; i < statsCount; i++) {
+ ProcessCpuTracker.Stats st = stats.get(i);
+ long pss = Debug.getPss(st.pid, null, memtrackTmp);
+ if (pss > 0) {
+ if (infoMap.indexOfKey(st.pid) < 0) {
+ ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+ ProcessList.NATIVE_ADJ, -1, "native", null);
+ mi.pss = pss;
+ mi.memtrack = memtrackTmp[0];
+ memInfos.add(mi);
+ }
+ }
+ }
+
+ long totalPss = 0;
+ long totalMemtrack = 0;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ if (mi.pss == 0) {
+ mi.pss = Debug.getPss(mi.pid, null, memtrackTmp);
+ mi.memtrack = memtrackTmp[0];
}
totalPss += mi.pss;
totalMemtrack += mi.memtrack;
PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
String[] emptyArgs = new String[] { };
catPw.println();
- dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
+ dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null, -1);
catPw.println();
mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0,
false, null).dumpLocked();
catPw.flush();
}
dropBuilder.append(catSw.toString());
+ StatsLog.write(StatsLog.LOW_MEM_REPORTED);
addErrorToDropBox("lowmem", null, "system_server", null,
null, tag.toString(), dropBuilder.toString(), null, null);
//Slog.i(TAG, "Sent to dropbox:");
* @return Returns true if the given process has been restarted, so the
* app that was passed in must remain on the process lists.
*/
+ @GuardedBy("this")
private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
- Slog.d(TAG, "cleanUpApplicationRecord -- " + app.pid);
if (index >= 0) {
removeLruProcessLocked(app);
ProcessList.remove(app.pid);
mProcessesToGc.remove(app);
mPendingPssProcesses.remove(app);
+ ProcessList.abortNextPssTime(app.procStateMemTracker);
// Dismiss any open dialogs.
if (app.crashDialog != null && !app.forceCrashReport) {
app.unlinkDeathRecipient();
app.makeInactive(mProcessStats);
app.waitingToKill = null;
- app.forcingToForeground = null;
+ app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.foregroundActivities = false;
app.hasShownUi = false;
if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
+ mBackupTarget.appInfo + " died during backup");
- try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnected(app.info.packageName);
- } catch (RemoteException e) {
- // can't happen; backup manager is local
- }
- }
-
+ mHandler.post(new Runnable() {
+ @Override
+ public void run(){
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentDisconnected(app.info.packageName);
+ } catch (RemoteException e) {
+ // can't happen; backup manager is local
+ }
+ }
+ });
+ }
+
for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
ProcessChangeItem item = mPendingProcessChanges.get(i);
- if (item.pid == app.pid) {
+ if (app.pid > 0 && item.pid == app.pid) {
mPendingProcessChanges.remove(i);
mAvailProcessChanges.add(item);
}
ProcessList.remove(app.pid);
}
addProcessNameLocked(app);
+ app.pendingStart = false;
startProcessLocked(app, "restart", app.processName);
return true;
} else if (app.pid > 0 && app.pid != MY_PID) {
// =========================================================
@Override
- public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
- int flags) {
+ public List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags) {
enforceNotIsolatedCaller("getServices");
+
+ final int callingUid = Binder.getCallingUid();
+ final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
+ INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
+ final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
+ callingUid);
synchronized (this) {
- return mServices.getRunningServiceInfoLocked(maxNum, flags);
+ return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
+ allowed, canInteractAcrossUsers);
}
}
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, String callingPackage, int userId)
+ String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
- "startService: " + service + " type=" + resolvedType);
+ "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
- ComponentName res = mServices.startServiceLocked(caller, service,
- resolvedType, callingPid, callingUid, callingPackage, userId);
- Binder.restoreCallingIdentity(origId);
+ ComponentName res;
+ try {
+ res = mServices.startServiceLocked(caller, service,
+ resolvedType, callingPid, callingUid,
+ requireForeground, callingPackage, userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
return res;
}
}
ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
- String callingPackage, int userId)
+ boolean fgRequired, String callingPackage, int userId)
throws TransactionTooLargeException {
synchronized(this) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startServiceInPackage: " + service + " type=" + resolvedType);
final long origId = Binder.clearCallingIdentity();
- ComponentName res = mServices.startServiceLocked(null, service,
- resolvedType, -1, uid, callingPackage, userId);
- Binder.restoreCallingIdentity(origId);
+ ComponentName res;
+ try {
+ res = mServices.startServiceLocked(null, service,
+ resolvedType, -1, uid, fgRequired, callingPackage, userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
return res;
}
}
String className, int flags) {
boolean result = false;
// For apps that don't have pre-defined UIDs, check for permission
- if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
+ if (UserHandle.getAppId(aInfo.uid) >= FIRST_APPLICATION_UID) {
if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
if (ActivityManager.checkUidPermission(
INTERACT_ACROSS_USERS,
result = true;
} else if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
// Phone app and persistent apps are allowed to export singleuser providers.
- result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID)
+ result = UserHandle.isSameApp(aInfo.uid, PHONE_UID)
|| (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
}
if (DEBUG_MU) Slog.v(TAG_MU,
boolean isValidSingletonCall(int callingUid, int componentUid) {
int componentAppId = UserHandle.getAppId(componentUid);
return UserHandle.isSameApp(callingUid, componentUid)
- || componentAppId == Process.SYSTEM_UID
- || componentAppId == Process.PHONE_UID
+ || componentAppId == SYSTEM_UID
+ || componentAppId == PHONE_UID
|| ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, componentUid)
== PackageManager.PERMISSION_GRANTED;
}
IPackageManager pm = AppGlobals.getPackageManager();
ApplicationInfo app = null;
try {
- app = pm.getApplicationInfo(packageName, 0, userId);
+ app = pm.getApplicationInfo(packageName, STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
// can't happen; package manager is process-local
}
return false;
}
+ int oldBackupUid;
+ int newBackupUid;
+
synchronized(this) {
// !!! TODO: currently no check here that we're already bound
BatteryStatsImpl.Uid.Pkg.Serv ss = null;
}
BackupRecord r = new BackupRecord(ss, app, backupMode);
- ComponentName hostingName = (backupMode == IApplicationThread.BACKUP_MODE_INCREMENTAL)
- ? new ComponentName(app.packageName, app.backupAgentName)
- : new ComponentName("android", "FullBackupAgent");
+ ComponentName hostingName =
+ (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL)
+ ? new ComponentName(app.packageName, app.backupAgentName)
+ : new ComponentName("android", "FullBackupAgent");
// startProcessLocked() returns existing proc's record if it's already running
ProcessRecord proc = startProcessLocked(app.processName, app,
false, 0, "backup", hostingName, false, false, false);
// process, etc, then mark it as being in full backup so that certain calls to the
// process can be blocked. This is not reset to false anywhere because we kill the
// process after the full backup is done and the ProcessRecord will vaporize anyway.
- if (UserHandle.isApp(app.uid) && backupMode == IApplicationThread.BACKUP_MODE_FULL) {
+ if (UserHandle.isApp(app.uid) &&
+ backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL) {
proc.inFullBackup = true;
}
r.app = proc;
+ oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+ newBackupUid = proc.inFullBackup ? r.appInfo.uid : -1;
mBackupTarget = r;
mBackupAppName = app.packageName;
// Try not to kill the process during backup
- updateOomAdjLocked(proc);
+ updateOomAdjLocked(proc, true);
// If the process is already attached, schedule the creation of the backup agent now.
// If it is not yet live, this will be done when it attaches to the framework.
// know that it's scheduled for a backup-agent operation.
}
+ JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
+ if (oldBackupUid != -1) {
+ js.removeBackingUpUid(oldBackupUid);
+ }
+ if (newBackupUid != -1) {
+ js.addBackingUpUid(newBackupUid);
+ }
+
return true;
}
mBackupTarget = null;
mBackupAppName = null;
}
+
+ JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
+ js.clearAllBackingUpUids();
}
// A backup agent has just come up
return;
}
+ int oldBackupUid;
+
synchronized(this) {
try {
if (mBackupAppName == null) {
// Not backing this app up any more; reset its OOM adjustment
final ProcessRecord proc = mBackupTarget.app;
- updateOomAdjLocked(proc);
+ updateOomAdjLocked(proc, true);
+ proc.inFullBackup = false;
+
+ oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
// If the app crashed during backup, 'thread' will be null here
if (proc.thread != null) {
mBackupAppName = null;
}
}
+
+ if (oldBackupUid != -1) {
+ JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
+ js.removeBackingUpUid(oldBackupUid);
+ }
}
+
// =========================================================
// BROADCASTS
// =========================================================
+ private boolean isInstantApp(ProcessRecord record, @Nullable String callerPackage, int uid) {
+ if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
+ return false;
+ }
+ // Easy case -- we have the app's ProcessRecord.
+ if (record != null) {
+ return record.info.isInstantApp();
+ }
+ // Otherwise check with PackageManager.
+ IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ if (callerPackage == null) {
+ final String[] packageNames = pm.getPackagesForUid(uid);
+ if (packageNames == null || packageNames.length == 0) {
+ throw new IllegalArgumentException("Unable to determine caller package name");
+ }
+ // Instant Apps can't use shared uids, so its safe to only check the first package.
+ callerPackage = packageNames[0];
+ }
+ mAppOpsService.checkPackage(uid, callerPackage);
+ return pm.isInstantApp(callerPackage, UserHandle.getUserId(uid));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error looking up if " + callerPackage + " is an instant app.", e);
+ return true;
+ }
+ }
+
boolean isPendingBroadcastProcessLocked(int pid) {
return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
|| mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
}
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
- IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
+ IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
+ int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
+ final boolean visibleToInstantApps
+ = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
int callingUid;
int callingPid;
+ boolean instantApp;
synchronized(this) {
if (caller != null) {
callerApp = getRecordForAppLocked(caller);
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
- if (callerApp.info.uid != Process.SYSTEM_UID &&
+ if (callerApp.info.uid != SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage)) {
throw new SecurityException("Given caller package " + callerPackage
callingPid = Binder.getCallingPid();
}
+ instantApp = isInstantApp(callerApp, callerPackage, callingUid);
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
+ // Don't provided intents that aren't available to instant apps.
+ if (instantApp &&
+ (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
+ continue;
+ }
// If intent has scheme "content", it will need to acccess
// provider that needs to lock mProviderMap in ActivityThread
// and also it may need to wait application response, so we
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
+ final int totalReceiversForApp = rl.app.receivers.size();
+ if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
+ throw new IllegalStateException("Too many receivers, total of "
+ + totalReceiversForApp + ", registered for pid: "
+ + rl.pid + ", callerPackage: " + callerPackage);
+ }
rl.app.receivers.add(rl);
} else {
try {
} else if (rl.uid != callingUid) {
throw new IllegalArgumentException(
"Receiver requested to register for uid " + callingUid
- + " was previously registered for uid " + rl.uid);
+ + " was previously registered for uid " + rl.uid
+ + " callerPackage is " + callerPackage);
} else if (rl.pid != callingPid) {
throw new IllegalArgumentException(
"Receiver requested to register for pid " + callingPid
- + " was previously registered for pid " + rl.pid);
+ + " was previously registered for pid " + rl.pid
+ + " callerPackage is " + callerPackage);
} else if (rl.userId != userId) {
throw new IllegalArgumentException(
"Receiver requested to register for user " + userId
- + " was previously registered for user " + rl.userId);
+ + " was previously registered for user " + rl.userId
+ + " callerPackage is " + callerPackage);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
- permission, callingUid, userId);
- rl.add(bf);
- if (!bf.debugCheck()) {
- Slog.w(TAG, "==> For Dynamic broadcast");
+ permission, callingUid, userId, instantApp, visibleToInstantApps);
+ if (rl.containsFilter(filter)) {
+ Slog.w(TAG, "Receiver with filter " + filter
+ + " already registered for pid " + rl.pid
+ + ", callerPackage is " + callerPackage);
+ } else {
+ rl.add(bf);
+ if (!bf.debugCheck()) {
+ Slog.w(TAG, "==> For Dynamic broadcast");
+ }
+ mReceiverResolver.addFilter(bf);
}
- mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
+ null, -1, -1, false, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
for (int user : users) {
// Skip users that have Shell restrictions, with exception of always permitted
// Shell broadcasts
- if (callingUid == Process.SHELL_UID
+ if (callingUid == SHELL_UID
&& mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, user)
&& !isPermittedShellBroadcast(intent)) {
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
+ if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
+ // Don't yell about broadcasts sent via shell
+ return;
+ }
+
final String action = intent.getAction();
if (isProtectedBroadcast
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
|| Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
|| Intent.ACTION_MASTER_CLEAR.equals(action)
+ || Intent.ACTION_FACTORY_RESET.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
|| LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
|| TelephonyIntents.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
- || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)) {
+ || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
+ || AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
+ || AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
// Broadcast is either protected, or it's a public action that
// we've relaxed, so it's fine for system internals to send.
return;
// explicitly list each action as a protected broadcast, so we will check for that
// one safe case and allow it: an explicit broadcast, only being received by something
// that has protected itself.
- if (receivers != null && receivers.size() > 0
- && (intent.getPackage() != null || intent.getComponent() != null)) {
+ if (intent.getPackage() != null || intent.getComponent() != null) {
+ if (receivers == null || receivers.size() == 0) {
+ // Intent is explicit and there's no receivers.
+ // This happens, e.g. , when a system component sends a broadcast to
+ // its own runtime receiver, and there's no manifest receivers for it,
+ // because this method is called twice for each broadcast,
+ // for runtime receivers and manifest receivers and the later check would find
+ // no receivers.
+ return;
+ }
boolean allProtected = true;
for (int i = receivers.size()-1; i >= 0; i--) {
Object target = receivers.get(i);
}
}
+ @GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
intent = new Intent(intent);
+ final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
+ // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
+ if (callerInstantApp) {
+ intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ }
+
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_NON_FULL, "broadcast", callerPackage);
- // Make sure that the user who is receiving this broadcast is running.
- // If not, we will just skip it. Make an exception for shutdown broadcasts
- // and upgrade steps.
-
- if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
- if ((callingUid != Process.SYSTEM_UID
+ // Make sure that the user who is receiving this broadcast or its parent is running.
+ // If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.
+ if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
+ if ((callingUid != SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
- + ": user " + userId + " is stopped");
+ + ": user " + userId + " and its parent (if any) are stopped");
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
+ final String action = intent.getAction();
BroadcastOptions brOptions = null;
if (bOptions != null) {
brOptions = new BroadcastOptions(bOptions);
throw new SecurityException(msg);
}
}
+ if (brOptions.isDontSendToRestrictedApps()
+ && !isUidActiveLocked(callingUid)
+ && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
+ Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage
+ + " has background restrictions");
+ return ActivityManager.START_CANCELED;
+ }
}
// Verify that protected broadcasts are only being sent by system code,
// and that system code is only sending protected broadcasts.
- final String action = intent.getAction();
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
- case Process.ROOT_UID:
- case Process.SYSTEM_UID:
- case Process.PHONE_UID:
- case Process.BLUETOOTH_UID:
- case Process.NFC_UID:
+ case ROOT_UID:
+ case SYSTEM_UID:
+ case PHONE_UID:
+ case BLUETOOTH_UID:
+ case NFC_UID:
+ case SE_UID:
isCallerSystem = true;
break;
default:
}
if (action != null) {
+ if (getBackgroundLaunchBroadcasts().contains(action)) {
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
+ }
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ }
+
switch (action) {
case Intent.ACTION_UID_REMOVED:
case Intent.ACTION_PACKAGE_REMOVED:
}
switch (action) {
case Intent.ACTION_UID_REMOVED:
- final Bundle intentExtras = intent.getExtras();
- final int uid = intentExtras != null
- ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
+ final int uid = getUidFromIntent(intent);
if (uid >= 0) {
mBatteryStatsService.removeUid(uid);
mAppOpsService.uidRemoved(uid);
}
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
sendPackageBroadcastLocked(
- IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
- userId);
+ ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,
+ list, userId);
}
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
removed ? "pkg removed" : "pkg changed");
}
final int cmd = killProcess
- ? IApplicationThread.PACKAGE_REMOVED
- : IApplicationThread.PACKAGE_REMOVED_DONT_KILL;
+ ? ApplicationThreadConstants.PACKAGE_REMOVED
+ : ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;
sendPackageBroadcastLocked(cmd,
new String[] {ssp}, userId);
if (fullUninstall) {
intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
// Remove all permissions granted from/to this package
- removeUriPermissionsForPackageLocked(ssp, userId, true);
+ removeUriPermissionsForPackageLocked(ssp, userId, true,
+ false);
- removeTasksByPackageNameLocked(ssp, userId);
+ mRecentTasks.removeTasksByPackageName(ssp, userId);
- // Hide the "unsupported display" dialog if necessary.
- if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
- mUnsupportedDisplaySizeDialog.getPackageName())) {
- mUnsupportedDisplaySizeDialog.dismiss();
- mUnsupportedDisplaySizeDialog = null;
- }
+ mServices.forceStopPackageLocked(ssp, userId);
+ mAppWarnings.onPackageUninstalled(ssp);
mCompatModePackages.handlePackageUninstalledLocked(ssp);
mBatteryStatsService.notePackageUninstalled(ssp);
}
final Uri data = intent.getData();
final String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
- final ApplicationInfo aInfo =
- getPackageManagerInternalLocked().getApplicationInfo(
- ssp,
- userId);
+ ApplicationInfo aInfo = null;
+ try {
+ aInfo = AppGlobals.getPackageManager()
+ .getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
+ } catch (RemoteException ignore) {}
if (aInfo == null) {
Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
+ " ssp=" + ssp + " data=" + data);
return ActivityManager.BROADCAST_SUCCESS;
}
mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
- sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REPLACED,
+ mServices.updateServiceApplicationInfoLocked(aInfo);
+ sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
new String[] {ssp}, userId);
}
break;
try {
ApplicationInfo ai = AppGlobals.getPackageManager().
- getApplicationInfo(ssp, 0, 0);
+ getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
mBatteryStatsService.notePackageInstalled(ssp,
ai != null ? ai.versionCode : 0);
} catch (RemoteException e) {
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
- // Hide the "unsupported display" dialog if necessary.
- if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
- mUnsupportedDisplaySizeDialog.getPackageName())) {
- mUnsupportedDisplaySizeDialog.dismiss();
- mUnsupportedDisplaySizeDialog = null;
- }
mCompatModePackages.handlePackageDataClearedLocked(ssp);
+ mAppWarnings.onPackageDataCleared(ssp);
}
break;
}
mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
break;
case Intent.ACTION_TIME_CHANGED:
- // If the user set the time, let all running processes know.
- final int is24Hour =
- intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1
- : 0;
- mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
+ // EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between
+ // the tri-state value it may contain and "unknown".
+ // For convenience we re-use the Intent extra values.
+ final int NO_EXTRA_VALUE_FOUND = -1;
+ final int timeFormatPreferenceMsgValue = intent.getIntExtra(
+ Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,
+ NO_EXTRA_VALUE_FOUND /* defaultValue */);
+ // Only send a message if the time preference is available.
+ if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {
+ Message updateTimePreferenceMsg =
+ mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,
+ timeFormatPreferenceMsgValue, 0);
+ mHandler.sendMessage(updateTimePreferenceMsg);
+ }
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteCurrentTimeChangedLocked();
break;
case android.hardware.Camera.ACTION_NEW_PICTURE:
case android.hardware.Camera.ACTION_NEW_VIDEO:
- // These broadcasts are no longer allowed by the system, since they can
- // cause significant thrashing at a crictical point (using the camera).
- // Apps should use JobScehduler to monitor for media provider changes.
- Slog.w(TAG, action + " no longer allowed; dropping from "
- + UserHandle.formatUid(callingUid));
- if (resultTo != null) {
- final BroadcastQueue queue = broadcastQueueForIntent(intent);
- try {
- queue.performReceiveLocked(callerApp, resultTo, intent,
- Activity.RESULT_CANCELED, null, null,
- false, false, userId);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure ["
- + queue.mQueueName + "] sending broadcast result of "
- + intent, e);
+ // In N we just turned these off; in O we are turing them back on partly,
+ // only for registered receivers. This will still address the main problem
+ // (a spam of apps waking up when a picture is taken putting significant
+ // memory pressure on the system at a bad point), while still allowing apps
+ // that are already actively running to know about this happening.
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ break;
+ case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
+ mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);
+ break;
+ case "com.android.launcher.action.INSTALL_SHORTCUT":
+ // As of O, we no longer support this broadcasts, even for pre-O apps.
+ // Apps should now be using ShortcutManager.pinRequestShortcut().
+ Log.w(TAG, "Broadcast " + action
+ + " no longer supported. It will not be delivered.");
+ return ActivityManager.BROADCAST_SUCCESS;
+ }
- }
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+ Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+ Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+ final int uid = getUidFromIntent(intent);
+ if (uid != -1) {
+ final UidRecord uidRec = mActiveUids.get(uid);
+ if (uidRec != null) {
+ uidRec.updateHasInternetPermission();
}
- // Lie; we don't want to crash the app.
- return ActivityManager.BROADCAST_SUCCESS;
+ }
}
}
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
- users = mUserController.getStartedUserArrayLocked();
+ users = mUserController.getStartedUserArray();
} else {
// Caller wants broadcast to go to one specific user.
users = new int[] {userId};
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
- if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
+ if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
for (int i = 0; i < users.length; i++) {
if (mUserController.hasUserRestriction(
}
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
- resolvedType, false, users[i]);
+ resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
- resolvedType, false, userId);
+ resolvedType, false /*defaultOnly*/, userId);
}
}
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
- if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
}
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
- callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
- appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
- resultExtras, ordered, sticky, false, userId);
+ callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
+ requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
+ resultCode, resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
- final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
+ final boolean replaced = replacePending
+ && (queue.replaceParallelBroadcastLocked(r) != null);
+ // Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
- callerPackage, callingPid, callingUid, resolvedType,
+ callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Enqueueing broadcast " + r.intent.getAction());
- boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
- if (!replaced) {
+ final BroadcastRecord oldRecord =
+ replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
+ if (oldRecord != null) {
+ // Replaced, fire the result-to receiver.
+ if (oldRecord.resultTo != null) {
+ final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
+ try {
+ oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
+ oldRecord.intent,
+ Activity.RESULT_CANCELED, null, null,
+ false, false, oldRecord.userId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure ["
+ + queue.mQueueName + "] sending broadcast result of "
+ + intent, e);
+
+ }
+ }
+ } else {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
return ActivityManager.BROADCAST_SUCCESS;
}
- final void addBroadcastStatLocked(String action, String srcPackage, int receiveCount,
- int skipCount, long dispatchTime) {
+ /**
+ * @return uid from the extra field {@link Intent#EXTRA_UID} if present, Otherwise -1
+ */
+ private int getUidFromIntent(Intent intent) {
+ if (intent == null) {
+ return -1;
+ }
+ final Bundle intentExtras = intent.getExtras();
+ return intent.hasExtra(Intent.EXTRA_UID)
+ ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
+ }
+
+ final void rotateBroadcastStatsIfNeededLocked() {
final long now = SystemClock.elapsedRealtime();
if (mCurBroadcastStats == null ||
(mCurBroadcastStats.mStartRealtime +(24*60*60*1000) < now)) {
}
mCurBroadcastStats = new BroadcastStats();
}
+ }
+
+ final void addBroadcastStatLocked(String action, String srcPackage, int receiveCount,
+ int skipCount, long dispatchTime) {
+ rotateBroadcastStatsIfNeededLocked();
mCurBroadcastStats.addBroadcast(action, srcPackage, receiveCount, skipCount, dispatchTime);
}
+ final void addBackgroundCheckViolationLocked(String action, String targetPackage) {
+ rotateBroadcastStatsIfNeededLocked();
+ mCurBroadcastStats.addBackgroundCheckViolation(action, targetPackage);
+ }
+
final Intent verifyBroadcastLocked(Intent intent) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
"Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
}
+ if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
+ switch (Binder.getCallingUid()) {
+ case ROOT_UID:
+ case SHELL_UID:
+ break;
+ default:
+ Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID "
+ + Binder.getCallingUid());
+ intent.removeFlags(Intent.FLAG_RECEIVER_FROM_SHELL);
+ break;
+ }
+ }
+
return intent;
}
: new String[] {requiredPermission};
int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, AppOpsManager.OP_NONE, bOptions, serialized,
+ requiredPermissions, OP_NONE, bOptions, serialized,
sticky, -1, uid, userId);
Binder.restoreCallingIdentity(origId);
return res;
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
+ if (doNext) {
+ r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
+ }
+ // updateOomAdjLocked() will be done here
+ trimApplicationsLocked();
}
- if (doNext) {
- r.queue.processNextBroadcast(false);
- }
- trimApplications();
} finally {
Binder.restoreCallingIdentity(origId);
}
throw new SecurityException(msg);
}
+ ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
+ activeInstr.mClass = className;
+ String defProcess = ai.processName;;
+ if (ii.targetProcesses == null) {
+ activeInstr.mTargetProcesses = new String[]{ai.processName};
+ } else if (ii.targetProcesses.equals("*")) {
+ activeInstr.mTargetProcesses = new String[0];
+ } else {
+ activeInstr.mTargetProcesses = ii.targetProcesses.split(",");
+ defProcess = activeInstr.mTargetProcesses[0];
+ }
+ activeInstr.mTargetInfo = ai;
+ activeInstr.mProfileFile = profileFile;
+ activeInstr.mArguments = arguments;
+ activeInstr.mWatcher = watcher;
+ activeInstr.mUiAutomationConnection = uiAutomationConnection;
+ activeInstr.mResultClass = className;
+
+ boolean disableHiddenApiChecks =
+ (flags & INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
+ if (disableHiddenApiChecks) {
+ enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
+ "disable hidden API checks");
+ }
+
final long origId = Binder.clearCallingIdentity();
// Instrumentation can kill and relaunch even persistent processes
forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
"start instr");
- ProcessRecord app = addAppLocked(ai, false, abiOverride);
- app.instrumentationClass = className;
- app.instrumentationInfo = ai;
- app.instrumentationProfileFile = profileFile;
- app.instrumentationArguments = arguments;
- app.instrumentationWatcher = watcher;
- app.instrumentationUiAutomationConnection = uiAutomationConnection;
- app.instrumentationResultClass = className;
+ // Inform usage stats to make the target package active
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(ii.targetPackage, userId,
+ UsageEvents.Event.SYSTEM_INTERACTION);
+ }
+
+ ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
+ abiOverride);
+ app.instr = activeInstr;
+ activeInstr.mFinished = false;
+ activeInstr.mRunningProcesses.add(app);
+ if (!mActiveInstrumentation.contains(activeInstr)) {
+ mActiveInstrumentation.add(activeInstr);
+ }
Binder.restoreCallingIdentity(origId);
}
}
}
+ void addInstrumentationResultsLocked(ProcessRecord app, Bundle results) {
+ if (app.instr == null) {
+ Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
+ return;
+ }
+
+ if (!app.instr.mFinished && results != null) {
+ if (app.instr.mCurResults == null) {
+ app.instr.mCurResults = new Bundle(results);
+ } else {
+ app.instr.mCurResults.putAll(results);
+ }
+ }
+ }
+
+ public void addInstrumentationResults(IApplicationThread target, Bundle results) {
+ int userId = UserHandle.getCallingUserId();
+ // Refuse possible leaked file descriptors
+ if (results != null && results.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ synchronized(this) {
+ ProcessRecord app = getRecordForAppLocked(target);
+ if (app == null) {
+ Slog.w(TAG, "addInstrumentationResults: no app for " + target);
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ addInstrumentationResultsLocked(app, results);
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @GuardedBy("this")
void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
- if (app.instrumentationWatcher != null) {
- mInstrumentationReporter.reportFinished(app.instrumentationWatcher,
- app.instrumentationClass, resultCode, results);
+ if (app.instr == null) {
+ Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
+ return;
}
- // Can't call out of the system process with a lock held, so post a message.
- if (app.instrumentationUiAutomationConnection != null) {
- mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
- app.instrumentationUiAutomationConnection).sendToTarget();
+ if (!app.instr.mFinished) {
+ if (app.instr.mWatcher != null) {
+ Bundle finalResults = app.instr.mCurResults;
+ if (finalResults != null) {
+ if (app.instr.mCurResults != null && results != null) {
+ finalResults.putAll(results);
+ }
+ } else {
+ finalResults = results;
+ }
+ mInstrumentationReporter.reportFinished(app.instr.mWatcher,
+ app.instr.mClass, resultCode, finalResults);
+ }
+
+ // Can't call out of the system process with a lock held, so post a message.
+ if (app.instr.mUiAutomationConnection != null) {
+ mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+ app.instr.mUiAutomationConnection).sendToTarget();
+ }
+ app.instr.mFinished = true;
}
- app.instrumentationWatcher = null;
- app.instrumentationUiAutomationConnection = null;
- app.instrumentationClass = null;
- app.instrumentationInfo = null;
- app.instrumentationProfileFile = null;
- app.instrumentationArguments = null;
+ app.instr.removeProcess(app);
+ app.instr = null;
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
"finished inst");
public ConfigurationInfo getDeviceConfigurationInfo() {
ConfigurationInfo config = new ConfigurationInfo();
synchronized (this) {
- config.reqTouchScreen = mConfiguration.touchscreen;
- config.reqKeyboardType = mConfiguration.keyboard;
- config.reqNavigation = mConfiguration.navigation;
- if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
- || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
+ final Configuration globalConfig = getGlobalConfiguration();
+ config.reqTouchScreen = globalConfig.touchscreen;
+ config.reqKeyboardType = globalConfig.keyboard;
+ config.reqNavigation = globalConfig.navigation;
+ if (globalConfig.navigation == Configuration.NAVIGATION_DPAD
+ || globalConfig.navigation == Configuration.NAVIGATION_TRACKBALL) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
}
- if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
- && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
+ if (globalConfig.keyboard != Configuration.KEYBOARD_UNDEFINED
+ && globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
}
config.reqGlEsVersion = GL_ES_VERSION;
}
@Override
- public int getFocusedStackId() throws RemoteException {
- ActivityStack focusedStack = getFocusedStack();
- if (focusedStack != null) {
- return focusedStack.getStackId();
+ public StackInfo getFocusedStackInfo() throws RemoteException {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack != null) {
+ return mStackSupervisor.getStackInfo(focusedStack.mStackId);
+ }
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- return -1;
}
public Configuration getConfiguration() {
Configuration ci;
synchronized(this) {
- ci = new Configuration(mConfiguration);
+ ci = new Configuration(getGlobalConfiguration());
ci.userSetLocale = false;
}
return ci;
}
}
+ /**
+ * NOTE: For the pinned stack, this method is usually called after the bounds animation has
+ * animated the stack to the fullscreen, but can also be called if we are relaunching an
+ * activity and clearing the task at the same time.
+ */
@Override
+ // TODO: API should just be about changing windowing modes...
public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
- if (fromStackId == HOME_STACK_ID) {
- throw new IllegalArgumentException("You can't move tasks from the home stack.");
- }
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+ "moveTasksToFullscreenStack()");
synchronized (this) {
final long origId = Binder.clearCallingIdentity();
try {
- mStackSupervisor.moveTasksToFullscreenStackLocked(fromStackId, onTop);
+ final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
+ if (stack != null){
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException(
+ "You can't move tasks from non-standard stacks.");
+ }
+ mStackSupervisor.moveTasksToFullscreenStackLocked(stack, onTop);
+ }
} finally {
Binder.restoreCallingIdentity(origId);
}
@Override
public void updatePersistentConfiguration(Configuration values) {
- enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
- "updateConfiguration()");
- enforceWriteSettingsPermission("updateConfiguration()");
+ enforceCallingPermission(CHANGE_CONFIGURATION, "updatePersistentConfiguration()");
+ enforceWriteSettingsPermission("updatePersistentConfiguration()");
if (values == null) {
throw new NullPointerException("Configuration must not be null");
}
private void updateFontScaleIfNeeded(@UserIdInt int userId) {
final float scaleFactor = Settings.System.getFloatForUser(mContext.getContentResolver(),
FONT_SCALE, 1.0f, userId);
- if (mConfiguration.fontScale != scaleFactor) {
- final Configuration configuration = mWindowManager.computeNewConfiguration();
- configuration.fontScale = scaleFactor;
- synchronized (this) {
- updatePersistentConfigurationLocked(configuration, userId);
+
+ synchronized (this) {
+ if (getGlobalConfiguration().fontScale == scaleFactor) {
+ return;
}
+
+ final Configuration configuration
+ = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
+ configuration.fontScale = scaleFactor;
+ updatePersistentConfigurationLocked(configuration, userId);
}
}
private void enforceWriteSettingsPermission(String func) {
int uid = Binder.getCallingUid();
- if (uid == Process.ROOT_UID) {
+ if (uid == ROOT_UID) {
return;
}
throw new SecurityException(msg);
}
- public void updateConfiguration(Configuration values) {
- enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
- "updateConfiguration()");
+ @Override
+ public boolean updateConfiguration(Configuration values) {
+ enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
synchronized(this) {
if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
- values = mWindowManager.computeNewConfiguration();
+ values = mWindowManager.computeNewConfiguration(DEFAULT_DISPLAY);
}
if (mWindowManager != null) {
+ // Update OOM levels based on display size.
mProcessList.applyDisplaySize(mWindowManager);
}
final long origId = Binder.clearCallingIdentity();
- if (values != null) {
- Settings.System.clearConfiguration(values);
+ try {
+ if (values != null) {
+ Settings.System.clearConfiguration(values);
+ }
+ updateConfigurationLocked(values, null, false, false /* persistent */,
+ UserHandle.USER_NULL, false /* deferResume */,
+ mTmpUpdateConfigurationResult);
+ return mTmpUpdateConfigurationResult.changes != 0;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- updateConfigurationLocked(values, null, false);
- Binder.restoreCallingIdentity(origId);
}
}
void updateUserConfigurationLocked() {
- Configuration configuration = new Configuration(mConfiguration);
+ final Configuration configuration = new Configuration(getGlobalConfiguration());
+ final int currentUserId = mUserController.getCurrentUserId();
Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
- mUserController.getCurrentUserIdLocked(), Settings.System.canWrite(mContext));
- updateConfigurationLocked(configuration, null, false);
+ currentUserId, Settings.System.canWrite(mContext));
+ updateConfigurationLocked(configuration, null /* starting */, false /* initLocale */,
+ false /* persistent */, currentUserId, false /* deferResume */);
}
boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
// To cache the list of supported system locales
private String[] mSupportedSystemLocales = null;
+ private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean persistent, int userId, boolean deferResume) {
+ return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
+ deferResume, null /* result */);
+ }
+
/**
* Do either or both things: (1) change the current configuration, and (2)
* make sure the given activity is running with the (now) current
* for that particular user
*/
private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean initLocale, boolean persistent, int userId, boolean deferResume) {
+ boolean initLocale, boolean persistent, int userId, boolean deferResume,
+ UpdateConfigurationResult result) {
int changes = 0;
+ boolean kept = true;
if (mWindowManager != null) {
mWindowManager.deferSurfaceLayout();
}
- if (values != null) {
- Configuration newConfig = new Configuration(mConfiguration);
- changes = newConfig.updateFrom(values);
- if (changes != 0) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
- "Updating configuration to: " + values);
-
- EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
-
- if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
- final LocaleList locales = values.getLocales();
- int bestLocaleIndex = 0;
- if (locales.size() > 1) {
- if (mSupportedSystemLocales == null) {
- mSupportedSystemLocales =
- Resources.getSystem().getAssets().getLocales();
- }
- bestLocaleIndex = Math.max(0,
- locales.getFirstMatchIndex(mSupportedSystemLocales));
- }
- SystemProperties.set("persist.sys.locale",
- locales.get(bestLocaleIndex).toLanguageTag());
- LocaleList.setDefault(locales, bestLocaleIndex);
- mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
- locales.get(bestLocaleIndex)));
- }
+ try {
+ if (values != null) {
+ changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
+ deferResume);
+ }
- mConfigurationSeq++;
- if (mConfigurationSeq <= 0) {
- mConfigurationSeq = 1;
- }
- newConfig.seq = mConfigurationSeq;
- mConfiguration = newConfig;
- Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
- mUsageStatsService.reportConfigurationChange(newConfig,
- mUserController.getCurrentUserIdLocked());
- //mUsageStatsService.noteStartConfig(newConfig);
+ kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
+ }
+ }
- final Configuration configCopy = new Configuration(mConfiguration);
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
+ return kept;
+ }
- // TODO: If our config changes, should we auto dismiss any currently
- // showing dialogs?
- mShowDialogs = shouldShowDialogs(newConfig, mInVrMode);
+ /**
+ * Returns true if this configuration change is interesting enough to send an
+ * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
+ */
+ private static boolean isSplitConfigurationChange(int configDiff) {
+ return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
+ }
+
+ /** Update default (global) configuration and notify listeners about changes. */
+ private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
+ boolean persistent, int userId, boolean deferResume) {
+ mTempConfig.setTo(getGlobalConfiguration());
+ final int changes = mTempConfig.updateFrom(values);
+ if (changes == 0) {
+ // Since calling to Activity.setRequestedOrientation leads to freezing the window with
+ // setting WindowManagerService.mWaitingForConfig to true, it is important that we call
+ // performDisplayOverrideConfigUpdate in order to send the new display configuration
+ // (even if there are no actual changes) to unfreeze the window.
+ performDisplayOverrideConfigUpdate(values, deferResume, DEFAULT_DISPLAY);
+ return 0;
+ }
- AttributeCache ac = AttributeCache.instance();
- if (ac != null) {
- ac.updateConfiguration(configCopy);
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
+ "Updating global configuration to: " + values);
+
+ EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+ StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
+ values.colorMode,
+ values.densityDpi,
+ values.fontScale,
+ values.hardKeyboardHidden,
+ values.keyboard,
+ values.keyboardHidden,
+ values.mcc,
+ values.mnc,
+ values.navigation,
+ values.navigationHidden,
+ values.orientation,
+ values.screenHeightDp,
+ values.screenLayout,
+ values.screenWidthDp,
+ values.smallestScreenWidthDp,
+ values.touchscreen,
+ values.uiMode);
+
+
+ if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
+ final LocaleList locales = values.getLocales();
+ int bestLocaleIndex = 0;
+ if (locales.size() > 1) {
+ if (mSupportedSystemLocales == null) {
+ mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+ }
+ bestLocaleIndex = Math.max(0, locales.getFirstMatchIndex(mSupportedSystemLocales));
+ }
+ SystemProperties.set("persist.sys.locale",
+ locales.get(bestLocaleIndex).toLanguageTag());
+ LocaleList.setDefault(locales, bestLocaleIndex);
+ mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
+ locales.get(bestLocaleIndex)));
+ }
+
+ mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+ mTempConfig.seq = mConfigurationSeq;
+
+ // Update stored global config and notify everyone about the change.
+ mStackSupervisor.onConfigurationChanged(mTempConfig);
+
+ Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
+ // TODO(multi-display): Update UsageEvents#Event to include displayId.
+ mUsageStatsService.reportConfigurationChange(mTempConfig,
+ mUserController.getCurrentUserId());
+
+ // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
+ updateShouldShowDialogsLocked(mTempConfig);
+
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.updateConfiguration(mTempConfig);
+ }
+
+ // Make sure all resources in our process are updated right now, so that anyone who is going
+ // to retrieve resource values after we return will be sure to get the new ones. This is
+ // especially important during boot, where the first config change needs to guarantee all
+ // resources have that config before following boot code is executed.
+ mSystemThread.applyConfigurationToResources(mTempConfig);
+
+ // We need another copy of global config because we're scheduling some calls instead of
+ // running them in place. We need to be sure that object we send will be handled unchanged.
+ final Configuration configCopy = new Configuration(mTempConfig);
+ if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
+ Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
+ msg.obj = configCopy;
+ msg.arg1 = userId;
+ mHandler.sendMessage(msg);
+ }
+
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ try {
+ if (app.thread != null) {
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ + app.processName + " new config " + configCopy);
+ mLifecycleManager.scheduleTransaction(app.thread,
+ ConfigurationChangeItem.obtain(configCopy));
}
+ } catch (Exception e) {
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+ }
+ }
- // Make sure all resources in our process are updated
- // right now, so that anyone who is going to retrieve
- // resource values after we return will be sure to get
- // the new ones. This is especially important during
- // boot, where the first config change needs to guarantee
- // all resources have that config before following boot
- // code is executed.
- mSystemThread.applyConfigurationToResources(configCopy);
+ Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
+ intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ if (initLocale || !mProcessesReady) {
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ }
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ }
- if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
- Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
- msg.obj = new Configuration(configCopy);
- msg.arg1 = userId;
- mHandler.sendMessage(msg);
- }
+ // Send a broadcast to PackageInstallers if the configuration change is interesting
+ // for the purposes of installing additional splits.
+ if (!initLocale && isSplitConfigurationChange(changes)) {
+ intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
- if (isDensityChange) {
- // Reset the unsupported display size dialog.
- mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG);
+ // Typically only app stores will have this permission.
+ String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ }
- killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
- ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
- }
+ // Override configuration of the default display duplicates global config, so we need to
+ // update it also. This will also notify WindowManager about changes.
+ performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
+ DEFAULT_DISPLAY);
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- try {
- if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.processName + " new config " + mConfiguration);
- app.thread.scheduleConfigurationChanged(configCopy);
- }
- } catch (Exception e) {
- }
+ return changes;
+ }
+
+ @Override
+ public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) {
+ enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
+
+ synchronized (this) {
+ // Check if display is initialized in AM.
+ if (!mStackSupervisor.isDisplayAdded(displayId)) {
+ // Call might come when display is not yet added or has already been removed.
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG, "Trying to update display configuration for non-existing displayId="
+ + displayId);
}
- Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_FOREGROUND);
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
- null, AppOpsManager.OP_NONE, null, false, false,
- MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
- if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
- intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- if (initLocale || !mProcessesReady) {
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- }
- broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
- }
- }
- // Update the configuration with WM first and check if any of the stacks need to be
- // resized due to the configuration change. If so, resize the stacks now and do any
- // relaunches if necessary. This way we don't need to relaunch again below in
- // ensureActivityConfigurationLocked().
+ return false;
+ }
+
+ if (values == null && mWindowManager != null) {
+ // sentinel: fetch the current configuration from the window manager
+ values = mWindowManager.computeNewConfiguration(displayId);
+ }
+
if (mWindowManager != null) {
- final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
- if (resizedStacks != null) {
- for (int stackId : resizedStacks) {
- final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
- mStackSupervisor.resizeStackLocked(
- stackId, newBounds, null, null, false, false, deferResume);
- }
+ // Update OOM levels based on display size.
+ mProcessList.applyDisplaySize(mWindowManager);
+ }
+
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ if (values != null) {
+ Settings.System.clearConfiguration(values);
}
+ updateDisplayOverrideConfigurationLocked(values, null /* starting */,
+ false /* deferResume */, displayId, mTmpUpdateConfigurationResult);
+ return mTmpUpdateConfigurationResult.changes != 0;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
+ }
+
+ boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean deferResume, int displayId) {
+ return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */,
+ displayId, null /* result */);
+ }
+ /**
+ * Updates override configuration specific for the selected display. If no config is provided,
+ * new one will be computed in WM based on current display info.
+ */
+ private boolean updateDisplayOverrideConfigurationLocked(Configuration values,
+ ActivityRecord starting, boolean deferResume, int displayId,
+ UpdateConfigurationResult result) {
+ int changes = 0;
+ boolean kept = true;
+
+ if (mWindowManager != null) {
+ mWindowManager.deferSurfaceLayout();
+ }
+ try {
+ if (values != null) {
+ if (displayId == DEFAULT_DISPLAY) {
+ // Override configuration of the default display duplicates global config, so
+ // we're calling global config update instead for default display. It will also
+ // apply the correct override config.
+ changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
+ false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
+ } else {
+ changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
+ }
+ }
+
+ kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ if (mWindowManager != null) {
+ mWindowManager.continueSurfaceLayout();
+ }
+ }
+
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
+ return kept;
+ }
+
+ private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume,
+ int displayId) {
+ mTempConfig.setTo(mStackSupervisor.getDisplayOverrideConfiguration(displayId));
+ final int changes = mTempConfig.updateFrom(values);
+ if (changes != 0) {
+ Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+ + mTempConfig + " for displayId=" + displayId);
+ mStackSupervisor.setDisplayOverrideConfiguration(mTempConfig, displayId);
+
+ final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+ if (isDensityChange && displayId == DEFAULT_DISPLAY) {
+ mAppWarnings.onDensityChanged();
+
+ killAllBackgroundProcessesExcept(N,
+ ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ }
+ }
+
+ // Update the configuration with WM first and check if any of the stacks need to be resized
+ // due to the configuration change. If so, resize the stacks now and do any relaunches if
+ // necessary. This way we don't need to relaunch again afterwards in
+ // ensureActivityConfiguration().
+ if (mWindowManager != null) {
+ final int[] resizedStacks =
+ mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId);
+ if (resizedStacks != null) {
+ for (int stackId : resizedStacks) {
+ resizeStackWithBoundsFromWindowManager(stackId, deferResume);
+ }
+ }
+ }
+
+ return changes;
+ }
+
+ /** Applies latest configuration and/or visibility updates if needed. */
+ private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
boolean kept = true;
final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
// mainStack is null during startup.
}
if (starting != null) {
- kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false);
+ kept = starting.ensureActivityConfiguration(changes,
+ false /* preserveWindow */);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
!PRESERVE_WINDOWS);
}
}
- if (mWindowManager != null) {
- mWindowManager.continueSurfaceLayout();
- }
+
return kept;
}
+ /** Helper method that requests bounds from WM and applies them to stack. */
+ private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) {
+ final Rect newStackBounds = new Rect();
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+
+ // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found.
+ if (stack == null) {
+ final StringWriter writer = new StringWriter();
+ final PrintWriter printWriter = new PrintWriter(writer);
+ mStackSupervisor.dumpDisplays(printWriter);
+ printWriter.flush();
+
+ Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer);
+ }
+
+ stack.getBoundsForNewConfiguration(newStackBounds);
+ mStackSupervisor.resizeStackLocked(
+ stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */,
+ null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume);
+ }
+
/**
- * Decide based on the configuration whether we should shouw the ANR,
- * crash, etc dialogs. The idea is that if there is no affordence to
+ * Decide based on the configuration whether we should show the ANR,
+ * crash, etc dialogs. The idea is that if there is no affordance to
* press the on-screen buttons, or the user experience would be more
* greatly impacted than the crash itself, we shouldn't show the dialog.
*
* A thought: SystemUI might also want to get told about this, the Power
* dialog / global actions also might want different behaviors.
*/
- private static final boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
+ private void updateShouldShowDialogsLocked(Configuration config) {
final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
&& config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
&& config.navigation == Configuration.NAVIGATION_NONAV);
int modeType = config.uiMode & Configuration.UI_MODE_TYPE_MASK;
final boolean uiModeSupportsDialogs = (modeType != Configuration.UI_MODE_TYPE_CAR
- && !(modeType == Configuration.UI_MODE_TYPE_WATCH && "user".equals(Build.TYPE)));
- return inputMethodExists && uiModeSupportsDialogs && !inVrMode;
+ && !(modeType == Configuration.UI_MODE_TYPE_WATCH && Build.IS_USER)
+ && modeType != Configuration.UI_MODE_TYPE_TELEVISION
+ && modeType != Configuration.UI_MODE_TYPE_VR_HEADSET);
+ final boolean hideDialogsSet = Settings.Global.getInt(mContext.getContentResolver(),
+ HIDE_ERROR_DIALOGS, 0) != 0;
+ mShowDialogs = inputMethodExists && uiModeSupportsDialogs && !hideDialogsSet;
}
@Override
synchronized (this) {
ActivityRecord srec = ActivityRecord.forTokenLocked(token);
if (srec != null) {
- return srec.task.stack.shouldUpRecreateTaskLocked(srec, destAffinity);
+ return srec.getStack().shouldUpRecreateTaskLocked(srec, destAffinity);
}
}
return false;
synchronized (this) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
- return r.task.stack.navigateUpToLocked(r, destIntent, resultCode, resultData);
+ return r.getStack().navigateUpToLocked(r, destIntent, resultCode, resultData);
}
return false;
}
// LIFETIME MANAGEMENT
// =========================================================
- // Returns which broadcast queue the app is the current [or imminent] receiver
- // on, or 'null' if the app is not an active broadcast recipient.
- private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
- BroadcastRecord r = app.curReceiver;
- if (r != null) {
- return r.queue;
+ // Returns whether the app is receiving broadcast.
+ // If receiving, fetch all broadcast queues which the app is
+ // the current [or imminent] receiver on.
+ private boolean isReceivingBroadcastLocked(ProcessRecord app,
+ ArraySet<BroadcastQueue> receivingQueues) {
+ final int N = app.curReceivers.size();
+ if (N > 0) {
+ for (int i = 0; i < N; i++) {
+ receivingQueues.add(app.curReceivers.valueAt(i).queue);
+ }
+ return true;
}
// It's not the current receiver, but it might be starting up to become one
- synchronized (this) {
- for (BroadcastQueue queue : mBroadcastQueues) {
- r = queue.mPendingBroadcast;
- if (r != null && r.curApp == app) {
- // found it; report which queue it's in
- return queue;
- }
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ final BroadcastRecord r = queue.mPendingBroadcast;
+ if (r != null && r.curApp == app) {
+ // found it; report which queue it's in
+ receivingQueues.add(queue);
}
}
- return null;
+ return !receivingQueues.isEmpty();
}
Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
private void noteUidProcessState(final int uid, final int state) {
mBatteryStatsService.noteUidProcessState(uid, state);
+ mAppOpsService.updateUidProcState(uid, state);
if (mTrackingAssociations) {
for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
}
}
- private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
+ private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
boolean doingAll, long now) {
if (mAdjSeq == app.adjSeq) {
- // This adjustment has already been computed.
- return app.curRawAdj;
+ if (app.adjSeq == app.completedAdjSeq) {
+ // This adjustment has already been computed successfully.
+ return false;
+ } else {
+ // The process is being computed, so there is a cycle. We cannot
+ // rely on this process's state.
+ app.containsCycle = true;
+
+ return false;
+ }
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
+ app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
+ app.completedAdjSeq = app.adjSeq;
+ return false;
}
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.cached = false;
final int activitiesSize = app.activities.size();
+ final int appUid = app.info.uid;
+ final int logUid = mCurOomAdjUid;
+
+ int prevAppAdj = app.curAdj;
+ int prevProcState = app.curProcState;
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
+ }
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "pers-top-activity";
} else if (app.hasTopUi) {
+ // sched group/proc state adjustment is below
app.systemNoUi = false;
- app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "pers-top-ui";
} else if (activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
}
}
if (!app.systemNoUi) {
- app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
- }
- return (app.curAdj=app.maxAdj);
+ if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ // screen on, promote UI
+ app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+ app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ } else {
+ // screen off, restrict UI scheduling
+ app.curProcState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.curSchedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
+ }
+ }
+ app.curAdj = app.maxAdj;
+ app.completedAdjSeq = app.adjSeq;
+ // if curAdj is less than prevAppAdj, then this process was promoted
+ return app.curAdj < prevAppAdj;
}
app.systemNoUi = false;
int adj;
int schedGroup;
int procState;
+ int cachedAdjSeq;
+
boolean foregroundActivities = false;
- BroadcastQueue queue;
- if (app == TOP_APP) {
+ mTmpBroadcastQueue.clear();
+ if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) {
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
- } else if (app.instrumentationClass != null) {
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
+ }
+ } else if (app.runningRemoteAnimation) {
+ adj = ProcessList.VISIBLE_APP_ADJ;
+ schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ app.adjType = "running-remote-anim";
+ procState = PROCESS_STATE_CUR_TOP;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
+ }
+ } else if (app.instr != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
- } else if ((queue = isReceivingBroadcast(app)) != null) {
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
+ }
+ } else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
// It's placed in a sched group based on the nature of the
// broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = (queue == mFgBroadcastQueue)
+ schedGroup = (mTmpBroadcastQueue.contains(mFgBroadcastQueue))
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "broadcast";
procState = ActivityManager.PROCESS_STATE_RECEIVER;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
+ }
} else if (app.executingServices.size() > 0) {
// An app that is currently executing a service callback also
// counts as being in the foreground.
ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
+ }
//Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
+ } else if (app == TOP_APP) {
+ adj = ProcessList.FOREGROUND_APP_ADJ;
+ schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+ app.adjType = "top-sleeping";
+ foregroundActivities = true;
+ procState = PROCESS_STATE_CUR_TOP;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
+ }
} else {
// As far as we know the process is empty. We may change our mind later.
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = true;
app.empty = true;
app.adjType = "cch-empty";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
+ }
}
// Examine all activities if not already foreground.
+ " instead of expected " + app);
if (r.app == null || (r.app.uid == app.uid)) {
// Only fix things up when they look sane
- r.app = app;
+ r.setProcess(app);
} else {
continue;
}
// App has a visible activity; only upgrade adjustment.
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
- app.adjType = "visible";
+ app.adjType = "vis-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to vis-activity: " + app);
+ }
}
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
+ app.adjType = "vis-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to vis-activity (top): " + app);
+ }
+ }
+ if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
- if (r.task != null && minLayer > 0) {
- final int layer = r.task.mLayerRank;
+ final TaskRecord task = r.getTask();
+ if (task != null && minLayer > 0) {
+ final int layer = task.mLayerRank;
if (layer >= 0 && minLayer > layer) {
minLayer = layer;
}
}
break;
- } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
+ } else if (r.isState(ActivityState.PAUSING, ActivityState.PAUSED)) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "pausing";
+ app.adjType = "pause-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to pause-activity: " + app);
+ }
}
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
+ app.adjType = "pause-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to pause-activity (top): " + app);
+ }
+ }
+ if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
app.empty = false;
foregroundActivities = true;
- } else if (r.state == ActivityState.STOPPING) {
+ } else if (r.isState(ActivityState.STOPPING)) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "stopping";
+ app.adjType = "stop-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to stop-activity: " + app);
+ }
}
// For the process state, we will at this point consider the
// process to be cached. It will be cached either as an activity
if (!r.finishing) {
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "stop-activity";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to stop-activity: " + app);
+ }
}
}
app.cached = false;
if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-act";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to cached activity: " + app);
+ }
}
}
}
adj += minLayer;
}
}
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.recentTasks.size() > 0) {
+ procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
+ app.adjType = "cch-rec";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app);
+ }
+ }
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
|| procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
app.cached = false;
app.adjType = "fg-service";
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- } else if (app.forcingToForeground != null) {
- // The user is aware of this app, so make it visible.
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to fg service: " + app);
+ }
+ } else if (app.hasOverlayUi) {
+ // The process is display an overlay UI.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
- app.adjType = "force-fg";
- app.adjSource = app.forcingToForeground;
+ app.adjType = "has-overlay-ui";
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app);
+ }
+ }
+ }
+
+ // If the app was recently in the foreground and moved to a foreground service status,
+ // allow it to get a higher rank in memory for some time, compared to other foreground
+ // services so that it can finish performing any persistence/processing of in-memory state.
+ if (app.foregroundServices && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ
+ && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now
+ || app.setProcState <= ActivityManager.PROCESS_STATE_TOP)) {
+ adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+ app.adjType = "fg-service-act";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
+ }
+ }
+
+ if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+ || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ if (app.forcingToImportant != null) {
+ // This is currently used for toasts... they are not interactive, and
+ // we don't want them to cause the app to become fully foreground (and
+ // thus out of background check), so we yes the best background level we can.
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+ app.cached = false;
+ app.adjType = "force-imp";
+ app.adjSource = app.forcingToImportant;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app);
+ }
}
}
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "heavy";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
+ }
}
if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+ app.adjType = "heavy";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app);
+ }
}
}
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "home";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
+ }
}
if (procState > ActivityManager.PROCESS_STATE_HOME) {
procState = ActivityManager.PROCESS_STATE_HOME;
+ app.adjType = "home";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app);
+ }
}
}
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "previous";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
+ }
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "previous";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
+ }
}
}
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
- app.adjSeq = mAdjSeq;
app.curRawAdj = adj;
app.hasStartedServices = false;
+ app.adjSeq = mAdjSeq;
if (mBackupTarget != null && app == mBackupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
if (adj > ProcessList.BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
adj = ProcessList.BACKUP_APP_ADJ;
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ if (procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
}
app.adjType = "backup";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
+ }
app.cached = false;
}
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
procState = ActivityManager.PROCESS_STATE_BACKUP;
+ app.adjType = "backup";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app);
+ }
}
}
boolean mayBeTop = false;
+ String mayBeTopType = null;
+ Object mayBeTopSource = null;
+ Object mayBeTopTarget = null;
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
app.hasStartedServices = true;
if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
procState = ActivityManager.PROCESS_STATE_SERVICE;
+ app.adjType = "started-services";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to started service: " + app);
+ }
}
if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
app.adjType = "cch-started-ui-services";
}
} else {
- if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
// This service has seen some activity within
// recent memory, so we will keep its process ahead
// of the background processes.
if (adj > ProcessList.SERVICE_ADJ) {
adj = ProcessList.SERVICE_ADJ;
app.adjType = "started-services";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to started service: " + app);
+ }
app.cached = false;
}
}
if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
- int clientAdj = computeOomAdjLocked(client, cachedAdj,
- TOP_APP, doingAll, now);
+ computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+ if (client.containsCycle) {
+ // We've detected a cycle. We should retry computeOomAdjLocked later in
+ // case a later-checked connection from a client would raise its
+ // priority legitimately.
+ app.containsCycle = true;
+ // If the client has not been completely evaluated, skip using its
+ // priority. Else use the conservative value for now and look for a
+ // better state in the next iteration.
+ if (client.completedAdjSeq < mAdjSeq) {
+ continue;
+ }
+ }
+ int clientAdj = client.curRawAdj;
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
clientAdj = adj;
clientProcState = procState;
} else {
- if (now >= (s.lastActivity
- + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ if (now >= (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
// This service has not seen activity within
// recent memory, so allow it to drop to the
// LRU list if there is no other reason to keep
// memory.
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-bound-ui-services";
+ if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ adjType = "cch-bound-ui-services";
+ }
} else {
+ int newAdj;
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
- adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
- ? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;
+ if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
+ newAdj = clientAdj;
+ } else {
+ // make this service persistent
+ newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ procState = ActivityManager.PROCESS_STATE_PERSISTENT;
+ }
+ } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0
+ && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+ && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) {
+ newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1;
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = clientAdj;
+ newAdj = clientAdj;
} else {
if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
+ newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
+ } else {
+ newAdj = adj;
}
}
if (!client.cached) {
app.cached = false;
}
- adjType = "service";
+ if (adj > newAdj) {
+ adj = newAdj;
+ adjType = "service";
+ }
}
}
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ if ((cr.flags & (Context.BIND_NOT_FOREGROUND
+ | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
// This will treat important bound services identically to
// the top app, which may behave differently than generic
// foreground work.
// is more important to continue considering it to be
// in the background state.
mayBeTop = true;
+ mayBeTopType = "service";
+ mayBeTopSource = cr.binding.client;
+ mayBeTopTarget = s.name;
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
} else {
// Special handling for above-top states (persistent
}
}
}
+ } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
+ if (clientProcState <
+ ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ clientProcState =
+ ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+ }
} else {
if (clientProcState <
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
}
if (procState > clientProcState) {
procState = clientProcState;
+ if (adjType == null) {
+ adjType = "service";
+ }
}
if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
&& (cr.flags&Context.BIND_SHOWING_UI) != 0) {
app.adjSource = cr.binding.client;
app.adjSourceProcState = clientProcState;
app.adjTarget = s.name;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ + ": " + app + ", due to " + cr.binding.client
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
}
}
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
}
final ActivityRecord a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED ||
- a.state == ActivityState.PAUSING)) {
+ if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && (a.visible
+ || a.isState(ActivityState.RESUMED, ActivityState.PAUSING))) {
adj = ProcessList.FOREGROUND_APP_ADJ;
if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
app.adjSource = a;
app.adjSourceProcState = procState;
app.adjTarget = s.name;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise to service w/activity: " + app);
+ }
}
}
}
// Being our own client is not interesting.
continue;
}
- int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+ computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+ if (client.containsCycle) {
+ // We've detected a cycle. We should retry computeOomAdjLocked later in
+ // case a later-checked connection from a client would raise its
+ // priority legitimately.
+ app.containsCycle = true;
+ // If the client has not been completely evaluated, skip using its
+ // priority. Else use the conservative value for now and look for a
+ // better state in the next iteration.
+ if (client.completedAdjSeq < mAdjSeq) {
+ continue;
+ }
+ }
+ int clientAdj = client.curRawAdj;
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty.
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
+ String adjType = null;
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- app.adjType = "cch-ui-provider";
+ adjType = "cch-ui-provider";
} else {
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
- app.adjType = "provider";
+ adjType = "provider";
}
app.cached &= client.cached;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE;
- app.adjSource = client;
- app.adjSourceProcState = clientProcState;
- app.adjTarget = cpr.name;
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
// in the background state.
mayBeTop = true;
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+ mayBeTopType = adjType = "provider-top";
+ mayBeTopSource = client;
+ mayBeTopTarget = cpr.name;
} else {
// Special handling for above-top states (persistent
// processes). These should not bring the current process
// give them the best state after that.
clientProcState =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ if (adjType == null) {
+ adjType = "provider";
+ }
}
}
if (procState > clientProcState) {
if (client.curSchedGroup > schedGroup) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
+ if (adjType != null) {
+ app.adjType = adjType;
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE;
+ app.adjSource = client;
+ app.adjSourceProcState = clientProcState;
+ app.adjTarget = cpr.name;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ + ": " + app + ", due to " + client
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
+ }
}
// If the provider has external (non-framework) process
// dependencies, ensure that its adjustment is at least
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
- app.adjType = "provider";
+ app.adjType = "ext-provider";
app.adjTarget = cpr.name;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to external provider: " + app);
+ }
}
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to external provider: " + app);
}
}
}
- if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
+ if (app.lastProviderTime > 0 &&
+ (app.lastProviderTime+mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
- app.adjType = "provider";
+ app.adjType = "recent-provider";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise adj to recent provider: " + app);
+ }
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "recent-provider";
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise procstate to recent provider: " + app);
+ }
}
}
// is top (states that tend to be longer-term) and otherwise allow it to go
// to the top state.
switch (procState) {
+ case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+ case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+ // Something else is keeping it at this level, just leave it.
+ break;
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
case ActivityManager.PROCESS_STATE_SERVICE:
// These all are longer-term states, so pull them up to the top
// of the background states, but not all the way to the top state.
procState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.adjType = mayBeTopType;
+ app.adjSource = mayBeTopSource;
+ app.adjTarget = mayBeTopTarget;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "May be top raise to " + mayBeTopType
+ + ": " + app + ", due to " + mayBeTopSource
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
break;
default:
// Otherwise, top is a better choice, so take it.
procState = ActivityManager.PROCESS_STATE_TOP;
+ app.adjType = mayBeTopType;
+ app.adjSource = mayBeTopSource;
+ app.adjTarget = mayBeTopTarget;
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "May be top raise to " + mayBeTopType
+ + ": " + app + ", due to " + mayBeTopSource
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
break;
}
}
}
}
+ // Put bound foreground services in a special sched group for additional
+ // restrictions on screen off
+ if (procState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE &&
+ mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
+ schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
+ }
+ }
+
// Do final modification to adj. Everything we do between here and applying
// the final setAdj must be done in this function, because we will also use
// it when computing the final cached adj later. Note that we don't need to
app.curSchedGroup = schedGroup;
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
+ app.completedAdjSeq = mAdjSeq;
- return app.curRawAdj;
+ // if curAdj or curProcState improved, then this process was promoted
+ return app.curAdj < prevAppAdj || app.curProcState < prevProcState;
}
/**
* Record new PSS sample for a process.
*/
void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long swapPss,
- long now) {
+ long rss, int statType, long pssDuration, long now) {
EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024,
- swapPss * 1024);
+ swapPss * 1024, rss * 1024, statType, procState, pssDuration);
proc.lastPssTime = now;
- proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
+ proc.baseProcessTracker.addPss(pss, uss, rss, true, statType, pssDuration, proc.pkgList);
if (DEBUG_PSS) Slog.d(TAG_PSS,
- "PSS of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
+ "pss of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
+ " state=" + ProcessList.makeProcStateString(procState));
if (proc.initialIdlePss == 0) {
proc.initialIdlePss = pss;
public void run() {
revokeUriPermission(ActivityThread.currentActivityThread()
.getApplicationThread(),
- DumpHeapActivity.JAVA_URI,
+ null, DumpHeapActivity.JAVA_URI,
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
UserHandle.myUserId());
if (DEBUG_PSS) Slog.d(TAG_PSS,
"Requesting dump heap from "
+ myProc + " to " + heapdumpFile);
- thread.dumpHeap(true, heapdumpFile.toString(), fd);
+ thread.dumpHeap(/* managed= */ true,
+ /* mallocInfo= */ false, /* runGc= */ false,
+ heapdumpFile.toString(), fd);
} catch (RemoteException e) {
}
}
/**
* Schedule PSS collection of a process.
*/
- void requestPssLocked(ProcessRecord proc, int procState) {
+ boolean requestPssLocked(ProcessRecord proc, int procState) {
if (mPendingPssProcesses.contains(proc)) {
- return;
+ return false;
}
if (mPendingPssProcesses.size() == 0) {
mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
}
- if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of: " + proc);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of: " + proc);
proc.pssProcState = procState;
+ proc.pssStatType = ProcessStats.ADD_PSS_INTERNAL_SINGLE;
mPendingPssProcesses.add(proc);
+ return true;
}
/**
void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
if (!always) {
if (now < (mLastFullPssTime +
- (memLowered ? FULL_PSS_LOWERED_INTERVAL : FULL_PSS_MIN_INTERVAL))) {
+ (memLowered ? mConstants.FULL_PSS_LOWERED_INTERVAL
+ : mConstants.FULL_PSS_MIN_INTERVAL))) {
return;
}
}
- if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of all procs! memLowered=" + memLowered);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of all procs! memLowered=" + memLowered);
mLastFullPssTime = now;
mFullPssPending = true;
+ for (int i = mPendingPssProcesses.size() - 1; i >= 0; i--) {
+ ProcessList.abortNextPssTime(mPendingPssProcesses.get(i).procStateMemTracker);;
+ }
mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
mPendingPssProcesses.clear();
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
|| app.curProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
continue;
}
- if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
+ if (memLowered || (always && now >
+ app.lastStateTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
+ || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
app.pssProcState = app.setProcState;
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mTestPssMode, isSleepingLocked(), now);
+ app.pssStatType = always ? ProcessStats.ADD_PSS_INTERNAL_ALL_POLL
+ : ProcessStats.ADD_PSS_INTERNAL_ALL_MEM;
+ app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
mPendingPssProcesses.add(app);
}
}
- mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+ if (!mBgHandler.hasMessages(COLLECT_PSS_BG_MSG)) {
+ mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+ }
}
public void setTestPssMode(boolean enabled) {
while (mProcessesToGc.size() > 0) {
ProcessRecord proc = mProcessesToGc.remove(0);
if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
- if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
+ if ((proc.lastRequestedGc+mConstants.GC_MIN_INTERVAL)
<= SystemClock.uptimeMillis()) {
// To avoid spamming the system, we will GC processes one
// at a time, waiting a few seconds between each.
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
- long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
+ long when = proc.lastRequestedGc + mConstants.GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
- if (when < (now+GC_TIMEOUT)) {
- when = now + GC_TIMEOUT;
+ if (when < (now+mConstants.GC_TIMEOUT)) {
+ when = now + mConstants.GC_TIMEOUT;
}
mHandler.sendMessageAtTime(msg, when);
}
*/
final void scheduleAppGcLocked(ProcessRecord app) {
long now = SystemClock.uptimeMillis();
- if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
+ if ((app.lastRequestedGc+mConstants.GC_MIN_INTERVAL) > now) {
return;
}
if (!mProcessesToGc.contains(app)) {
}
}
- final void checkExcessivePowerUsageLocked(boolean doKills) {
+ final void checkExcessivePowerUsageLocked() {
updateCpuStatsNow();
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- boolean doWakeKills = doKills;
- boolean doCpuKills = doKills;
- if (mLastPowerCheckRealtime == 0) {
- doWakeKills = false;
- }
+ boolean doCpuKills = true;
if (mLastPowerCheckUptime == 0) {
doCpuKills = false;
}
- if (stats.isScreenOn()) {
- doWakeKills = false;
- }
- final long curRealtime = SystemClock.elapsedRealtime();
- final long realtimeSince = curRealtime - mLastPowerCheckRealtime;
final long curUptime = SystemClock.uptimeMillis();
final long uptimeSince = curUptime - mLastPowerCheckUptime;
- mLastPowerCheckRealtime = curRealtime;
mLastPowerCheckUptime = curUptime;
- if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) {
- doWakeKills = false;
- }
- if (uptimeSince < CPU_MIN_CHECK_DURATION) {
- doCpuKills = false;
- }
int i = mLruProcesses.size();
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
- long wtime;
- synchronized (stats) {
- wtime = stats.getProcessWakeTime(app.info.uid,
- app.pid, curRealtime);
+ if (app.lastCpuTime <= 0) {
+ continue;
}
- long wtimeUsed = wtime - app.lastWakeTime;
long cputimeUsed = app.curCpuTime - app.lastCpuTime;
if (DEBUG_POWER) {
StringBuilder sb = new StringBuilder(128);
- sb.append("Wake for ");
- app.toShortString(sb);
- sb.append(": over ");
- TimeUtils.formatDuration(realtimeSince, sb);
- sb.append(" used ");
- TimeUtils.formatDuration(wtimeUsed, sb);
- sb.append(" (");
- sb.append((wtimeUsed*100)/realtimeSince);
- sb.append("%)");
- Slog.i(TAG_POWER, sb.toString());
- sb.setLength(0);
sb.append("CPU for ");
app.toShortString(sb);
sb.append(": over ");
sb.append("%)");
Slog.i(TAG_POWER, sb.toString());
}
- // If a process has held a wake lock for more
- // than 50% of the time during this period,
- // that sounds bad. Kill!
- if (doWakeKills && realtimeSince > 0
- && ((wtimeUsed*100)/realtimeSince) >= 50) {
- synchronized (stats) {
- stats.reportExcessiveWakeLocked(app.info.uid, app.processName,
- realtimeSince, wtimeUsed);
+ // If the process has used too much CPU over the last duration, the
+ // user probably doesn't want this, so kill!
+ if (doCpuKills && uptimeSince > 0) {
+ // What is the limit for this process?
+ int cpuLimit;
+ long checkDur = curUptime - app.whenUnimportant;
+ if (checkDur <= mConstants.POWER_CHECK_INTERVAL) {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1;
+ } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*2)
+ || app.setProcState <= ActivityManager.PROCESS_STATE_HOME) {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2;
+ } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*3)) {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3;
+ } else {
+ cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;
}
- app.kill("excessive wake held " + wtimeUsed + " during " + realtimeSince, true);
- app.baseProcessTracker.reportExcessiveWake(app.pkgList);
- } else if (doCpuKills && uptimeSince > 0
- && ((cputimeUsed*100)/uptimeSince) >= 25) {
- synchronized (stats) {
- stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
- uptimeSince, cputimeUsed);
+ if (((cputimeUsed*100)/uptimeSince) >= cpuLimit) {
+ synchronized (stats) {
+ stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
+ uptimeSince, cputimeUsed);
+ }
+ app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
+ + " dur=" + checkDur + " limit=" + cpuLimit, true);
+ app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
}
- app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince, true);
- app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
- } else {
- app.lastWakeTime = wtime;
- app.lastCpuTime = app.curCpuTime;
}
+ app.lastCpuTime = app.curCpuTime;
}
}
}
int changes = 0;
if (app.curAdj != app.setAdj) {
- ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
- + app.adjType);
+ ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.info.uid) {
+ String msg = "Set " + app.pid + " " + app.processName + " adj "
+ + app.curAdj + ": " + app.adjType;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+ }
app.setAdj = app.curAdj;
app.verifiedAdj = ProcessList.INVALID_ADJ;
}
if (app.setSchedGroup != app.curSchedGroup) {
int oldSchedGroup = app.setSchedGroup;
app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Setting sched group of " + app.processName
- + " to " + app.curSchedGroup);
- if (app.waitingToKill != null && app.curReceiver == null
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
+ String msg = "Setting sched group of " + app.processName
+ + " to " + app.curSchedGroup + ": " + app.adjType;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+ }
+ if (app.waitingToKill != null && app.curReceivers.isEmpty()
&& app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
app.kill(app.waitingToKill, true);
success = false;
int processGroup;
switch (app.curSchedGroup) {
case ProcessList.SCHED_GROUP_BACKGROUND:
- processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
break;
case ProcessList.SCHED_GROUP_TOP_APP:
case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
- processGroup = Process.THREAD_GROUP_TOP_APP;
+ processGroup = THREAD_GROUP_TOP_APP;
+ break;
+ case ProcessList.SCHED_GROUP_RESTRICTED:
+ processGroup = THREAD_GROUP_RESTRICTED;
break;
default:
- processGroup = Process.THREAD_GROUP_DEFAULT;
+ processGroup = THREAD_GROUP_DEFAULT;
break;
}
long oldId = Binder.clearCallingIdentity();
try {
- Process.setProcessGroup(app.pid, processGroup);
+ setProcessGroup(app.pid, processGroup);
if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
// do nothing if we already switched to RT
if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
- // Switch VR thread for app to SCHED_FIFO
- if (mInVrMode && app.vrThreadTid != 0) {
- try {
- Process.setThreadScheduler(app.vrThreadTid,
- Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
- } catch (IllegalArgumentException e) {
- // thread died, ignore
- }
- }
+ mVrController.onTopProcChangedLocked(app);
if (mUseFifoUiScheduling) {
// Switch UI pipeline for app to SCHED_FIFO
app.savedPriority = Process.getThreadPriority(app.pid);
- try {
- Process.setThreadScheduler(app.pid,
- Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
- } catch (IllegalArgumentException e) {
- // thread died, ignore
- }
+ scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
if (app.renderThreadTid != 0) {
- try {
- Process.setThreadScheduler(app.renderThreadTid,
- Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
- } catch (IllegalArgumentException e) {
- // thread died, ignore
- }
+ scheduleAsFifoPriority(app.renderThreadTid,
+ /* suppressLogs */true);
if (DEBUG_OOM_ADJ) {
Slog.d("UI_FIFO", "Set RenderThread (TID " +
app.renderThreadTid + ") to FIFO");
}
} else {
// Boost priority for top app UI and render threads
- Process.setThreadPriority(app.pid, -10);
+ setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
if (app.renderThreadTid != 0) {
try {
- Process.setThreadPriority(app.renderThreadTid, -10);
+ setThreadPriority(app.renderThreadTid,
+ TOP_APP_PRIORITY_BOOST);
} catch (IllegalArgumentException e) {
// thread died, ignore
}
}
} else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
app.curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
- // Reset VR thread to SCHED_OTHER
- // Safe to do even if we're not in VR mode
- if (app.vrThreadTid != 0) {
- Process.setThreadScheduler(app.vrThreadTid, Process.SCHED_OTHER, 0);
- }
+ mVrController.onTopProcChangedLocked(app);
if (mUseFifoUiScheduling) {
- // Reset UI pipeline to SCHED_OTHER
- Process.setThreadScheduler(app.pid, Process.SCHED_OTHER, 0);
- Process.setThreadPriority(app.pid, app.savedPriority);
- if (app.renderThreadTid != 0) {
- Process.setThreadScheduler(app.renderThreadTid,
- Process.SCHED_OTHER, 0);
- Process.setThreadPriority(app.renderThreadTid, -4);
+ try {
+ // Reset UI pipeline to SCHED_OTHER
+ setThreadScheduler(app.pid, SCHED_OTHER, 0);
+ setThreadPriority(app.pid, app.savedPriority);
+ if (app.renderThreadTid != 0) {
+ setThreadScheduler(app.renderThreadTid,
+ SCHED_OTHER, 0);
+ setThreadPriority(app.renderThreadTid, -4);
+ }
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG,
+ "Failed to set scheduling policy, thread does not exist:\n"
+ + e);
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
}
} else {
// Reset priority for top app UI and render threads
- Process.setThreadPriority(app.pid, 0);
+ setThreadPriority(app.pid, 0);
if (app.renderThreadTid != 0) {
- Process.setThreadPriority(app.renderThreadTid, 0);
+ setThreadPriority(app.renderThreadTid, 0);
}
}
}
} catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
+ if (false) {
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ Slog.w(TAG, "at location", e);
+ }
} finally {
Binder.restoreCallingIdentity(oldId);
}
}
if (app.repProcState != app.curProcState) {
app.repProcState = app.curProcState;
- changes |= ProcessChangeItem.CHANGE_PROCESS_STATE;
if (app.thread != null) {
try {
if (false) {
// Experimental code to more aggressively collect pss while
// running test... the problem is that this tends to collect
// the data right when a process is transitioning between process
- // states, which well tend to give noisy data.
+ // states, which will tend to give noisy data.
long start = SystemClock.uptimeMillis();
+ long startTime = SystemClock.currentThreadTimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
- recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], mTmpLong[1], now);
+ long endTime = SystemClock.currentThreadTimeMillis();
+ recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], mTmpLong[1],
+ mTmpLong[2], ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
mPendingPssProcesses.remove(app);
Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+ " to " + app.curProcState + ": "
+ (SystemClock.uptimeMillis()-start) + "ms");
}
app.lastStateTime = now;
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mTestPssMode, isSleepingLocked(), now);
+ app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.curProcState) + " next pss in "
if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
&& now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
mTestPssMode)))) {
- requestPssLocked(app, app.setProcState);
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
- mTestPssMode, isSleepingLocked(), now);
+ if (requestPssLocked(app, app.setProcState)) {
+ app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
+ }
} else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
- "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
+ "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
}
if (app.setProcState != app.curProcState) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
- "Proc state change of " + app.processName
- + " to " + app.curProcState);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
+ String msg = "Proc state change of " + app.processName
+ + " to " + ProcessList.makeProcStateString(app.curProcState)
+ + " (" + app.curProcState + ")" + ": " + app.adjType;
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+ }
boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
boolean curImportant = app.curProcState < ActivityManager.PROCESS_STATE_SERVICE;
if (setImportant && !curImportant) {
// This app is no longer something we consider important enough to allow to
// use arbitrary amounts of battery power. Note
- // its current wake lock time to later know to kill it if
+ // its current CPU time to later know to kill it if
// it is not behaving well.
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
- app.pid, nowElapsed);
- }
- app.lastCpuTime = app.curCpuTime;
-
+ app.whenUnimportant = now;
+ app.lastCpuTime = 0;
}
// Inform UsageStats of important process state change
// Must be called before updating setProcState
maybeUpdateUsageStatsLocked(app, nowElapsed);
+ maybeUpdateLastTopTime(app, now);
+
app.setProcState = app.curProcState;
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
app.notCachedSinceIdle = false;
app.procStateChanged = true;
}
} else if (app.reportedInteraction && (nowElapsed-app.interactionEventTime)
- > USAGE_STATS_INTERACTION_INTERVAL) {
+ > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
// For apps that sit around for a long time in the interactive state, we need
// to report this at least once a day so they don't go idle.
maybeUpdateUsageStatsLocked(app, nowElapsed);
mPendingProcessChanges.add(item);
}
item.changes |= changes;
- item.processState = app.repProcState;
item.foregroundActivities = app.repForegroundActivities;
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Item " + Integer.toHexString(System.identityHashCode(item))
+ " " + app.toShortString() + ": changes=" + item.changes
- + " procState=" + item.processState
+ " foreground=" + item.foregroundActivities
+ " type=" + app.adjType + " source=" + app.adjSource
+ " target=" + app.adjTarget);
return success;
}
- private final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
+ private boolean isEphemeralLocked(int uid) {
+ String packages[] = mContext.getPackageManager().getPackagesForUid(uid);
+ if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid
+ return false;
+ }
+ return getPackageManagerInternalLocked().isPackageEphemeral(UserHandle.getUserId(uid),
+ packages[0]);
+ }
+
+ @VisibleForTesting
+ final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) {
final UidRecord.ChangeItem pendingChange;
if (uidRec == null || uidRec.pendingChange == null) {
if (mPendingUidChanges.size() == 0) {
}
if (uidRec != null) {
uidRec.pendingChange = pendingChange;
- if (change == UidRecord.CHANGE_GONE && !uidRec.idle) {
+ if ((change & UidRecord.CHANGE_GONE) != 0 && !uidRec.idle) {
// If this uid is going away, and we haven't yet reported it is gone,
// then do so now.
- change = UidRecord.CHANGE_GONE_IDLE;
+ change |= UidRecord.CHANGE_IDLE;
}
} else if (uid < 0) {
throw new IllegalArgumentException("No UidRecord or uid");
mPendingUidChanges.add(pendingChange);
} else {
pendingChange = uidRec.pendingChange;
- if (change == UidRecord.CHANGE_GONE && pendingChange.change == UidRecord.CHANGE_IDLE) {
- change = UidRecord.CHANGE_GONE_IDLE;
+ // If there is no change in idle or active state, then keep whatever was pending.
+ if ((change & (UidRecord.CHANGE_IDLE | UidRecord.CHANGE_ACTIVE)) == 0) {
+ change |= (pendingChange.change & (UidRecord.CHANGE_IDLE
+ | UidRecord.CHANGE_ACTIVE));
+ }
+ // If there is no change in cached or uncached state, then keep whatever was pending.
+ if ((change & (UidRecord.CHANGE_CACHED | UidRecord.CHANGE_UNCACHED)) == 0) {
+ change |= (pendingChange.change & (UidRecord.CHANGE_CACHED
+ | UidRecord.CHANGE_UNCACHED));
+ }
+ // If this is a report of the UID being gone, then we shouldn't keep any previous
+ // report of it being active or cached. (That is, a gone uid is never active,
+ // and never cached.)
+ if ((change & UidRecord.CHANGE_GONE) != 0) {
+ change &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED);
+ if (!uidRec.idle) {
+ // If this uid is going away, and we haven't yet reported it is gone,
+ // then do so now.
+ change |= UidRecord.CHANGE_IDLE;
+ }
}
}
pendingChange.change = change;
pendingChange.processState = uidRec != null
? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+ pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid);
+ pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
+ if (uidRec != null) {
+ uidRec.lastReportedChange = change;
+ uidRec.updateLastDispatchedProcStateSeq(change);
+ }
+
+ // Directly update the power manager, since we sit on top of it and it is critical
+ // it be kept in sync (so wake locks will be held as soon as appropriate).
+ if (mLocalPowerManager != null) {
+ // TO DO: dispatch cached/uncached changes here, so we don't need to report
+ // all proc state changes.
+ if ((change & UidRecord.CHANGE_ACTIVE) != 0) {
+ mLocalPowerManager.uidActive(pendingChange.uid);
+ }
+ if ((change & UidRecord.CHANGE_IDLE) != 0) {
+ mLocalPowerManager.uidIdle(pendingChange.uid);
+ }
+ if ((change & UidRecord.CHANGE_GONE) != 0) {
+ mLocalPowerManager.uidGone(pendingChange.uid);
+ } else {
+ mLocalPowerManager.updateUidProcState(pendingChange.uid,
+ pendingChange.processState);
+ }
+ }
}
private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
String authority) {
if (app == null) return;
if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- UserState userState = mUserController.getStartedUserStateLocked(app.userId);
+ UserState userState = mUserController.getStartedUserState(app.userId);
if (userState == null) return;
final long now = SystemClock.elapsedRealtime();
Long lastReported = userState.mProviderLastReportedFg.get(authority);
// To avoid some abuse patterns, we are going to be careful about what we consider
// to be an app interaction. Being the top activity doesn't count while the display
// is sleeping, nor do short foreground services.
- if (app.curProcState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP) {
isInteraction = true;
app.fgInteractionTime = 0;
- } else if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
+ } else if (app.curProcState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
if (app.fgInteractionTime == 0) {
app.fgInteractionTime = nowElapsed;
isInteraction = false;
} else {
- isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
+ isInteraction = nowElapsed > app.fgInteractionTime
+ + mConstants.SERVICE_USAGE_INTERACTION_TIME;
}
} else {
- // If the app was being forced to the foreground, by say a Toast, then
- // no need to treat it as an interaction
- isInteraction = app.forcingToForeground == null
- && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.fgInteractionTime = 0;
}
- if (isInteraction && (!app.reportedInteraction
- || (nowElapsed-app.interactionEventTime) > USAGE_STATS_INTERACTION_INTERVAL)) {
+ if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
+ > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
app.interactionEventTime = nowElapsed;
String[] packages = app.getPackageList();
if (packages != null) {
}
}
+ private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
+ if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
+ && app.curProcState > ActivityManager.PROCESS_STATE_TOP) {
+ app.lastTopTime = nowUptime;
+ }
+ }
+
private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
if (proc.thread != null) {
if (proc.baseProcessTracker != null) {
return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
}
+ @GuardedBy("this")
final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
boolean oomAdj) {
if (isForeground != proc.foregroundServices) {
}
private final ActivityRecord resumedAppLocked() {
- ActivityRecord act = mStackSupervisor.resumedAppLocked();
+ ActivityRecord act = mStackSupervisor.getResumedActivityLocked();
String pkg;
int uid;
if (act != null) {
return act;
}
- final boolean updateOomAdjLocked(ProcessRecord app) {
+ /**
+ * Update OomAdj for a specific process.
+ * @param app The process to update
+ * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
+ * if necessary, or skip.
+ * @return whether updateOomAdjLocked(app) was successful.
+ */
+ @GuardedBy("this")
+ final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final boolean wasCached = app.cached;
? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());
- if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
+ if (oomAdjAll
+ && (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ)) {
// Changed to/from cached state, so apps after it in the LRU
// list may also be changed.
updateOomAdjLocked();
return success;
}
+ @GuardedBy("this")
final void updateOomAdjLocked() {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
mNewNumServiceProcs = 0;
mNewNumAServiceProcs = 0;
- final int emptyProcessLimit;
- final int cachedProcessLimit;
- if (mProcessLimit <= 0) {
- emptyProcessLimit = cachedProcessLimit = 0;
- } else if (mProcessLimit == 1) {
- emptyProcessLimit = 1;
- cachedProcessLimit = 0;
- } else {
- emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);
- cachedProcessLimit = mProcessLimit - emptyProcessLimit;
- }
+ final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
+ final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit;
// Let's determine how many processes we have running vs.
// how many slots we have for background processes; we may want
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
+
+ boolean retryCycles = false;
+
+ // need to reset cycle state before calling computeOomAdjLocked because of service connections
+ for (int i=N-1; i>=0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ app.containsCycle = false;
+ }
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (app == null) {
- continue;
- }
if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+ // if any app encountered a cycle, we need to perform an additional loop later
+ retryCycles |= app.containsCycle;
+
// If we haven't yet assigned the final cached adj
// to the process, do that now.
if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
switch (app.curProcState) {
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ case ActivityManager.PROCESS_STATE_CACHED_RECENT:
// This process is a cached process holding activities...
// assign it the next cached value for that type, and then
// step that cached level.
}
}
- applyOomAdjLocked(app, true, now, nowElapsed);
- // Count the number of process types.
- switch (app.curProcState) {
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- mNumCachedHiddenProcs++;
- numCached++;
- if (numCached > cachedProcessLimit) {
- app.kill("cached #" + numCached, true);
+ }
+ }
+
+ // Cycle strategy:
+ // - Retry computing any process that has encountered a cycle.
+ // - Continue retrying until no process was promoted.
+ // - Iterate from least important to most important.
+ int cycleCount = 0;
+ while (retryCycles && cycleCount < 10) {
+ cycleCount++;
+ retryCycles = false;
+
+ for (int i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+ app.adjSeq--;
+ app.completedAdjSeq--;
+ }
+ }
+
+ for (int i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+
+ if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
+ retryCycles = true;
+ }
+ }
+ }
+ }
+
+ for (int i=N-1; i>=0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (!app.killedByAm && app.thread != null) {
+ applyOomAdjLocked(app, true, now, nowElapsed);
+
+ // Count the number of process types.
+ switch (app.curProcState) {
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ mNumCachedHiddenProcs++;
+ numCached++;
+ if (numCached > cachedProcessLimit) {
+ app.kill("cached #" + numCached, true);
}
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- if (numEmpty > ProcessList.TRIM_EMPTY_APPS
+ if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
&& app.lastActivityTime < oldTime) {
app.kill("empty for "
+ ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
break;
}
- if (app.isolated && app.services.size() <= 0) {
- // If this is an isolated process, and there are no
- // services running in it, then the process is no longer
+ if (app.isolated && app.services.size() <= 0 && app.isolatedEntryPoint == null) {
+ // If this is an isolated process, there are no services
+ // running in it, and it's not a special process with a
+ // custom entry point, then the process is no longer
// needed. We agressively kill these because we can by
// definition not re-use the same process again, and it is
// good to avoid having whatever code was running in them
} else {
// Keeping this process, update its uid.
final UidRecord uidRec = app.uidRecord;
- if (uidRec != null && uidRec.curProcState > app.curProcState) {
- uidRec.curProcState = app.curProcState;
+ if (uidRec != null) {
+ uidRec.ephemeral = app.info.isInstantApp();
+ if (uidRec.curProcState > app.curProcState) {
+ uidRec.curProcState = app.curProcState;
+ }
+ if (app.foregroundServices) {
+ uidRec.foregroundServices = true;
+ }
}
}
}
}
+ incrementProcStateSeqAndNotifyAppsLocked();
+
mNumServiceProcs = mNewNumServiceProcs;
// Now determine the memory trimming level of background processes.
// memory they want.
final int numCachedAndEmpty = numCached + numEmpty;
int memFactor;
- if (numCached <= ProcessList.TRIM_CACHED_APPS
- && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
+ if (numCached <= mConstants.CUR_TRIM_CACHED_PROCESSES
+ && numEmpty <= mConstants.CUR_TRIM_EMPTY_PROCESSES) {
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (app == null) {
- continue;
- }
if (allChanged || app.procStateChanged) {
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
break;
}
}
- } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
+ } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ && !app.killedByAm) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
}
+ ArrayList<UidRecord> becameIdle = null;
+
// Update from any uid changes.
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.startUidChanges();
+ }
for (int i=mActiveUids.size()-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
int uidChange = UidRecord.CHANGE_PROCSTATE;
- if (uidRec.setProcState != uidRec.curProcState) {
+ if (uidRec.curProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
+ && (uidRec.setProcState != uidRec.curProcState
+ || uidRec.setWhitelist != uidRec.curWhitelist)) {
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
"Changes in " + uidRec + ": proc state from " + uidRec.setProcState
- + " to " + uidRec.curProcState);
- if (ActivityManager.isProcStateBackground(uidRec.curProcState)) {
- if (!ActivityManager.isProcStateBackground(uidRec.setProcState)) {
+ + " to " + uidRec.curProcState + ", whitelist from " + uidRec.setWhitelist
+ + " to " + uidRec.curWhitelist);
+ if (ActivityManager.isProcStateBackground(uidRec.curProcState)
+ && !uidRec.curWhitelist) {
+ // UID is now in the background (and not on the temp whitelist). Was it
+ // previously in the foreground (or on the temp whitelist)?
+ if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
+ || uidRec.setWhitelist) {
uidRec.lastBackgroundTime = nowElapsed;
if (!mHandler.hasMessages(IDLE_UIDS_MSG)) {
// Note: the background settle time is in elapsed realtime, while
// the handler time base is uptime. All this means is that we may
// stop background uids later than we had intended, but that only
// happens because the device was sleeping so we are okay anyway.
- mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG, BACKGROUND_SETTLE_TIME);
+ mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+ mConstants.BACKGROUND_SETTLE_TIME);
}
}
+ if (uidRec.idle && !uidRec.setIdle) {
+ uidChange = UidRecord.CHANGE_IDLE;
+ if (becameIdle == null) {
+ becameIdle = new ArrayList<>();
+ }
+ becameIdle.add(uidRec);
+ }
} else {
if (uidRec.idle) {
uidChange = UidRecord.CHANGE_ACTIVE;
+ EventLogTags.writeAmUidActive(uidRec.uid);
uidRec.idle = false;
}
uidRec.lastBackgroundTime = 0;
}
+ final boolean wasCached = uidRec.setProcState
+ > ActivityManager.PROCESS_STATE_RECEIVER;
+ final boolean isCached = uidRec.curProcState
+ > ActivityManager.PROCESS_STATE_RECEIVER;
+ if (wasCached != isCached ||
+ uidRec.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
+ }
uidRec.setProcState = uidRec.curProcState;
+ uidRec.setWhitelist = uidRec.curWhitelist;
+ uidRec.setIdle = uidRec.idle;
enqueueUidChangeLocked(uidRec, -1, uidChange);
noteUidProcessState(uidRec.uid, uidRec.curProcState);
+ if (uidRec.foregroundServices) {
+ mServices.foregroundServiceProcStateChangedLocked(uidRec);
+ }
+ }
+ }
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.finishUidChanges();
+ }
+
+ if (becameIdle != null) {
+ // If we have any new uids that became idle this time, we need to make sure
+ // they aren't left with running services.
+ for (int i = becameIdle.size() - 1; i >= 0; i--) {
+ mServices.stopInBackgroundLocked(becameIdle.get(i).uid);
}
}
}
}
+ @Override
+ public void makePackageIdle(String packageName, int userId) {
+ if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: makePackageIdle() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ final int callingPid = Binder.getCallingPid();
+ userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
+ userId, true, ALLOW_FULL_ONLY, "makePackageIdle", null);
+ long callingId = Binder.clearCallingIdentity();
+ synchronized(this) {
+ try {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ int pkgUid = -1;
+ try {
+ pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES
+ | MATCH_DEBUG_TRIAGED_MISSING, UserHandle.USER_SYSTEM);
+ } catch (RemoteException e) {
+ }
+ if (pkgUid == -1) {
+ throw new IllegalArgumentException("Unknown package name " + packageName);
+ }
+
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.startUidChanges();
+ }
+ final int appId = UserHandle.getAppId(pkgUid);
+ final int N = mActiveUids.size();
+ for (int i=N-1; i>=0; i--) {
+ final UidRecord uidRec = mActiveUids.valueAt(i);
+ final long bgTime = uidRec.lastBackgroundTime;
+ if (bgTime > 0 && !uidRec.idle) {
+ if (UserHandle.getAppId(uidRec.uid) == appId) {
+ if (userId == UserHandle.USER_ALL ||
+ userId == UserHandle.getUserId(uidRec.uid)) {
+ EventLogTags.writeAmUidIdle(uidRec.uid);
+ uidRec.idle = true;
+ uidRec.setIdle = true;
+ Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
+ + " from package " + packageName + " user " + userId);
+ doStopUidLocked(uidRec.uid, uidRec);
+ }
+ }
+ }
+ }
+ } finally {
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.finishUidChanges();
+ }
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+ }
+
final void idleUids() {
synchronized (this) {
+ final int N = mActiveUids.size();
+ if (N <= 0) {
+ return;
+ }
final long nowElapsed = SystemClock.elapsedRealtime();
- final long maxBgTime = nowElapsed - BACKGROUND_SETTLE_TIME;
+ final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
long nextTime = 0;
- for (int i=mActiveUids.size()-1; i>=0; i--) {
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.startUidChanges();
+ }
+ for (int i=N-1; i>=0; i--) {
final UidRecord uidRec = mActiveUids.valueAt(i);
final long bgTime = uidRec.lastBackgroundTime;
if (bgTime > 0 && !uidRec.idle) {
if (bgTime <= maxBgTime) {
+ EventLogTags.writeAmUidIdle(uidRec.uid);
uidRec.idle = true;
+ uidRec.setIdle = true;
doStopUidLocked(uidRec.uid, uidRec);
} else {
if (nextTime == 0 || nextTime > bgTime) {
}
}
}
+ if (mLocalPowerManager != null) {
+ mLocalPowerManager.finishUidChanges();
+ }
if (nextTime > 0) {
mHandler.removeMessages(IDLE_UIDS_MSG);
mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
- nextTime + BACKGROUND_SETTLE_TIME - nowElapsed);
+ nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
+ }
+ }
+ }
+
+ /**
+ * Checks if any uid is coming from background to foreground or vice versa and if so, increments
+ * the {@link UidRecord#curProcStateSeq} corresponding to that uid using global seq counter
+ * {@link #mProcStateSeqCounter} and notifies the app if it needs to block.
+ */
+ @VisibleForTesting
+ @GuardedBy("this")
+ void incrementProcStateSeqAndNotifyAppsLocked() {
+ if (mWaitForNetworkTimeoutMs <= 0) {
+ return;
+ }
+ // Used for identifying which uids need to block for network.
+ ArrayList<Integer> blockingUids = null;
+ for (int i = mActiveUids.size() - 1; i >= 0; --i) {
+ final UidRecord uidRec = mActiveUids.valueAt(i);
+ // If the network is not restricted for uid, then nothing to do here.
+ if (!mInjector.isNetworkRestrictedForUid(uidRec.uid)) {
+ continue;
+ }
+ if (!UserHandle.isApp(uidRec.uid) || !uidRec.hasInternetPermission) {
+ continue;
+ }
+ // If process state is not changed, then there's nothing to do.
+ if (uidRec.setProcState == uidRec.curProcState) {
+ continue;
+ }
+ final int blockState = getBlockStateForUid(uidRec);
+ // No need to inform the app when the blockState is NETWORK_STATE_NO_CHANGE as
+ // there's nothing the app needs to do in this scenario.
+ if (blockState == NETWORK_STATE_NO_CHANGE) {
+ continue;
+ }
+ synchronized (uidRec.networkStateLock) {
+ uidRec.curProcStateSeq = ++mProcStateSeqCounter;
+ if (blockState == NETWORK_STATE_BLOCK) {
+ if (blockingUids == null) {
+ blockingUids = new ArrayList<>();
+ }
+ blockingUids.add(uidRec.uid);
+ } else {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "uid going to background, notifying all blocking"
+ + " threads for uid: " + uidRec);
+ }
+ if (uidRec.waitingForNetwork) {
+ uidRec.networkStateLock.notifyAll();
+ }
+ }
+ }
+ }
+
+ // There are no uids that need to block, so nothing more to do.
+ if (blockingUids == null) {
+ return;
+ }
+
+ for (int i = mLruProcesses.size() - 1; i >= 0; --i) {
+ final ProcessRecord app = mLruProcesses.get(i);
+ if (!blockingUids.contains(app.uid)) {
+ continue;
}
+ if (!app.killedByAm && app.thread != null) {
+ final UidRecord uidRec = mActiveUids.get(app.uid);
+ try {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Informing app thread that it needs to block: "
+ + uidRec);
+ }
+ app.thread.setNetworkBlockSeq(uidRec.curProcStateSeq);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the uid is coming from background to foreground or vice versa and returns
+ * appropriate block state based on this.
+ *
+ * @return blockState based on whether the uid is coming from background to foreground or
+ * vice versa. If bg->fg or fg->bg, then {@link #NETWORK_STATE_BLOCK} or
+ * {@link #NETWORK_STATE_UNBLOCK} respectively, otherwise
+ * {@link #NETWORK_STATE_NO_CHANGE}.
+ */
+ @VisibleForTesting
+ int getBlockStateForUid(UidRecord uidRec) {
+ // Denotes whether uid's process state is currently allowed network access.
+ final boolean isAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.curProcState)
+ || isProcStateAllowedWhileOnRestrictBackground(uidRec.curProcState);
+ // Denotes whether uid's process state was previously allowed network access.
+ final boolean wasAllowed = isProcStateAllowedWhileIdleOrPowerSaveMode(uidRec.setProcState)
+ || isProcStateAllowedWhileOnRestrictBackground(uidRec.setProcState);
+
+ // When the uid is coming to foreground, AMS should inform the app thread that it should
+ // block for the network rules to get updated before launching an activity.
+ if (!wasAllowed && isAllowed) {
+ return NETWORK_STATE_BLOCK;
}
+ // When the uid is going to background, AMS should inform the app thread that if an
+ // activity launch is blocked for the network rules to get updated, it should be unblocked.
+ if (wasAllowed && !isAllowed) {
+ return NETWORK_STATE_UNBLOCK;
+ }
+ return NETWORK_STATE_NO_CHANGE;
}
final void runInBackgroundDisabled(int uid) {
}
}
+ /**
+ * Call {@link #doStopUidLocked} (which will also stop background services) for all idle UIDs.
+ */
+ void doStopUidForIdleUidsLocked() {
+ final int size = mActiveUids.size();
+ for (int i = 0; i < size; i++) {
+ final int uid = mActiveUids.keyAt(i);
+ if (UserHandle.isCore(uid)) {
+ continue;
+ }
+ final UidRecord uidRec = mActiveUids.valueAt(i);
+ if (!uidRec.idle) {
+ continue;
+ }
+ doStopUidLocked(uidRec.uid, uidRec);
+ }
+ }
+
final void doStopUidLocked(int uid, final UidRecord uidRec) {
mServices.stopInBackgroundLocked(uid);
enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
}
- final void trimApplications() {
- synchronized (this) {
- int i;
+ /**
+ * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
+ */
+ @GuardedBy("this")
+ void tempWhitelistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
+ long duration, String tag) {
+ if (DEBUG_WHITELISTS) {
+ Slog.d(TAG, "tempWhitelistForPendingIntentLocked(" + callerPid + ", " + callerUid + ", "
+ + targetUid + ", " + duration + ")");
+ }
- // First remove any unused application processes whose package
- // has been removed.
- for (i=mRemovedProcesses.size()-1; i>=0; i--) {
- final ProcessRecord app = mRemovedProcesses.get(i);
- if (app.activities.size() == 0
- && app.curReceiver == null && app.services.size() == 0) {
- Slog.i(
- TAG, "Exiting empty application process "
- + app.toShortString() + " ("
- + (app.thread != null ? app.thread.asBinder() : null)
- + ")\n");
- if (app.pid > 0 && app.pid != MY_PID) {
- app.kill("empty", false);
- } else {
- try {
- app.thread.scheduleExit();
- } catch (Exception e) {
- // Ignore exceptions.
- }
+ synchronized (mPidsSelfLocked) {
+ final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
+ if (pr == null) {
+ Slog.w(TAG, "tempWhitelistForPendingIntentLocked() no ProcessRecord for pid "
+ + callerPid);
+ return;
+ }
+ if (!pr.whitelistManager) {
+ if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid)
+ != PackageManager.PERMISSION_GRANTED) {
+ if (DEBUG_WHITELISTS) {
+ Slog.d(TAG, "tempWhitelistForPendingIntentLocked() for target " + targetUid
+ + ": pid " + callerPid + " is not allowed");
}
- cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
- mRemovedProcesses.remove(i);
+ return;
+ }
+ }
+ }
- if (app.persistent) {
- addAppLocked(app.info, false, null /* ABI override */);
- }
+ tempWhitelistUidLocked(targetUid, duration, tag);
+ }
+
+ /**
+ * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
+ */
+ @GuardedBy("this")
+ void tempWhitelistUidLocked(int targetUid, long duration, String tag) {
+ mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag));
+ setUidTempWhitelistStateLocked(targetUid, true);
+ mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget();
+ }
+
+ void pushTempWhitelist() {
+ final int N;
+ final PendingTempWhitelist[] list;
+
+ // First copy out the pending changes... we need to leave them in the map for now,
+ // in case someone needs to check what is coming up while we don't have the lock held.
+ synchronized(this) {
+ N = mPendingTempWhitelist.size();
+ list = new PendingTempWhitelist[N];
+ for (int i = 0; i < N; i++) {
+ list[i] = mPendingTempWhitelist.valueAt(i);
+ }
+ }
+
+ // Now safely dispatch changes to device idle controller.
+ for (int i = 0; i < N; i++) {
+ PendingTempWhitelist ptw = list[i];
+ mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid,
+ ptw.duration, true, ptw.tag);
+ }
+
+ // And now we can safely remove them from the map.
+ synchronized(this) {
+ for (int i = 0; i < N; i++) {
+ PendingTempWhitelist ptw = list[i];
+ int index = mPendingTempWhitelist.indexOfKey(ptw.targetUid);
+ if (index >= 0 && mPendingTempWhitelist.valueAt(index) == ptw) {
+ mPendingTempWhitelist.removeAt(index);
}
}
+ }
+ }
+
+ @GuardedBy("this")
+ final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
+ boolean changed = false;
+ for (int i=mActiveUids.size()-1; i>=0; i--) {
+ final UidRecord uidRec = mActiveUids.valueAt(i);
+ if (UserHandle.getAppId(uidRec.uid) == appId && uidRec.curWhitelist != onWhitelist) {
+ uidRec.curWhitelist = onWhitelist;
+ changed = true;
+ }
+ }
+ if (changed) {
+ updateOomAdjLocked();
+ }
+ }
- // Now update the oom adj for all processes.
+ @GuardedBy("this")
+ final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
+ boolean changed = false;
+ final UidRecord uidRec = mActiveUids.get(uid);
+ if (uidRec != null && uidRec.curWhitelist != onWhitelist) {
+ uidRec.curWhitelist = onWhitelist;
updateOomAdjLocked();
}
}
+ final void trimApplications() {
+ synchronized (this) {
+ trimApplicationsLocked();
+ }
+ }
+
+ final void trimApplicationsLocked() {
+ // First remove any unused application processes whose package
+ // has been removed.
+ for (int i=mRemovedProcesses.size()-1; i>=0; i--) {
+ final ProcessRecord app = mRemovedProcesses.get(i);
+ if (app.activities.size() == 0 && app.recentTasks.size() == 0
+ && app.curReceivers.isEmpty() && app.services.size() == 0) {
+ Slog.i(
+ TAG, "Exiting empty application process "
+ + app.toShortString() + " ("
+ + (app.thread != null ? app.thread.asBinder() : null)
+ + ")\n");
+ if (app.pid > 0 && app.pid != MY_PID) {
+ app.kill("empty", false);
+ } else if (app.thread != null) {
+ try {
+ app.thread.scheduleExit();
+ } catch (Exception e) {
+ // Ignore exceptions.
+ }
+ }
+ cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
+ mRemovedProcesses.remove(i);
+
+ if (app.persistent) {
+ addAppLocked(app.info, null, false, null /* ABI override */);
+ }
+ }
+ }
+
+ // Now update the oom adj for all processes. Don't skip this, since other callers
+ // might be depending on it.
+ updateOomAdjLocked();
+ }
+
/** This method sends the specified signal to each of the persistent apps */
public void signalPersistentProcesses(int sig) throws RemoteException {
- if (sig != Process.SIGNAL_USR1) {
+ if (sig != SIGNAL_USR1) {
throw new SecurityException("Only SIGNAL_USR1 is allowed");
}
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r.thread != null && r.persistent) {
- Process.sendSignal(r.pid, sig);
+ sendSignal(r.pid, sig);
}
}
}
}
private void clearProfilerLocked() {
- if (mProfileFd != null) {
+ if (mProfilerInfo !=null && mProfilerInfo.profileFd != null) {
try {
- mProfileFd.close();
+ mProfilerInfo.profileFd.close();
} catch (IOException e) {
}
}
mProfileApp = null;
mProfileProc = null;
- mProfileFile = null;
- mProfileType = 0;
- mAutoStopProfiler = false;
- mSamplingInterval = 0;
+ mProfilerInfo = null;
}
public boolean profileControl(String process, int userId, boolean start,
profilerInfo.profileFd = fd;
proc.thread.profilerControl(start, profilerInfo, profileType);
fd = null;
- mProfileFd = null;
+ try {
+ mProfilerInfo.profileFd.close();
+ } catch (IOException e) {
+ }
+ mProfilerInfo.profileFd = null;
+
+ if (proc.pid == MY_PID) {
+ // When profiling the system server itself, avoid closing the file
+ // descriptor, as profilerControl will not create a copy.
+ // Note: it is also not correct to just set profileFd to null, as the
+ // whole ProfilerInfo instance is passed down!
+ profilerInfo = null;
+ }
} else {
stopProfilerLocked(proc, profileType);
if (profilerInfo != null && profilerInfo.profileFd != null) {
return proc;
}
- public boolean dumpHeap(String process, int userId, boolean managed,
- String path, ParcelFileDescriptor fd) throws RemoteException {
+ public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo,
+ boolean runGc, String path, ParcelFileDescriptor fd) throws RemoteException {
try {
synchronized (this) {
}
}
- proc.thread.dumpHeap(managed, path, fd);
+ proc.thread.dumpHeap(managed, mallocInfo, runGc, path, fd);
fd = null;
return true;
}
}
if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+
+ // Forced gc to clean up the remnant hprof fd.
+ Runtime.getRuntime().gc();
}
}
*/
@Override
public boolean startUserInBackground(final int userId) {
- return mUserController.startUser(userId, /* foreground */ false);
+ return startUserInBackgroundWithListener(userId, null);
+ }
+
+ @Override
+ public boolean startUserInBackgroundWithListener(final int userId,
+ @Nullable IProgressListener unlockListener) {
+ return mUserController.startUser(userId, /* foreground */ false, unlockListener);
}
@Override
@Override
public boolean switchUser(final int targetUserId) {
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId);
- UserInfo currentUserInfo;
- UserInfo targetUserInfo;
- synchronized (this) {
- int currentUserId = mUserController.getCurrentUserIdLocked();
- currentUserInfo = mUserController.getUserInfo(currentUserId);
- targetUserInfo = mUserController.getUserInfo(targetUserId);
- if (targetUserInfo == null) {
- Slog.w(TAG, "No user info for user #" + targetUserId);
- return false;
- }
- if (!targetUserInfo.isDemo() && UserManager.isDeviceInDemoMode(mContext)) {
- Slog.w(TAG, "Cannot switch to non-demo user #" + targetUserId
- + " when device is in demo mode");
- return false;
- }
- if (!targetUserInfo.supportsSwitchTo()) {
- Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
- return false;
- }
- if (targetUserInfo.isManagedProfile()) {
- Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
- return false;
- }
- mUserController.setTargetUserIdLocked(targetUserId);
- }
- Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
- mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG);
- mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_UI_MSG, userNames));
- return true;
- }
-
- void scheduleStartProfilesLocked() {
- if (!mHandler.hasMessages(START_PROFILES_MSG)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
- DateUtils.SECOND_IN_MILLIS);
- }
+ return mUserController.switchUser(targetUserId);
}
@Override
return mUserController.getCurrentUser();
}
+ String getStartedUserState(int userId) {
+ final UserState userState = mUserController.getStartedUserState(userId);
+ return UserState.stateToString(userState.state);
+ }
+
@Override
public boolean isUserRunning(int userId, int flags) {
if (!mUserController.isSameProfileGroup(userId, UserHandle.getCallingUserId())
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- synchronized (this) {
- return mUserController.isUserRunningLocked(userId, flags);
- }
+ return mUserController.isUserRunning(userId, flags);
}
@Override
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- synchronized (this) {
- return mUserController.getStartedUserArrayLocked();
- }
+ return mUserController.getStartedUserArray();
}
@Override
}
public boolean isUserStopped(int userId) {
- synchronized (this) {
- return mUserController.getStartedUserStateLocked(userId) == null;
- }
+ return mUserController.getStartedUserState(userId) == null;
}
ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
try {
TransferPipe tp = new TransferPipe();
try {
- process.thread.stopBinderTrackingAndDump(
- tp.getWriteFd().getFileDescriptor());
+ process.thread.stopBinderTrackingAndDump(tp.getWriteFd());
tp.go(fd.getFileDescriptor());
} finally {
tp.kill();
}
}
- private final class LocalService extends ActivityManagerInternal {
+ @VisibleForTesting
+ final class LocalService extends ActivityManagerInternal {
@Override
public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent,
int targetUserId) {
}
@Override
- public int startIsolatedProcess(String entryPoint, String[] entryPointArgs,
+ public boolean startIsolatedProcess(String entryPoint, String[] entryPointArgs,
String processName, String abiOverride, int uid, Runnable crashHandler) {
return ActivityManagerService.this.startIsolatedProcess(entryPoint, entryPointArgs,
processName, abiOverride, uid, crashHandler);
}
@Override
- public SleepToken acquireSleepToken(String tag) {
+ public SleepToken acquireSleepToken(String tag, int displayId) {
Preconditions.checkNotNull(tag);
-
- synchronized (ActivityManagerService.this) {
- SleepTokenImpl token = new SleepTokenImpl(tag);
- mSleepTokens.add(token);
- updateSleepIfNeededLocked();
- return token;
- }
+ return ActivityManagerService.this.acquireSleepToken(tag, displayId);
}
@Override
synchronized (ActivityManagerService.this) {
ActivityManagerService.this.onUserStoppedLocked(userId);
}
+ mBatteryStatsService.onUserRemoved(userId);
+ mUserController.onUserRemoved(userId);
}
@Override
}
@Override
- public void notifyStartingWindowDrawn() {
+ public void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp) {
synchronized (ActivityManagerService.this) {
- mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn();
- }
- }
-
- @Override
- public void notifyAppTransitionStarting(int reason) {
- synchronized (ActivityManagerService.this) {
- mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(reason);
+ mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
+ reasons, timestamp);
}
}
}
@Override
- public void setPendingIntentWhitelistDuration(IIntentSender target, long duration) {
+ public void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
+ long duration) {
if (!(target instanceof PendingIntentRecord)) {
Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
return;
}
- ((PendingIntentRecord) target).setWhitelistDuration(duration);
+ synchronized (ActivityManagerService.this) {
+ ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration);
+ }
}
@Override
- public void updatePersistentConfigurationForUser(@NonNull Configuration values,
- int userId) {
- Preconditions.checkNotNull(values, "Configuration must not be null");
- Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported");
+ public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
synchronized (ActivityManagerService.this) {
- updateConfigurationLocked(values, null, false, true, userId,
- false /* deferResume */);
+ mDeviceIdleWhitelist = allAppids;
+ mDeviceIdleExceptIdleWhitelist = exceptIdleAppids;
}
}
@Override
- public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
- Bundle bOptions) {
- Preconditions.checkNotNull(intents, "intents");
- final String[] resolvedTypes = new String[intents.length];
- for (int i = 0; i < intents.length; i++) {
- resolvedTypes[i] = intents[i].resolveTypeIfNeeded(mContext.getContentResolver());
+ public void updateDeviceIdleTempWhitelist(int[] appids, int changingAppId, boolean adding) {
+ synchronized (ActivityManagerService.this) {
+ mDeviceIdleTempWhitelist = appids;
+ setAppIdTempWhitelistStateLocked(changingAppId, adding);
}
+ }
+
+ @Override
+ public void updatePersistentConfigurationForUser(@NonNull Configuration values,
+ int userId) {
+ Preconditions.checkNotNull(values, "Configuration must not be null");
+ Preconditions.checkArgumentNonnegative(userId, "userId " + userId + " not supported");
+ synchronized (ActivityManagerService.this) {
+ updateConfigurationLocked(values, null, false, true, userId,
+ false /* deferResume */);
+ }
+ }
+
+ @Override
+ public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
+ Bundle bOptions) {
+ Preconditions.checkNotNull(intents, "intents");
+ final String[] resolvedTypes = new String[intents.length];
// UID of the package on user userId.
// "= 0" is needed because otherwise catch(RemoteException) would make it look like
// packageUid may not be initialized.
int packageUid = 0;
+ final long ident = Binder.clearCallingIdentity();
+
try {
+ for (int i = 0; i < intents.length; i++) {
+ resolvedTypes[i] =
+ intents[i].resolveTypeIfNeeded(mContext.getContentResolver());
+ }
+
packageUid = AppGlobals.getPackageManager().getPackageUid(
packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
} catch (RemoteException e) {
// Shouldn't happen.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
synchronized (ActivityManagerService.this) {
- return startActivitiesInPackage(packageUid, packageName, intents, resolvedTypes,
- /*resultTo*/ null, bOptions, userId);
+ return mActivityStartController.startActivitiesInPackage(
+ packageUid, packageName,
+ intents, resolvedTypes, null /* resultTo */,
+ SafeActivityOptions.fromBundle(bOptions), userId,
+ false /* validateIncomingUser */, null /* originatingPendingIntent */);
}
}
@Override
+ public int startActivityAsUser(IApplicationThread caller, String callerPacakge,
+ Intent intent, Bundle options, int userId) {
+ return ActivityManagerService.this.startActivityAsUser(
+ caller, callerPacakge, intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, userId,
+ false /*validateIncomingUser*/);
+ }
+
+ @Override
public int getUidProcessState(int uid) {
return getUidState(uid);
}
- }
- private final class SleepTokenImpl extends SleepToken {
- private final String mTag;
- private final long mAcquireTime;
+ @Override
+ public void notifyKeyguardFlagsChanged(@Nullable Runnable callback) {
+ synchronized (ActivityManagerService.this) {
+
+ // We might change the visibilities here, so prepare an empty app transition which
+ // might be overridden later if we actually change visibilities.
+ final boolean wasTransitionSet =
+ mWindowManager.getPendingAppTransition() != TRANSIT_NONE;
+ if (!wasTransitionSet) {
+ mWindowManager.prepareAppTransition(TRANSIT_NONE,
+ false /* alwaysKeepCurrent */);
+ }
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- public SleepTokenImpl(String tag) {
- mTag = tag;
- mAcquireTime = SystemClock.uptimeMillis();
+ // If there was a transition set already we don't want to interfere with it as we
+ // might be starting it too early.
+ if (!wasTransitionSet) {
+ mWindowManager.executeAppTransition();
+ }
+ }
+ if (callback != null) {
+ callback.run();
+ }
}
@Override
- public void release() {
+ public boolean isSystemReady() {
+ // no need to synchronize(this) just to read & return the value
+ return mSystemReady;
+ }
+
+ @Override
+ public void notifyKeyguardTrustedChanged() {
synchronized (ActivityManagerService.this) {
- if (mSleepTokens.remove(this)) {
- updateSleepIfNeededLocked();
+ if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
}
+ /**
+ * Sets if the given pid has an overlay UI or not.
+ *
+ * @param pid The pid we are setting overlay UI for.
+ * @param hasOverlayUi True if the process has overlay UI.
+ * @see android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY
+ */
@Override
- public String toString() {
- return "{\"" + mTag + "\", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
+ public void setHasOverlayUi(int pid, boolean hasOverlayUi) {
+ synchronized (ActivityManagerService.this) {
+ final ProcessRecord pr;
+ synchronized (mPidsSelfLocked) {
+ pr = mPidsSelfLocked.get(pid);
+ if (pr == null) {
+ Slog.w(TAG, "setHasOverlayUi called on unknown pid: " + pid);
+ return;
+ }
+ }
+ if (pr.hasOverlayUi == hasOverlayUi) {
+ return;
+ }
+ pr.hasOverlayUi = hasOverlayUi;
+ //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
+ updateOomAdjLocked(pr, true);
+ }
}
- }
- /**
- * An implementation of IAppTask, that allows an app to manage its own tasks via
- * {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that
- * only the process that calls getAppTasks() can call the AppTask methods.
- */
- class AppTaskImpl extends IAppTask.Stub {
- private int mTaskId;
- private int mCallingUid;
+ @Override
+ public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) {
+ ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation);
+ }
- public AppTaskImpl(int taskId, int callingUid) {
- mTaskId = taskId;
- mCallingUid = callingUid;
+ /**
+ * Called after the network policy rules are updated by
+ * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid}
+ * and {@param procStateSeq}.
+ */
+ @Override
+ public void notifyNetworkPolicyRulesUpdated(int uid, long procStateSeq) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Got update from NPMS for uid: "
+ + uid + " seq: " + procStateSeq);
+ }
+ UidRecord record;
+ synchronized (ActivityManagerService.this) {
+ record = mActiveUids.get(uid);
+ if (record == null) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "No active uidRecord for uid: " + uid
+ + " procStateSeq: " + procStateSeq);
+ }
+ return;
+ }
+ }
+ synchronized (record.networkStateLock) {
+ if (record.lastNetworkUpdatedProcStateSeq >= procStateSeq) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "procStateSeq: " + procStateSeq + " has already"
+ + " been handled for uid: " + uid);
+ }
+ return;
+ }
+ record.lastNetworkUpdatedProcStateSeq = procStateSeq;
+ if (record.curProcStateSeq > procStateSeq) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "No need to handle older seq no., Uid: " + uid
+ + ", curProcstateSeq: " + record.curProcStateSeq
+ + ", procStateSeq: " + procStateSeq);
+ }
+ return;
+ }
+ if (record.waitingForNetwork) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Notifying all blocking threads for uid: " + uid
+ + ", procStateSeq: " + procStateSeq);
+ }
+ record.networkStateLock.notifyAll();
+ }
+ }
}
- private void checkCaller() {
- if (mCallingUid != Binder.getCallingUid()) {
- throw new SecurityException("Caller " + mCallingUid
- + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+ @Override
+ public void notifyActiveVoiceInteractionServiceChanged(ComponentName component) {
+ synchronized (ActivityManagerService.this) {
+ mActiveVoiceInteractionServiceComponent = component;
}
}
+ /**
+ * Called after virtual display Id is updated by
+ * {@link com.android.server.vr.Vr2dDisplay} with a specific
+ * {@param vrVr2dDisplayId}.
+ */
@Override
- public void finishAndRemoveTask() {
- checkCaller();
+ public void setVr2dDisplayId(int vr2dDisplayId) {
+ if (DEBUG_STACK) {
+ Slog.d(TAG, "setVr2dDisplayId called for: " +
+ vr2dDisplayId);
+ }
+ synchronized (ActivityManagerService.this) {
+ mVr2dDisplayId = vr2dDisplayId;
+ }
+ }
+ @Override
+ public void saveANRState(String reason) {
synchronized (ActivityManagerService.this) {
- long origId = Binder.clearCallingIdentity();
- try {
- // We remove the task from recents to preserve backwards
- if (!removeTaskByIdLocked(mTaskId, false, REMOVE_FROM_RECENTS)) {
- throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new FastPrintWriter(sw, false, 1024);
+ pw.println(" ANR time: " + DateFormat.getDateTimeInstance().format(new Date()));
+ if (reason != null) {
+ pw.println(" Reason: " + reason);
}
+ pw.println();
+ mActivityStartController.dump(pw, " ", null);
+ pw.println();
+ pw.println("-------------------------------------------------------------------------------");
+ dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
+ true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
+ "" /* header */);
+ pw.println();
+ pw.close();
+
+ mLastANRState = sw.toString();
}
}
@Override
- public ActivityManager.RecentTaskInfo getTaskInfo() {
- checkCaller();
+ public void clearSavedANRState() {
+ synchronized (ActivityManagerService.this) {
+ mLastANRState = null;
+ }
+ }
+ @Override
+ public void setFocusedActivity(IBinder token) {
synchronized (ActivityManagerService.this) {
- long origId = Binder.clearCallingIdentity();
- try {
- TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
- if (tr == null) {
- throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
- }
- return createRecentTaskInfoFromTaskRecord(tr);
- } finally {
- Binder.restoreCallingIdentity(origId);
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (r == null) {
+ throw new IllegalArgumentException(
+ "setFocusedActivity: No activity record matching token=" + token);
+ }
+ if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(
+ r, "setFocusedActivity")) {
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@Override
- public void moveToFront() {
- checkCaller();
- // Will bring task to front if it already has a root activity.
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- mStackSupervisor.startActivityFromRecentsInner(mTaskId, null);
+ public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
+ synchronized (ActivityManagerService.this) {
+ if (mUserController.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(userId);
+ if (types == null) {
+ if (uid < 0) {
+ return;
+ }
+ types = new ArrayMap<>();
+ mAllowAppSwitchUids.put(userId, types);
+ }
+ if (uid < 0) {
+ types.remove(type);
+ } else {
+ types.put(type, uid);
+ }
}
- } finally {
- Binder.restoreCallingIdentity(origId);
}
}
@Override
- public int startActivity(IBinder whoThread, String callingPackage,
- Intent intent, String resolvedType, Bundle bOptions) {
- checkCaller();
+ public boolean isRuntimeRestarted() {
+ return mSystemServiceManager.isRuntimeRestarted();
+ }
+
+ @Override
+ public boolean hasRunningActivity(int uid, @Nullable String packageName) {
+ if (packageName == null) return false;
- int callingUser = UserHandle.getCallingUserId();
- TaskRecord tr;
- IApplicationThread appThread;
synchronized (ActivityManagerService.this) {
- tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
- if (tr == null) {
- throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
- }
- appThread = ApplicationThreadNative.asInterface(whoThread);
- if (appThread == null) {
- throw new IllegalArgumentException("Bad app thread " + appThread);
+ for (int i = 0; i < mLruProcesses.size(); i++) {
+ final ProcessRecord processRecord = mLruProcesses.get(i);
+ if (processRecord.uid == uid) {
+ for (int j = 0; j < processRecord.activities.size(); j++) {
+ final ActivityRecord activityRecord = processRecord.activities.get(j);
+ if (packageName.equals(activityRecord.packageName)) {
+ return true;
+ }
+ }
+ }
}
}
- return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
- resolvedType, null, null, null, null, 0, 0, null, null,
- null, bOptions, false, callingUser, null, tr);
+ return false;
+ }
+
+ @Override
+ public void registerScreenObserver(ScreenObserver observer) {
+ mScreenObservers.add(observer);
+ }
+
+ @Override
+ public boolean canStartMoreUsers() {
+ return mUserController.canStartMoreUsers();
}
@Override
- public void setExcludeFromRecents(boolean exclude) {
- checkCaller();
+ public void setSwitchingFromSystemUserMessage(String switchingFromSystemUserMessage) {
+ mUserController.setSwitchingFromSystemUserMessage(switchingFromSystemUserMessage);
+ }
+ @Override
+ public void setSwitchingToSystemUserMessage(String switchingToSystemUserMessage) {
+ mUserController.setSwitchingToSystemUserMessage(switchingToSystemUserMessage);
+ }
+
+ @Override
+ public int getMaxRunningUsers() {
+ return mUserController.mMaxRunningUsers;
+ }
+
+ @Override
+ public boolean isCallerRecents(int callingUid) {
+ return getRecentTasks().isCallerRecents(callingUid);
+ }
+
+ @Override
+ public boolean isRecentsComponentHomeActivity(int userId) {
+ return getRecentTasks().isRecentsComponentHomeActivity(userId);
+ }
+
+ @Override
+ public void cancelRecentsAnimation(boolean restoreHomeStackPosition) {
+ ActivityManagerService.this.cancelRecentsAnimation(restoreHomeStackPosition);
+ }
+
+ @Override
+ public boolean isUidActive(int uid) {
synchronized (ActivityManagerService.this) {
- long origId = Binder.clearCallingIdentity();
- try {
- TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(mTaskId);
- if (tr == null) {
- throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
+ return isUidActiveLocked(uid);
+ }
+ }
+
+ @Override
+ public List<ProcessMemoryState> getMemoryStateForProcesses() {
+ List<ProcessMemoryState> processMemoryStates = new ArrayList<>();
+ synchronized (mPidsSelfLocked) {
+ for (int i = 0, size = mPidsSelfLocked.size(); i < size; i++) {
+ final ProcessRecord r = mPidsSelfLocked.valueAt(i);
+ final int pid = r.pid;
+ final int uid = r.uid;
+ final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid);
+ if (memoryStat == null) {
+ continue;
}
- Intent intent = tr.getBaseIntent();
- if (exclude) {
- intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- } else {
- intent.setFlags(intent.getFlags()
- & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ ProcessMemoryState processMemoryState =
+ new ProcessMemoryState(uid,
+ r.processName,
+ r.maxAdj,
+ memoryStat.pgfault,
+ memoryStat.pgmajfault,
+ memoryStat.rssInBytes,
+ memoryStat.cacheInBytes,
+ memoryStat.swapInBytes);
+ processMemoryStates.add(processMemoryState);
+ }
+ }
+ return processMemoryStates;
+ }
+
+ @Override
+ public void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
+ ActivityManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func);
+ }
+
+ @Override
+ public Intent getHomeIntent() {
+ synchronized (ActivityManagerService.this) {
+ return ActivityManagerService.this.getHomeIntent();
+ }
+ }
+
+ @Override
+ public void notifyDefaultDisplaySizeChanged() {
+ synchronized (ActivityManagerService.this) {
+ if (mSystemServiceManager.isBootCompleted() && mHomeProcess != null) {
+
+ // TODO: Ugly hack to unblock the release
+ Slog.i(TAG, "Killing home process because of display size change");
+ removeProcessLocked(mHomeProcess, false, true, "kill home screen size");
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by app main thread to wait for the network policy rules to get updated.
+ *
+ * @param procStateSeq The sequence number indicating the process state change that the main
+ * thread is interested in.
+ */
+ @Override
+ public void waitForNetworkStateUpdate(long procStateSeq) {
+ final int callingUid = Binder.getCallingUid();
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Called from " + callingUid + " to wait for seq: " + procStateSeq);
+ }
+ UidRecord record;
+ synchronized (this) {
+ record = mActiveUids.get(callingUid);
+ if (record == null) {
+ return;
+ }
+ }
+ synchronized (record.networkStateLock) {
+ if (record.lastDispatchedProcStateSeq < procStateSeq) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Uid state change for seq no. " + procStateSeq + " is not "
+ + "dispatched to NPMS yet, so don't wait. Uid: " + callingUid
+ + " lastProcStateSeqDispatchedToObservers: "
+ + record.lastDispatchedProcStateSeq);
+ }
+ return;
+ }
+ if (record.curProcStateSeq > procStateSeq) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Ignore the wait requests for older seq numbers. Uid: "
+ + callingUid + ", curProcStateSeq: " + record.curProcStateSeq
+ + ", procStateSeq: " + procStateSeq);
+ }
+ return;
+ }
+ if (record.lastNetworkUpdatedProcStateSeq >= procStateSeq) {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Network rules have been already updated for seq no. "
+ + procStateSeq + ", so no need to wait. Uid: "
+ + callingUid + ", lastProcStateSeqWithUpdatedNetworkState: "
+ + record.lastNetworkUpdatedProcStateSeq);
+ }
+ return;
+ }
+ try {
+ if (DEBUG_NETWORK) {
+ Slog.d(TAG_NETWORK, "Starting to wait for the network rules update."
+ + " Uid: " + callingUid + " procStateSeq: " + procStateSeq);
+ }
+ final long startTime = SystemClock.uptimeMillis();
+ record.waitingForNetwork = true;
+ record.networkStateLock.wait(mWaitForNetworkTimeoutMs);
+ record.waitingForNetwork = false;
+ final long totalTime = SystemClock.uptimeMillis() - startTime;
+ if (totalTime >= mWaitForNetworkTimeoutMs || DEBUG_NETWORK) {
+ Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: "
+ + totalTime + ". Uid: " + callingUid + " procStateSeq: "
+ + procStateSeq + " UidRec: " + record
+ + " validateUidRec: " + mValidateUids.get(callingUid));
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void waitForBroadcastIdle(PrintWriter pw) {
+ enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
+ while (true) {
+ boolean idle = true;
+ synchronized (this) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ if (!queue.isIdle()) {
+ final String msg = "Waiting for queue " + queue + " to become idle...";
+ pw.println(msg);
+ pw.flush();
+ Slog.v(TAG, msg);
+ idle = false;
}
- } finally {
- Binder.restoreCallingIdentity(origId);
}
}
+
+ if (idle) {
+ final String msg = "All broadcast queues are idle!";
+ pw.println(msg);
+ pw.flush();
+ Slog.v(TAG, msg);
+ return;
+ } else {
+ SystemClock.sleep(1000);
+ }
+ }
+ }
+
+ /**
+ * Return the user id of the last resumed activity.
+ */
+ @Override
+ public @UserIdInt int getLastResumedActivityUserId() {
+ enforceCallingPermission(
+ permission.INTERACT_ACROSS_USERS_FULL, "getLastResumedActivityUserId()");
+ synchronized (this) {
+ if (mLastResumedActivity == null) {
+ return mUserController.getCurrentUserId();
+ }
+ return mLastResumedActivity.userId;
}
}
}
@Override
- public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException {
- final int userId = intent.getCreatorUserHandle().getIdentifier();
- if (!mUserController.isUserRunningLocked(userId, ActivityManager.FLAG_AND_LOCKED)) {
- return false;
+ public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback,
+ CharSequence message) throws RemoteException {
+ if (message != null) {
+ enforceCallingPermission(permission.SHOW_KEYGUARD_MESSAGE,
+ "dismissKeyguard()");
}
- IIntentSender target = intent.getTarget();
- if (!(target instanceof PendingIntentRecord)) {
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ mKeyguardController.dismissKeyguard(token, callback, message);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ @Override
+ public int restartUserInBackground(final int userId) {
+ return mUserController.restartUser(userId, /* foreground */ false);
+ }
+
+ @Override
+ public void scheduleApplicationInfoChanged(List<String> packageNames, int userId) {
+ enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+ "scheduleApplicationInfoChanged()");
+
+ synchronized (this) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ updateApplicationInfoLocked(packageNames, userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
+ final boolean updateFrameworkRes = packagesToUpdate.contains("android");
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord app = mLruProcesses.get(i);
+ if (app.thread == null) {
+ continue;
+ }
+
+ if (userId != UserHandle.USER_ALL && app.userId != userId) {
+ continue;
+ }
+
+ final int packageCount = app.pkgList.size();
+ for (int j = 0; j < packageCount; j++) {
+ final String packageName = app.pkgList.keyAt(j);
+ if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
+ try {
+ final ApplicationInfo ai = AppGlobals.getPackageManager()
+ .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
+ if (ai != null) {
+ app.thread.scheduleApplicationInfoChanged(ai);
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
+ packageName, app));
+ }
+ }
+ }
+ }
+ if (updateFrameworkRes) {
+ // Update system server components that need to know about changed overlays. Because the
+ // overlay is applied in ActivityThread, we need to serialize through its thread too.
+ final Executor executor = ActivityThread.currentActivityThread().getExecutor();
+ final DisplayManagerInternal display =
+ LocalServices.getService(DisplayManagerInternal.class);
+ if (display != null) {
+ executor.execute(display::onOverlayChanged);
+ }
+ if (mWindowManager != null) {
+ executor.execute(mWindowManager::onOverlayChanged);
+ }
+ }
+ }
+
+ /**
+ * Attach an agent to the specified process (proces name or PID)
+ */
+ public void attachAgent(String process, String path) {
+ try {
+ synchronized (this) {
+ ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, "attachAgent");
+ if (proc == null || proc.thread == null) {
+ throw new IllegalArgumentException("Unknown process: " + process);
+ }
+
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + proc);
+ }
+ }
+
+ proc.thread.attachAgent(path);
+ }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Process disappeared");
+ }
+ }
+
+ @VisibleForTesting
+ public static class Injector {
+ private NetworkManagementInternal mNmi;
+
+ public Context getContext() {
+ return null;
+ }
+
+ public AppOpsService getAppOpsService(File file, Handler handler) {
+ return new AppOpsService(file, handler);
+ }
+
+ public Handler getUiHandler(ActivityManagerService service) {
+ return service.new UiHandler();
+ }
+
+ public boolean isNetworkRestrictedForUid(int uid) {
+ if (ensureHasNetworkManagementInternal()) {
+ return mNmi.isNetworkRestrictedForUid(uid);
+ }
return false;
}
- final PendingIntentRecord record = (PendingIntentRecord) target;
- final ResolveInfo rInfo = mStackSupervisor.resolveIntent(record.key.requestIntent,
- record.key.requestResolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE);
- // For direct boot aware activities, they can be shown without triggering a work challenge
- // before the profile user is unlocked.
- return rInfo != null && rInfo.activityInfo != null;
+
+ private boolean ensureHasNetworkManagementInternal() {
+ if (mNmi == null) {
+ mNmi = LocalServices.getService(NetworkManagementInternal.class);
+ }
+ return mNmi != null;
+ }
+ }
+
+ @Override
+ public void setShowWhenLocked(IBinder token, boolean showWhenLocked)
+ throws RemoteException {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ r.setShowWhenLocked(showWhenLocked);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ @Override
+ public void setTurnScreenOn(IBinder token, boolean turnScreenOn) throws RemoteException {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ r.setTurnScreenOn(turnScreenOn);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ @Override
+ public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition)
+ throws RemoteException {
+ enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ "registerRemoteAnimations");
+ definition.setCallingPid(Binder.getCallingPid());
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ r.registerRemoteAnimations(definition);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ @Override
+ public void registerRemoteAnimationForNextActivityStart(String packageName,
+ RemoteAnimationAdapter adapter) throws RemoteException {
+ enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+ "registerRemoteAnimationForNextActivityStart");
+ adapter.setCallingPid(Binder.getCallingPid());
+ synchronized (this) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mActivityStartController.registerRemoteAnimationForNextActivityStart(packageName,
+ adapter);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
+ @Override
+ public void alwaysShowUnsupportedCompileSdkWarning(ComponentName activity) {
+ synchronized (this) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mAppWarnings.alwaysShowUnsupportedCompileSdkWarning(activity);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
}
}