| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.am; |
| |
| import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; |
| import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.UserIdInt; |
| import android.app.ActivityManagerInternal; |
| import android.app.AppOpsManager; |
| import android.app.role.RoleManager; |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManagerInternal; |
| import android.media.session.MediaSessionManager; |
| import android.os.BatteryManagerInternal; |
| import android.os.BatteryStatsInternal; |
| import android.os.Handler; |
| import android.os.ServiceManager; |
| import android.permission.PermissionManager; |
| import android.util.Slog; |
| import android.util.proto.ProtoOutputStream; |
| |
| import com.android.internal.app.IAppOpsService; |
| import com.android.server.DeviceIdleInternal; |
| import com.android.server.LocalServices; |
| import com.android.server.am.AppRestrictionController.TrackerType; |
| import com.android.server.notification.NotificationManagerInternal; |
| import com.android.server.pm.UserManagerInternal; |
| import com.android.server.pm.permission.PermissionManagerServiceInternal; |
| |
| import java.io.PrintWriter; |
| import java.lang.reflect.Constructor; |
| import java.util.ArrayList; |
| |
| /** |
| * Base class to track certain state of the app, could be used to determine the restriction level. |
| * |
| * @param <T> A class derived from BaseAppStatePolicy. |
| */ |
| public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> { |
| protected static final String TAG = TAG_WITH_CLASS_NAME ? "BaseAppStatePolicy" : TAG_AM; |
| |
| static final long ONE_MINUTE = 60 * 1_000L; |
| static final long ONE_HOUR = 60 * ONE_MINUTE; |
| static final long ONE_DAY = 24 * ONE_HOUR; |
| |
| static final int STATE_TYPE_MEDIA_SESSION = 1; |
| static final int STATE_TYPE_FGS_MEDIA_PLAYBACK = 1 << 1; |
| static final int STATE_TYPE_FGS_LOCATION = 1 << 2; |
| static final int STATE_TYPE_FGS_WITH_NOTIFICATION = 1 << 3; |
| static final int STATE_TYPE_PERMISSION = 1 << 4; |
| static final int STATE_TYPE_NUM = 5; |
| |
| static final int STATE_TYPE_INDEX_MEDIA_SESSION = 0; |
| static final int STATE_TYPE_INDEX_FGS_MEDIA_PLAYBACK = 1; |
| static final int STATE_TYPE_INDEX_FGS_LOCATION = 2; |
| static final int STATE_TYPE_INDEX_FGS_WITH_NOTIFICATION = 3; |
| static final int STATE_TYPE_INDEX_PERMISSION = 4; |
| |
| protected final AppRestrictionController mAppRestrictionController; |
| protected final Injector<T> mInjector; |
| protected final Context mContext; |
| protected final Handler mBgHandler; |
| protected final Object mLock; |
| protected final ArrayList<StateListener> mStateListeners = new ArrayList<>(); |
| |
| interface StateListener { |
| void onStateChange(int uid, String packageName, boolean start, long now, int stateType); |
| } |
| |
| BaseAppStateTracker(Context context, AppRestrictionController controller, |
| @Nullable Constructor<? extends Injector<T>> injector, Object outerContext) { |
| mContext = context; |
| mAppRestrictionController = controller; |
| mBgHandler = controller.getBackgroundHandler(); |
| mLock = controller.getLock(); |
| if (injector == null) { |
| mInjector = new Injector<>(); |
| } else { |
| Injector<T> localInjector = null; |
| try { |
| localInjector = injector.newInstance(outerContext); |
| } catch (Exception e) { |
| Slog.w(TAG, "Unable to instantiate " + injector, e); |
| } |
| mInjector = (localInjector == null) ? new Injector<>() : localInjector; |
| } |
| } |
| |
| static int stateTypeToIndex(int stateType) { |
| return Integer.numberOfTrailingZeros(stateType); |
| } |
| |
| static int stateIndexToType(int stateTypeIndex) { |
| return 1 << stateTypeIndex; |
| } |
| |
| static String stateTypesToString(int stateTypes) { |
| final StringBuilder sb = new StringBuilder("["); |
| boolean needDelimiter = false; |
| for (int stateType = Integer.highestOneBit(stateTypes); stateType != 0; |
| stateType = Integer.highestOneBit(stateTypes)) { |
| if (needDelimiter) { |
| sb.append('|'); |
| } |
| needDelimiter = true; |
| switch (stateType) { |
| case STATE_TYPE_MEDIA_SESSION: |
| sb.append("MEDIA_SESSION"); |
| break; |
| case STATE_TYPE_FGS_MEDIA_PLAYBACK: |
| sb.append("FGS_MEDIA_PLAYBACK"); |
| break; |
| case STATE_TYPE_FGS_LOCATION: |
| sb.append("FGS_LOCATION"); |
| break; |
| case STATE_TYPE_FGS_WITH_NOTIFICATION: |
| sb.append("FGS_NOTIFICATION"); |
| break; |
| case STATE_TYPE_PERMISSION: |
| sb.append("PERMISSION"); |
| break; |
| default: |
| return "[UNKNOWN(" + Integer.toHexString(stateTypes) + ")]"; |
| } |
| stateTypes &= ~stateType; |
| } |
| sb.append("]"); |
| return sb.toString(); |
| } |
| |
| void registerStateListener(@NonNull StateListener listener) { |
| synchronized (mLock) { |
| mStateListeners.add(listener); |
| } |
| } |
| |
| void notifyListenersOnStateChange(int uid, String packageName, |
| boolean start, long now, int stateType) { |
| synchronized (mLock) { |
| for (int i = 0, size = mStateListeners.size(); i < size; i++) { |
| mStateListeners.get(i).onStateChange(uid, packageName, start, now, stateType); |
| } |
| } |
| } |
| |
| /** |
| * Return the type of tracker (as defined by AppRestrictionController.TrackerType) |
| */ |
| @TrackerType int getType() { |
| return AppRestrictionController.TRACKER_TYPE_UNKNOWN; |
| } |
| |
| /** |
| * Return the relevant info object for the tracker for the given uid, used for statsd. |
| */ |
| byte[] getTrackerInfoForStatsd(int uid) { |
| return null; |
| } |
| |
| /** |
| * Return the policy holder of this tracker. |
| */ |
| T getPolicy() { |
| return mInjector.getPolicy(); |
| } |
| |
| /** |
| * Called when the system is ready to rock. |
| */ |
| void onSystemReady() { |
| mInjector.onSystemReady(); |
| } |
| |
| /** |
| * Called when a user with the given uid is added. |
| */ |
| void onUidAdded(final int uid) { |
| } |
| |
| /** |
| * Called when a user with the given uid is removed. |
| */ |
| void onUidRemoved(final int uid) { |
| } |
| |
| /** |
| * Called when a user with the given userId is added. |
| */ |
| void onUserAdded(final @UserIdInt int userId) { |
| } |
| |
| /** |
| * Called when a user with the given userId is started. |
| */ |
| void onUserStarted(final @UserIdInt int userId) { |
| } |
| |
| /** |
| * Called when a user with the given userId is stopped. |
| */ |
| void onUserStopped(final @UserIdInt int userId) { |
| } |
| |
| /** |
| * Called when a user with the given userId is removed. |
| */ |
| void onUserRemoved(final @UserIdInt int userId) { |
| } |
| |
| /** |
| * Called when the system sends LOCKED_BOOT_COMPLETED. |
| */ |
| void onLockedBootCompleted() { |
| } |
| |
| /** |
| * Called when a device config property in the activity manager namespace |
| * has changed. |
| */ |
| void onPropertiesChanged(@NonNull String name) { |
| getPolicy().onPropertiesChanged(name); |
| } |
| |
| /** |
| * Called when an app has transitioned into an active state due to user interaction. |
| */ |
| void onUserInteractionStarted(String packageName, int uid) { |
| } |
| |
| /** |
| * Called when the background restriction settings of the given app is changed. |
| */ |
| void onBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted) { |
| } |
| |
| /** |
| * Called when the process state of the given UID has been changed. |
| * |
| * <p>Note: as of now, for simplification, we're tracking the TOP state changes only.</p> |
| */ |
| void onUidProcStateChanged(int uid, int procState) { |
| } |
| |
| /** |
| * Called when all the processes in the given UID have died. |
| */ |
| void onUidGone(int uid) { |
| } |
| |
| /** |
| * Dump to the given printer writer. |
| */ |
| void dump(PrintWriter pw, String prefix) { |
| mInjector.getPolicy().dump(pw, " " + prefix); |
| } |
| |
| void dumpAsProto(ProtoOutputStream proto, int uid) { |
| } |
| |
| static class Injector<T extends BaseAppStatePolicy> { |
| T mAppStatePolicy; |
| |
| ActivityManagerInternal mActivityManagerInternal; |
| BatteryManagerInternal mBatteryManagerInternal; |
| BatteryStatsInternal mBatteryStatsInternal; |
| DeviceIdleInternal mDeviceIdleInternal; |
| UserManagerInternal mUserManagerInternal; |
| PackageManager mPackageManager; |
| PackageManagerInternal mPackageManagerInternal; |
| PermissionManager mPermissionManager; |
| PermissionManagerServiceInternal mPermissionManagerServiceInternal; |
| AppOpsManager mAppOpsManager; |
| MediaSessionManager mMediaSessionManager; |
| RoleManager mRoleManager; |
| NotificationManagerInternal mNotificationManagerInternal; |
| IAppOpsService mIAppOpsService; |
| |
| void setPolicy(T policy) { |
| mAppStatePolicy = policy; |
| } |
| |
| void onSystemReady() { |
| mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); |
| mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class); |
| mBatteryStatsInternal = LocalServices.getService(BatteryStatsInternal.class); |
| mDeviceIdleInternal = LocalServices.getService(DeviceIdleInternal.class); |
| mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); |
| mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); |
| mPermissionManagerServiceInternal = LocalServices.getService( |
| PermissionManagerServiceInternal.class); |
| final Context context = mAppStatePolicy.mTracker.mContext; |
| mPackageManager = context.getPackageManager(); |
| mAppOpsManager = context.getSystemService(AppOpsManager.class); |
| mMediaSessionManager = context.getSystemService(MediaSessionManager.class); |
| mPermissionManager = context.getSystemService(PermissionManager.class); |
| mRoleManager = context.getSystemService(RoleManager.class); |
| mNotificationManagerInternal = LocalServices.getService( |
| NotificationManagerInternal.class); |
| mIAppOpsService = IAppOpsService.Stub.asInterface( |
| ServiceManager.getService(Context.APP_OPS_SERVICE)); |
| |
| getPolicy().onSystemReady(); |
| } |
| |
| ActivityManagerInternal getActivityManagerInternal() { |
| return mActivityManagerInternal; |
| } |
| |
| BatteryManagerInternal getBatteryManagerInternal() { |
| return mBatteryManagerInternal; |
| } |
| |
| BatteryStatsInternal getBatteryStatsInternal() { |
| return mBatteryStatsInternal; |
| } |
| |
| T getPolicy() { |
| return mAppStatePolicy; |
| } |
| |
| DeviceIdleInternal getDeviceIdleInternal() { |
| return mDeviceIdleInternal; |
| } |
| |
| UserManagerInternal getUserManagerInternal() { |
| return mUserManagerInternal; |
| } |
| |
| /** |
| * Equivalent to {@link java.lang.System#currentTimeMillis}. |
| */ |
| long currentTimeMillis() { |
| return System.currentTimeMillis(); |
| } |
| |
| PackageManager getPackageManager() { |
| return mPackageManager; |
| } |
| |
| PackageManagerInternal getPackageManagerInternal() { |
| return mPackageManagerInternal; |
| } |
| |
| PermissionManager getPermissionManager() { |
| return mPermissionManager; |
| } |
| |
| PermissionManagerServiceInternal getPermissionManagerServiceInternal() { |
| return mPermissionManagerServiceInternal; |
| } |
| |
| AppOpsManager getAppOpsManager() { |
| return mAppOpsManager; |
| } |
| |
| MediaSessionManager getMediaSessionManager() { |
| return mMediaSessionManager; |
| } |
| |
| long getServiceStartForegroundTimeout() { |
| return mActivityManagerInternal.getServiceStartForegroundTimeout(); |
| } |
| |
| RoleManager getRoleManager() { |
| return mRoleManager; |
| } |
| |
| NotificationManagerInternal getNotificationManagerInternal() { |
| return mNotificationManagerInternal; |
| } |
| |
| IAppOpsService getIAppOpsService() { |
| return mIAppOpsService; |
| } |
| } |
| } |