blob: 8d609104656da37e1cf1b3d2d5cc85701f31754d [file] [log] [blame]
/*
* 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;
}
}
}