Exclude the bg battery usage for apps with access to fine location
If an app has the permission ACCESS_FINE_LOCATION granted, its background battery usage during that wil be excluded from its overall background battery usage in AppBatteryTracker. Also turning OFF the exemption for apps with ACCESS_BACKGROUND_LOCATION only, as this doesn't mean it has access to locations. Bug: 200326767 Bug: 203105544 Test: atest FrameworksMockingServicesTests:BackgroundRestrictionTest Change-Id: Ibbd6dbb555c34c1839be6d21c62de00012832de6
This commit is contained in:
@@ -5764,4 +5764,15 @@
|
||||
show the prompt to user, False - we'll not show it.
|
||||
-->
|
||||
<bool name="config_bg_prompt_fgs_with_noti_to_bg_restricted">false</bool>
|
||||
|
||||
<!-- The types of state where we'll exempt its battery usage during that state.
|
||||
The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
|
||||
-->
|
||||
<integer name="config_bg_current_drain_exempted_types">9</integer>
|
||||
|
||||
<!-- The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
|
||||
whether or not the system will use a higher threshold towards its background battery usage
|
||||
because of it.
|
||||
-->
|
||||
<bool name="config_bg_current_drain_high_threshold_by_bg_location">false</bool>
|
||||
</resources>
|
||||
|
||||
@@ -4744,4 +4744,6 @@
|
||||
<java-symbol type="integer" name="config_bg_current_drain_media_playback_min_duration" />
|
||||
<java-symbol type="integer" name="config_bg_current_drain_location_min_duration" />
|
||||
<java-symbol type="bool" name="config_bg_prompt_fgs_with_noti_to_bg_restricted" />
|
||||
<java-symbol type="integer" name="config_bg_current_drain_exempted_types" />
|
||||
<java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
|
||||
</resources>
|
||||
|
||||
@@ -20,7 +20,7 @@ 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.AppBatteryTracker.BATTERY_USAGE_NONE;
|
||||
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
|
||||
import static com.android.server.am.BaseAppStateDurationsTracker.EVENT_NUM;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_NUM;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -36,9 +36,9 @@ import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
|
||||
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
|
||||
import com.android.server.am.AppBatteryTracker.BatteryUsage;
|
||||
import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
|
||||
import com.android.server.am.BaseAppStateDurationsTracker.EventListener;
|
||||
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
|
||||
import com.android.server.am.BaseAppStateTracker.Injector;
|
||||
import com.android.server.am.BaseAppStateTracker.StateListener;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -57,13 +57,13 @@ import java.util.LinkedList;
|
||||
*/
|
||||
final class AppBatteryExemptionTracker
|
||||
extends BaseAppStateDurationsTracker<AppBatteryExemptionPolicy, UidBatteryStates>
|
||||
implements BaseAppStateEvents.Factory<UidBatteryStates>, EventListener {
|
||||
implements BaseAppStateEvents.Factory<UidBatteryStates>, StateListener {
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "AppBatteryExemptionTracker" : TAG_AM;
|
||||
|
||||
private static final boolean DEBUG_BACKGROUND_BATTERY_EXEMPTION_TRACKER = false;
|
||||
|
||||
// As it's a UID-based tracker, anywhere which requires a package name, use this default name.
|
||||
private static final String DEFAULT_NAME = "";
|
||||
static final String DEFAULT_NAME = "";
|
||||
|
||||
AppBatteryExemptionTracker(Context context, AppRestrictionController controller) {
|
||||
this(context, controller, null, null);
|
||||
@@ -80,9 +80,7 @@ final class AppBatteryExemptionTracker
|
||||
void onSystemReady() {
|
||||
super.onSystemReady();
|
||||
mAppRestrictionController.forEachTracker(tracker -> {
|
||||
if (tracker instanceof BaseAppStateDurationsTracker) {
|
||||
((BaseAppStateDurationsTracker) tracker).registerEventListener(this);
|
||||
}
|
||||
tracker.registerStateListener(this);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -97,19 +95,20 @@ final class AppBatteryExemptionTracker
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewEvent(int uid, String packageName, boolean start, long now, int eventType) {
|
||||
public void onStateChange(int uid, String packageName, boolean start, long now, int stateType) {
|
||||
if (!mInjector.getPolicy().isEnabled()) {
|
||||
return;
|
||||
}
|
||||
final ImmutableBatteryUsage batteryUsage = mAppRestrictionController
|
||||
.getUidBatteryUsage(uid);
|
||||
final int stateTypeIndex = stateTypeToIndex(stateType);
|
||||
synchronized (mLock) {
|
||||
UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
|
||||
if (pkg == null) {
|
||||
pkg = createAppStateEvents(uid, DEFAULT_NAME);
|
||||
mPkgEvents.put(uid, DEFAULT_NAME, pkg);
|
||||
}
|
||||
pkg.addEvent(start, now, batteryUsage, eventType);
|
||||
pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +124,8 @@ final class AppBatteryExemptionTracker
|
||||
* @return The to-be-exempted battery usage of the given UID in the given duration; it could
|
||||
* be considered as "exempted" due to various use cases, i.e. media playback.
|
||||
*/
|
||||
ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now) {
|
||||
ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now,
|
||||
int types) {
|
||||
if (!mInjector.getPolicy().isEnabled()) {
|
||||
return BATTERY_USAGE_NONE;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ final class AppBatteryExemptionTracker
|
||||
if (pkg == null) {
|
||||
return BATTERY_USAGE_NONE;
|
||||
}
|
||||
result = pkg.getBatteryUsageSince(since, now);
|
||||
result = pkg.getBatteryUsageSince(since, now, types);
|
||||
}
|
||||
if (!result.second.isEmpty()) {
|
||||
// We have an open event (just start, no stop), get the battery usage till now.
|
||||
@@ -149,7 +149,7 @@ final class AppBatteryExemptionTracker
|
||||
static final class UidBatteryStates extends BaseAppStateDurations<UidStateEventWithBattery> {
|
||||
UidBatteryStates(int uid, @NonNull String tag,
|
||||
@NonNull MaxTrackingDurationConfig maxTrackingDurationConfig) {
|
||||
super(uid, DEFAULT_NAME, EVENT_NUM, tag, maxTrackingDurationConfig);
|
||||
super(uid, DEFAULT_NAME, STATE_TYPE_NUM, tag, maxTrackingDurationConfig);
|
||||
}
|
||||
|
||||
UidBatteryStates(@NonNull UidBatteryStates other) {
|
||||
@@ -160,7 +160,7 @@ final class AppBatteryExemptionTracker
|
||||
* @param start {@code true} if it's a start event.
|
||||
* @param now The timestamp when this event occurred.
|
||||
* @param batteryUsage The background current drain since the system boots.
|
||||
* @param eventType One of EVENT_TYPE_* defined in the class BaseAppStateDurationsTracker.
|
||||
* @param eventType One of STATE_TYPE_INDEX_* defined in the class BaseAppStateTracker.
|
||||
*/
|
||||
void addEvent(boolean start, long now, ImmutableBatteryUsage batteryUsage, int eventType) {
|
||||
if (start) {
|
||||
@@ -184,17 +184,6 @@ final class AppBatteryExemptionTracker
|
||||
return mEvents[eventType] != null ? mEvents[eventType].peekLast() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pair of bg battery usage of given duration; the first value in the pair
|
||||
* is the aggregated battery usage of all event pairs in this duration; while
|
||||
* the second value is the battery usage since the system boots, if there is
|
||||
* an open event(just start, no stop) at the end of the duration.
|
||||
*/
|
||||
Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
|
||||
long now, int eventType) {
|
||||
return getBatteryUsageSince(since, now, mEvents[eventType]);
|
||||
}
|
||||
|
||||
private Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
|
||||
long now, LinkedList<UidStateEventWithBattery> events) {
|
||||
if (events == null || events.size() == 0) {
|
||||
@@ -217,13 +206,18 @@ final class AppBatteryExemptionTracker
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The aggregated battery usage amongst all the event types we're tracking.
|
||||
* @return The pair of bg battery usage of given duration; the first value in the pair
|
||||
* is the aggregated battery usage of selected events in this duration; while
|
||||
* the second value is the battery usage since the system boots, if there is
|
||||
* an open event(just start, no stop) at the end of the duration.
|
||||
*/
|
||||
Pair<ImmutableBatteryUsage, ImmutableBatteryUsage> getBatteryUsageSince(long since,
|
||||
long now) {
|
||||
long now, int types) {
|
||||
LinkedList<UidStateEventWithBattery> result = new LinkedList<>();
|
||||
for (int i = 0; i < mEvents.length; i++) {
|
||||
result = add(result, mEvents[i]);
|
||||
if ((types & stateIndexToType(i)) != 0) {
|
||||
result = add(result, mEvents[i]);
|
||||
}
|
||||
}
|
||||
return getBatteryUsageSince(since, now, result);
|
||||
}
|
||||
|
||||
@@ -325,7 +325,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
final int uid = uidConsumers.keyAt(i);
|
||||
final ImmutableBatteryUsage actualUsage = uidConsumers.valueAt(i);
|
||||
final ImmutableBatteryUsage exemptedUsage = mAppRestrictionController
|
||||
.getUidBatteryExemptedUsageSince(uid, since, now);
|
||||
.getUidBatteryExemptedUsageSince(uid, since, now,
|
||||
bgPolicy.mBgCurrentDrainExemptedTypes);
|
||||
// It's possible the exemptedUsage could be larger than actualUsage,
|
||||
// as the former one is an approximate value.
|
||||
final BatteryUsage bgUsage = actualUsage.mutate()
|
||||
@@ -656,7 +657,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
final BatteryUsage bgUsage = uidConsumers.valueAt(i)
|
||||
.calcPercentage(uid, bgPolicy);
|
||||
final BatteryUsage exemptedUsage = mAppRestrictionController
|
||||
.getUidBatteryExemptedUsageSince(uid, since, now)
|
||||
.getUidBatteryExemptedUsageSince(uid, since, now,
|
||||
bgPolicy.mBgCurrentDrainExemptedTypes)
|
||||
.calcPercentage(uid, bgPolicy);
|
||||
final BatteryUsage reportedUsage = new BatteryUsage(bgUsage)
|
||||
.subtract(exemptedUsage)
|
||||
@@ -1026,6 +1028,21 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
static final String KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS =
|
||||
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_power_components";
|
||||
|
||||
/**
|
||||
* The types of state where we'll exempt its battery usage when it's in that state.
|
||||
* The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
|
||||
*/
|
||||
static final String KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES =
|
||||
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_exempted_types";
|
||||
|
||||
/**
|
||||
* The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
|
||||
* whether or not the system will use a higher threshold towards its background battery
|
||||
* usage because of it.
|
||||
*/
|
||||
static final String KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION =
|
||||
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_high_threshold_by_bg_location";
|
||||
|
||||
/**
|
||||
* Default value to the {@link #INDEX_REGULAR_CURRENT_DRAIN_THRESHOLD} of
|
||||
* the {@link #mBgCurrentDrainRestrictedBucketThreshold}.
|
||||
@@ -1088,6 +1105,16 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
|
||||
final int mDefaultBgCurrentDrainPowerComponent;
|
||||
|
||||
/**
|
||||
* Default value to {@link #mBgCurrentDrainExmptedTypes}.
|
||||
**/
|
||||
final int mDefaultBgCurrentDrainExemptedTypes;
|
||||
|
||||
/**
|
||||
* Default value to {@link #mBgCurrentDrainHighThresholdByBgLocation}.
|
||||
*/
|
||||
final boolean mDefaultBgCurrentDrainHighThresholdByBgLocation;
|
||||
|
||||
/**
|
||||
* The index to {@link #mBgCurrentDrainRestrictedBucketThreshold}
|
||||
* and {@link #mBgCurrentDrainBgRestrictedThreshold}.
|
||||
@@ -1145,6 +1172,16 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
|
||||
volatile Dimensions[] mBatteryDimensions;
|
||||
|
||||
/**
|
||||
* @see #KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES.
|
||||
*/
|
||||
volatile int mBgCurrentDrainExemptedTypes;
|
||||
|
||||
/**
|
||||
* @see #KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION.
|
||||
*/
|
||||
volatile boolean mBgCurrentDrainHighThresholdByBgLocation;
|
||||
|
||||
/**
|
||||
* The capacity of the battery when fully charged in mAh.
|
||||
*/
|
||||
@@ -1201,6 +1238,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
R.integer.config_bg_current_drain_types_to_bg_restricted);
|
||||
mDefaultBgCurrentDrainPowerComponent = resources.getInteger(
|
||||
R.integer.config_bg_current_drain_power_components);
|
||||
mDefaultBgCurrentDrainExemptedTypes = resources.getInteger(
|
||||
R.integer.config_bg_current_drain_exempted_types);
|
||||
mDefaultBgCurrentDrainHighThresholdByBgLocation = resources.getBoolean(
|
||||
R.bool.config_bg_current_drain_high_threshold_by_bg_location);
|
||||
mBgCurrentDrainRestrictedBucketThreshold[0] =
|
||||
mDefaultBgCurrentDrainRestrictedBucket;
|
||||
mBgCurrentDrainRestrictedBucketThreshold[1] =
|
||||
@@ -1230,6 +1271,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
switch (name) {
|
||||
case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET:
|
||||
case KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_BG_RESTRICTED:
|
||||
case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION:
|
||||
case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_RESTRICTED_BUCKET:
|
||||
case KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_TO_BG_RESTRICTED:
|
||||
case KEY_BG_CURRENT_DRAIN_TYPES_TO_RESTRICTED_BUCKET:
|
||||
@@ -1249,6 +1291,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
case KEY_BG_CURRENT_DRAIN_EVENT_DURATION_BASED_THRESHOLD_ENABLED:
|
||||
updateCurrentDrainEventDurationBasedThresholdEnabled();
|
||||
break;
|
||||
case KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES:
|
||||
updateCurrentDrainExemptedTypes();
|
||||
break;
|
||||
default:
|
||||
super.onPropertiesChanged(name);
|
||||
break;
|
||||
@@ -1305,6 +1350,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
mBatteryDimensions[i] = new Dimensions(mBgCurrentDrainPowerComponents, i);
|
||||
}
|
||||
}
|
||||
mBgCurrentDrainHighThresholdByBgLocation =
|
||||
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION,
|
||||
mDefaultBgCurrentDrainHighThresholdByBgLocation);
|
||||
}
|
||||
|
||||
private void updateCurrentDrainWindow() {
|
||||
@@ -1335,6 +1384,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled);
|
||||
}
|
||||
|
||||
private void updateCurrentDrainExemptedTypes() {
|
||||
mBgCurrentDrainExemptedTypes = DeviceConfig.getInt(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
|
||||
mDefaultBgCurrentDrainExemptedTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemReady() {
|
||||
mBatteryFullChargeMah =
|
||||
@@ -1345,6 +1401,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
updateCurrentDrainMediaPlaybackMinDuration();
|
||||
updateCurrentDrainLocationMinDuration();
|
||||
updateCurrentDrainEventDurationBasedThresholdEnabled();
|
||||
updateCurrentDrainExemptedTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1507,6 +1564,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
}
|
||||
|
||||
private boolean hasLocation(int uid, long now, long window) {
|
||||
if (!mBgCurrentDrainHighThresholdByBgLocation) {
|
||||
return false;
|
||||
}
|
||||
final AppRestrictionController controller = mTracker.mAppRestrictionController;
|
||||
if (mInjector.getPermissionManagerServiceInternal().checkUidPermission(
|
||||
uid, ACCESS_BACKGROUND_LOCATION) == PERMISSION_GRANTED) {
|
||||
@@ -1620,6 +1680,14 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
|
||||
pw.print(KEY_BG_CURRENT_DRAIN_POWER_COMPONENTS);
|
||||
pw.print('=');
|
||||
pw.println(mBgCurrentDrainPowerComponents);
|
||||
pw.print(prefix);
|
||||
pw.print(KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES);
|
||||
pw.print('=');
|
||||
pw.println(BaseAppStateTracker.stateTypesToString(mBgCurrentDrainExemptedTypes));
|
||||
pw.print(prefix);
|
||||
pw.print(KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION);
|
||||
pw.print('=');
|
||||
pw.println(mBgCurrentDrainHighThresholdByBgLocation);
|
||||
|
||||
pw.print(prefix);
|
||||
pw.println("Excessive current drain detected:");
|
||||
|
||||
@@ -543,7 +543,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
}
|
||||
if (isActive(i)) {
|
||||
mEvents[i].add(new BaseTimeEvent(now));
|
||||
notifyListenersOnEventIfNecessary(false, now,
|
||||
notifyListenersOnStateChangeIfNecessary(false, now,
|
||||
indexToForegroundServiceType(i));
|
||||
}
|
||||
}
|
||||
@@ -569,13 +569,13 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
}
|
||||
if (!isActive(i)) {
|
||||
mEvents[i].add(new BaseTimeEvent(now));
|
||||
notifyListenersOnEventIfNecessary(true, now, serviceType);
|
||||
notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
|
||||
}
|
||||
} else {
|
||||
// Stop this type.
|
||||
if (mEvents[i] != null && isActive(i)) {
|
||||
mEvents[i].add(new BaseTimeEvent(now));
|
||||
notifyListenersOnEventIfNecessary(false, now, serviceType);
|
||||
notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
|
||||
}
|
||||
}
|
||||
changes &= ~serviceType;
|
||||
@@ -584,20 +584,20 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
mForegroundServiceTypes = serviceTypes;
|
||||
}
|
||||
|
||||
private void notifyListenersOnEventIfNecessary(boolean start, long now,
|
||||
private void notifyListenersOnStateChangeIfNecessary(boolean start, long now,
|
||||
@ForegroundServiceType int serviceType) {
|
||||
int eventType;
|
||||
int stateType;
|
||||
switch (serviceType) {
|
||||
case FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK:
|
||||
eventType = BaseAppStateDurationsTracker.EVENT_TYPE_FGS_MEDIA_PLAYBACK;
|
||||
stateType = BaseAppStateDurationsTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
|
||||
break;
|
||||
case FOREGROUND_SERVICE_TYPE_LOCATION:
|
||||
eventType = BaseAppStateDurationsTracker.EVENT_TYPE_FGS_LOCATION;
|
||||
stateType = BaseAppStateDurationsTracker.STATE_TYPE_FGS_LOCATION;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
mTracker.notifyListenersOnEvent(mUid, mPackageName, start, now, eventType);
|
||||
mTracker.notifyListenersOnStateChange(mUid, mPackageName, start, now, stateType);
|
||||
}
|
||||
|
||||
void setIsLongRunning(boolean isLongRunning) {
|
||||
|
||||
@@ -19,8 +19,8 @@ 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 static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
|
||||
import static com.android.server.am.BaseAppStateDurationsTracker.EVENT_TYPE_MEDIA_SESSION;
|
||||
import static com.android.server.am.BaseAppStateTracker.ONE_DAY;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
@@ -104,8 +104,8 @@ final class AppMediaSessionTracker
|
||||
}
|
||||
if (!pkg.isActive()) {
|
||||
pkg.addEvent(true, now);
|
||||
notifyListenersOnEvent(pkg.mUid, pkg.mPackageName, true, now,
|
||||
EVENT_TYPE_MEDIA_SESSION);
|
||||
notifyListenersOnStateChange(pkg.mUid, pkg.mPackageName, true, now,
|
||||
STATE_TYPE_MEDIA_SESSION);
|
||||
}
|
||||
// Mark it as active, so we could filter out inactive ones below.
|
||||
mTmpMediaControllers.put(packageName, uid, Boolean.TRUE);
|
||||
@@ -127,8 +127,8 @@ final class AppMediaSessionTracker
|
||||
&& mTmpMediaControllers.get(pkg.mPackageName, pkg.mUid) == null) {
|
||||
// This package has removed its controller, issue a stop event.
|
||||
pkg.addEvent(false, now);
|
||||
notifyListenersOnEvent(pkg.mUid, pkg.mPackageName, false, now,
|
||||
EVENT_TYPE_MEDIA_SESSION);
|
||||
notifyListenersOnStateChange(pkg.mUid, pkg.mPackageName, false, now,
|
||||
STATE_TYPE_MEDIA_SESSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,8 +146,8 @@ final class AppMediaSessionTracker
|
||||
final SimplePackageDurations pkg = val.valueAt(j);
|
||||
if (pkg.isActive()) {
|
||||
pkg.addEvent(false, now);
|
||||
notifyListenersOnEvent(pkg.mUid, pkg.mPackageName, false, now,
|
||||
EVENT_TYPE_MEDIA_SESSION);
|
||||
notifyListenersOnStateChange(pkg.mUid, pkg.mPackageName, false, now,
|
||||
STATE_TYPE_MEDIA_SESSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 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 android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.os.Process.SYSTEM_UID;
|
||||
|
||||
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.AppBatteryExemptionTracker.DEFAULT_NAME;
|
||||
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager.OnPermissionsChangedListener;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.permission.PermissionManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
|
||||
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The tracker for monitoring selected permission state of apps.
|
||||
*/
|
||||
final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy>
|
||||
implements OnPermissionsChangedListener {
|
||||
static final String TAG = TAG_WITH_CLASS_NAME ? "AppPermissionTracker" : TAG_AM;
|
||||
|
||||
static final boolean DEBUG_PERMISSION_TRACKER = false;
|
||||
|
||||
private final MyHandler mHandler;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
|
||||
|
||||
AppPermissionTracker(Context context, AppRestrictionController controller) {
|
||||
this(context, controller, null, null);
|
||||
}
|
||||
|
||||
AppPermissionTracker(Context context, AppRestrictionController controller,
|
||||
Constructor<? extends Injector<AppPermissionPolicy>> injector, Object outerContext) {
|
||||
super(context, controller, injector, outerContext);
|
||||
mHandler = new MyHandler(this);
|
||||
mInjector.setPolicy(new AppPermissionPolicy(mInjector, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionsChanged(int uid) {
|
||||
mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
|
||||
}
|
||||
|
||||
private void handlePermissionsInit() {
|
||||
final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
|
||||
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
|
||||
final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
|
||||
final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
|
||||
for (int userId : allUsers) {
|
||||
final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
|
||||
if (apps == null) {
|
||||
continue;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
for (int i = 0, size = apps.size(); i < size; i++) {
|
||||
final ApplicationInfo ai = apps.get(i);
|
||||
for (String permission : permissions) {
|
||||
if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
|
||||
continue;
|
||||
}
|
||||
ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
|
||||
if (grantedPermissions == null) {
|
||||
grantedPermissions = new ArraySet<String>();
|
||||
uidPerms.put(ai.uid, grantedPermissions);
|
||||
}
|
||||
grantedPermissions.add(permission);
|
||||
notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
|
||||
STATE_TYPE_PERMISSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePermissionsDestroy() {
|
||||
synchronized (mLock) {
|
||||
final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
for (int i = 0, size = uidPerms.size(); i < size; i++) {
|
||||
final int uid = uidPerms.keyAt(i);
|
||||
final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
|
||||
for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
|
||||
notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
|
||||
STATE_TYPE_PERMISSION);
|
||||
}
|
||||
}
|
||||
uidPerms.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePermissionsChanged(int uid) {
|
||||
final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
|
||||
if (permissions != null && permissions.length > 0) {
|
||||
synchronized (mLock) {
|
||||
handlePermissionsChangedLocked(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void handlePermissionsChangedLocked(int uid) {
|
||||
final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
|
||||
final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
|
||||
ArraySet<String> grantedPermissions = index >= 0
|
||||
? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
|
||||
final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
for (String permission: permissions) {
|
||||
boolean granted = pm.checkUidPermission(uid, permission) == PERMISSION_GRANTED;
|
||||
if (DEBUG_PERMISSION_TRACKER) {
|
||||
Slog.i(TAG, UserHandle.formatUid(uid) + " " + permission + "=" + granted);
|
||||
}
|
||||
boolean changed = false;
|
||||
if (granted) {
|
||||
if (grantedPermissions == null) {
|
||||
grantedPermissions = new ArraySet<>();
|
||||
mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
|
||||
}
|
||||
changed = grantedPermissions.add(permission);
|
||||
} else if (grantedPermissions != null) {
|
||||
changed = grantedPermissions.remove(permission);
|
||||
if (grantedPermissions.isEmpty()) {
|
||||
mUidGrantedPermissionsInMonitor.removeAt(index);
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
notifyListenersOnStateChange(uid, DEFAULT_NAME, granted, now,
|
||||
STATE_TYPE_PERMISSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyHandler extends Handler {
|
||||
static final int MSG_PERMISSIONS_INIT = 0;
|
||||
static final int MSG_PERMISSIONS_DESTROY = 1;
|
||||
static final int MSG_PERMISSIONS_CHANGED = 2;
|
||||
|
||||
private @NonNull AppPermissionTracker mTracker;
|
||||
|
||||
MyHandler(@NonNull AppPermissionTracker tracker) {
|
||||
super(tracker.mBgHandler.getLooper());
|
||||
mTracker = tracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_PERMISSIONS_INIT:
|
||||
mTracker.handlePermissionsInit();
|
||||
break;
|
||||
case MSG_PERMISSIONS_DESTROY:
|
||||
mTracker.handlePermissionsDestroy();
|
||||
break;
|
||||
case MSG_PERMISSIONS_CHANGED:
|
||||
mTracker.handlePermissionsChanged(msg.arg1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onPermissionTrackerEnabled(boolean enabled) {
|
||||
final PermissionManager pm = mInjector.getPermissionManager();
|
||||
if (enabled) {
|
||||
pm.addOnPermissionsChangeListener(this);
|
||||
mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_INIT).sendToTarget();
|
||||
} else {
|
||||
pm.removeOnPermissionsChangeListener(this);
|
||||
mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_DESTROY).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void dump(PrintWriter pw, String prefix) {
|
||||
pw.print(prefix);
|
||||
pw.println("APP PERMISSIONS TRACKER:");
|
||||
final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
|
||||
final String prefixMore = " " + prefix;
|
||||
final String prefixMoreMore = " " + prefixMore;
|
||||
for (String permission : permissions) {
|
||||
pw.print(prefixMore);
|
||||
pw.print(permission);
|
||||
pw.println(':');
|
||||
synchronized (mLock) {
|
||||
final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
|
||||
pw.print(prefixMoreMore);
|
||||
pw.print('[');
|
||||
boolean needDelimiter = false;
|
||||
for (int i = 0, size = uidPerms.size(); i < size; i++) {
|
||||
if (uidPerms.valueAt(i).contains(permission)) {
|
||||
if (needDelimiter) {
|
||||
pw.print(',');
|
||||
}
|
||||
needDelimiter = true;
|
||||
pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
|
||||
}
|
||||
}
|
||||
pw.println(']');
|
||||
}
|
||||
}
|
||||
super.dump(pw, prefix);
|
||||
}
|
||||
|
||||
static final class AppPermissionPolicy extends BaseAppStatePolicy<AppPermissionTracker> {
|
||||
/**
|
||||
* Whether or not we should enable the monitoring on app permissions.
|
||||
*/
|
||||
static final String KEY_BG_PERMISSION_MONITOR_ENABLED =
|
||||
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "permission_monitor_enabled";
|
||||
|
||||
/**
|
||||
* The names of the permissions we're monitoring its changes.
|
||||
*/
|
||||
static final String KEY_BG_PERMISSIONS_IN_MONITOR =
|
||||
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "permission_in_monitor";
|
||||
|
||||
/**
|
||||
* Default value to {@link #mTrackerEnabled}.
|
||||
*/
|
||||
static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;
|
||||
|
||||
/**
|
||||
* Default value to {@link #mBgPermissionsInMonitor}.
|
||||
*/
|
||||
static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
|
||||
ACCESS_FINE_LOCATION,
|
||||
};
|
||||
|
||||
/**
|
||||
* @see #KEY_BG_PERMISSIONS_IN_MONITOR.
|
||||
*/
|
||||
volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
|
||||
|
||||
AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
|
||||
super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
|
||||
DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSystemReady() {
|
||||
super.onSystemReady();
|
||||
updateBgPermissionsInMonitor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertiesChanged(String name) {
|
||||
switch (name) {
|
||||
case KEY_BG_PERMISSIONS_IN_MONITOR:
|
||||
updateBgPermissionsInMonitor();
|
||||
break;
|
||||
default:
|
||||
super.onPropertiesChanged(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String[] getBgPermissionsInMonitor() {
|
||||
return mBgPermissionsInMonitor;
|
||||
}
|
||||
|
||||
private void updateBgPermissionsInMonitor() {
|
||||
final String config = DeviceConfig.getString(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
KEY_BG_PERMISSIONS_IN_MONITOR,
|
||||
null);
|
||||
mBgPermissionsInMonitor = config != null
|
||||
? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackerEnabled(boolean enabled) {
|
||||
mTracker.onPermissionTrackerEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
void dump(PrintWriter pw, String prefix) {
|
||||
pw.print(prefix);
|
||||
pw.println("APP PERMISSION TRACKER POLICY SETTINGS:");
|
||||
prefix = " " + prefix;
|
||||
super.dump(pw, prefix);
|
||||
pw.print(prefix);
|
||||
pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
|
||||
pw.print('=');
|
||||
pw.println(Arrays.toString(mBgPermissionsInMonitor));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1141,9 +1141,10 @@ public final class AppRestrictionController {
|
||||
* @return The to-be-exempted battery usage of the given UID in the given duration; it could
|
||||
* be considered as "exempted" due to various use cases, i.e. media playback.
|
||||
*/
|
||||
ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now) {
|
||||
ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now,
|
||||
int types) {
|
||||
return mInjector.getAppBatteryExemptionTracker()
|
||||
.getUidBatteryExemptedUsageSince(uid, since, now);
|
||||
.getUidBatteryExemptedUsageSince(uid, since, now, types);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1944,6 +1945,7 @@ public final class AppRestrictionController {
|
||||
private AppBatteryExemptionTracker mAppBatteryExemptionTracker;
|
||||
private AppFGSTracker mAppFGSTracker;
|
||||
private AppMediaSessionTracker mAppMediaSessionTracker;
|
||||
private AppPermissionTracker mAppPermissionTracker;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
|
||||
Injector(Context context) {
|
||||
@@ -1960,10 +1962,12 @@ public final class AppRestrictionController {
|
||||
mAppBatteryExemptionTracker = new AppBatteryExemptionTracker(mContext, controller);
|
||||
mAppFGSTracker = new AppFGSTracker(mContext, controller);
|
||||
mAppMediaSessionTracker = new AppMediaSessionTracker(mContext, controller);
|
||||
mAppPermissionTracker = new AppPermissionTracker(mContext, controller);
|
||||
controller.mAppStateTrackers.add(mAppBatteryTracker);
|
||||
controller.mAppStateTrackers.add(mAppBatteryExemptionTracker);
|
||||
controller.mAppStateTrackers.add(mAppFGSTracker);
|
||||
controller.mAppStateTrackers.add(mAppMediaSessionTracker);
|
||||
controller.mAppStateTrackers.add(mAppPermissionTracker);
|
||||
controller.mAppStateTrackers.add(new AppBroadcastEventsTracker(mContext, controller));
|
||||
controller.mAppStateTrackers.add(new AppBindServiceEventsTracker(mContext, controller));
|
||||
}
|
||||
@@ -2071,6 +2075,10 @@ public final class AppRestrictionController {
|
||||
return mAppBatteryExemptionTracker;
|
||||
}
|
||||
|
||||
AppPermissionTracker getAppPermissionTracker() {
|
||||
return mAppPermissionTracker;
|
||||
}
|
||||
|
||||
String getPackageName(int pid) {
|
||||
final ActivityManagerService am = getActivityManagerService();
|
||||
final ProcessRecord app;
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.server.am;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseArray;
|
||||
@@ -32,7 +31,6 @@ import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
@@ -43,20 +41,9 @@ abstract class BaseAppStateDurationsTracker
|
||||
extends BaseAppStateEventsTracker<T, U> {
|
||||
static final boolean DEBUG_BASE_APP_STATE_DURATION_TRACKER = false;
|
||||
|
||||
static final int EVENT_TYPE_MEDIA_SESSION = 0;
|
||||
static final int EVENT_TYPE_FGS_MEDIA_PLAYBACK = 1;
|
||||
static final int EVENT_TYPE_FGS_LOCATION = 2;
|
||||
static final int EVENT_NUM = 3;
|
||||
|
||||
final ArrayList<EventListener> mEventListeners = new ArrayList<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
final SparseArray<UidStateDurations> mUidStateDurations = new SparseArray<>();
|
||||
|
||||
interface EventListener {
|
||||
void onNewEvent(int uid, String packageName, boolean start, long now, int eventType);
|
||||
}
|
||||
|
||||
BaseAppStateDurationsTracker(Context context, AppRestrictionController controller,
|
||||
Constructor<? extends Injector<T>> injector, Object outerContext) {
|
||||
super(context, controller, injector, outerContext);
|
||||
@@ -104,21 +91,6 @@ abstract class BaseAppStateDurationsTracker
|
||||
mUidStateDurations.remove(uid);
|
||||
}
|
||||
|
||||
void registerEventListener(@NonNull EventListener listener) {
|
||||
synchronized (mLock) {
|
||||
mEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void notifyListenersOnEvent(int uid, String packageName,
|
||||
boolean start, long now, int eventType) {
|
||||
synchronized (mLock) {
|
||||
for (int i = 0, size = mEventListeners.size(); i < size; i++) {
|
||||
mEventListeners.get(i).onNewEvent(uid, packageName, start, now, eventType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long getTotalDurations(String packageName, int uid, long now, int index, boolean bgOnly) {
|
||||
synchronized (mLock) {
|
||||
final U durations = mPkgEvents.get(uid, packageName);
|
||||
|
||||
@@ -28,10 +28,12 @@ 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.permission.PermissionManager;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.DeviceIdleInternal;
|
||||
@@ -42,6 +44,7 @@ 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.
|
||||
@@ -55,11 +58,27 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
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_PERMISSION = 1 << 3;
|
||||
static final int STATE_TYPE_NUM = 4;
|
||||
|
||||
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_PERMISSION = 3;
|
||||
|
||||
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) {
|
||||
@@ -80,6 +99,60 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
}
|
||||
}
|
||||
|
||||
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_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 policy holder of this tracker.
|
||||
*/
|
||||
@@ -180,6 +253,8 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
DeviceIdleInternal mDeviceIdleInternal;
|
||||
UserManagerInternal mUserManagerInternal;
|
||||
PackageManager mPackageManager;
|
||||
PackageManagerInternal mPackageManagerInternal;
|
||||
PermissionManager mPermissionManager;
|
||||
PermissionManagerServiceInternal mPermissionManagerServiceInternal;
|
||||
AppOpsManager mAppOpsManager;
|
||||
MediaSessionManager mMediaSessionManager;
|
||||
@@ -196,12 +271,14 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
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);
|
||||
@@ -244,6 +321,14 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
return mPackageManager;
|
||||
}
|
||||
|
||||
PackageManagerInternal getPackageManagerInternal() {
|
||||
return mPackageManagerInternal;
|
||||
}
|
||||
|
||||
PermissionManager getPermissionManager() {
|
||||
return mPermissionManager;
|
||||
}
|
||||
|
||||
PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
|
||||
return mPermissionManagerServiceInternal;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.server.am;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
|
||||
import static android.app.ActivityManager.PROCESS_STATE_TOP;
|
||||
import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
|
||||
@@ -52,7 +54,12 @@ import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE
|
||||
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND;
|
||||
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE;
|
||||
import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATT_DIMENS;
|
||||
import static com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
|
||||
import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_LOCATION;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -103,6 +110,7 @@ import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UidBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.permission.PermissionManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
@@ -152,6 +160,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Tests for {@link AppRestrictionController}.
|
||||
@@ -217,6 +226,7 @@ public final class BackgroundRestrictionTest {
|
||||
@Mock private PackageManagerInternal mPackageManagerInternal;
|
||||
@Mock private NotificationManager mNotificationManager;
|
||||
@Mock private NotificationManagerInternal mNotificationManagerInternal;
|
||||
@Mock private PermissionManager mPermissionManager;
|
||||
@Mock private PermissionManagerServiceInternal mPermissionManagerServiceInternal;
|
||||
@Mock private MediaSessionManager mMediaSessionManager;
|
||||
@Mock private RoleManager mRoleManager;
|
||||
@@ -252,6 +262,7 @@ public final class BackgroundRestrictionTest {
|
||||
private AppBindServiceEventsTracker mAppBindServiceEventsTracker;
|
||||
private AppFGSTracker mAppFGSTracker;
|
||||
private AppMediaSessionTracker mAppMediaSessionTracker;
|
||||
private AppPermissionTracker mAppPermissionTracker;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -291,12 +302,16 @@ public final class BackgroundRestrictionTest {
|
||||
doReturn(AppOpsManager.MODE_IGNORED)
|
||||
.when(mAppOpsManager)
|
||||
.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, uid, packageName);
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkUidPermission(uid, ACCESS_BACKGROUND_LOCATION);
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkPermission(packageName, ACCESS_BACKGROUND_LOCATION, userId);
|
||||
final String[] permissions = new String[] {ACCESS_BACKGROUND_LOCATION,
|
||||
ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION};
|
||||
for (String permission : permissions) {
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkUidPermission(uid, permission);
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkPermission(packageName, permission, userId);
|
||||
}
|
||||
}
|
||||
doReturn(appStandbyInfoList).when(mAppStandbyInternal).getAppStandbyBuckets(userId);
|
||||
}
|
||||
@@ -1278,7 +1293,8 @@ public final class BackgroundRestrictionTest {
|
||||
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
|
||||
doReturn(PERMISSION_GRANTED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkUidPermission(uid, ACCESS_BACKGROUND_LOCATION);
|
||||
.checkUidPermission(uid, perm);
|
||||
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
|
||||
}
|
||||
|
||||
if (mediaControllers != null) {
|
||||
@@ -1303,7 +1319,8 @@ public final class BackgroundRestrictionTest {
|
||||
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkUidPermission(uid, ACCESS_BACKGROUND_LOCATION);
|
||||
.checkUidPermission(uid, perm);
|
||||
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
|
||||
}
|
||||
if (topStateThread != null) {
|
||||
topStateThread.join();
|
||||
@@ -1371,6 +1388,10 @@ public final class BackgroundRestrictionTest {
|
||||
DeviceConfigSession<Long> bgLocationMinDurationThreshold = null;
|
||||
DeviceConfigSession<Boolean> bgCurrentDrainEventDurationBasedThresholdEnabled = null;
|
||||
DeviceConfigSession<Boolean> bgBatteryExemptionEnabled = null;
|
||||
DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
|
||||
DeviceConfigSession<Boolean> bgPermissionMonitorEnabled = null;
|
||||
DeviceConfigSession<String> bgPermissionsInMonitor = null;
|
||||
DeviceConfigSession<Boolean> bgCurrentDrainHighThresholdByBgLocation = null;
|
||||
|
||||
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
|
||||
|
||||
@@ -1469,6 +1490,38 @@ public final class BackgroundRestrictionTest {
|
||||
AppBatteryExemptionPolicy.DEFAULT_BG_BATTERY_EXEMPTION_ENABLED);
|
||||
bgBatteryExemptionEnabled.set(false);
|
||||
|
||||
bgBatteryExemptionTypes = new DeviceConfigSession<>(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
|
||||
DeviceConfig::getInt,
|
||||
mContext.getResources().getInteger(
|
||||
R.integer.config_bg_current_drain_exempted_types));
|
||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
|
||||
| STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
|
||||
|
||||
bgPermissionMonitorEnabled = new DeviceConfigSession<>(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
AppPermissionPolicy.KEY_BG_PERMISSION_MONITOR_ENABLED,
|
||||
DeviceConfig::getBoolean,
|
||||
AppPermissionPolicy.DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
|
||||
bgPermissionMonitorEnabled.set(true);
|
||||
|
||||
bgPermissionsInMonitor = new DeviceConfigSession<>(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
AppPermissionPolicy.KEY_BG_PERMISSION_MONITOR_ENABLED,
|
||||
DeviceConfig::getString,
|
||||
Arrays.stream(AppPermissionPolicy.DEFAULT_BG_PERMISSIONS_IN_MONITOR)
|
||||
.collect(Collectors.joining(",")));
|
||||
bgPermissionsInMonitor.set(ACCESS_FINE_LOCATION);
|
||||
|
||||
bgCurrentDrainHighThresholdByBgLocation = new DeviceConfigSession<>(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_HIGH_THRESHOLD_BY_BG_LOCATION,
|
||||
DeviceConfig::getBoolean,
|
||||
mContext.getResources().getBoolean(
|
||||
R.bool.config_bg_current_drain_high_threshold_by_bg_location));
|
||||
bgCurrentDrainHighThresholdByBgLocation.set(true);
|
||||
|
||||
mCurrentTimeMillis = 10_000L;
|
||||
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
|
||||
@@ -1618,15 +1671,44 @@ public final class BackgroundRestrictionTest {
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
mAppBatteryPolicy.reset();
|
||||
|
||||
// Run with bg location permission, with higher current drain.
|
||||
// Turn off the higher threshold for bg location access.
|
||||
bgCurrentDrainHighThresholdByBgLocation.set(false);
|
||||
|
||||
// Run with bg location permission, with moderate current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{restrictBucketThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, null, null, null);
|
||||
|
||||
// Run with bg location permission, with a bit higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, null, null, null);
|
||||
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
mAppBatteryPolicy.reset();
|
||||
|
||||
// Turn on the higher threshold for bg location access.
|
||||
bgCurrentDrainHighThresholdByBgLocation.set(true);
|
||||
|
||||
// Run with bg location permission, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
true , RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
||||
null, windowMs, null, null, null);
|
||||
|
||||
// Run with bg location permission, with even higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
@@ -1709,6 +1791,36 @@ public final class BackgroundRestrictionTest {
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
||||
null, windowMs, initialBg, initialFgs, initialFg);
|
||||
|
||||
// Set the policy to exempt media session and permission.
|
||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_PERMISSION);
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
mAppBatteryPolicy.reset();
|
||||
|
||||
// Run with coarse location permission, with high current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
ACCESS_COARSE_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, initialBg, initialFgs, initialFg);
|
||||
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
mAppBatteryPolicy.reset();
|
||||
|
||||
// Run with fine location permission, with high current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
ACCESS_FINE_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, initialBg, initialFgs, initialFg);
|
||||
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
@@ -1738,6 +1850,10 @@ public final class BackgroundRestrictionTest {
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, initialBg, initialFgs, initialFg);
|
||||
|
||||
// Set the policy to exempt all.
|
||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
|
||||
| STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
|
||||
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
@@ -1772,6 +1888,10 @@ public final class BackgroundRestrictionTest {
|
||||
closeIfNotNull(bgLocationMinDurationThreshold);
|
||||
closeIfNotNull(bgCurrentDrainEventDurationBasedThresholdEnabled);
|
||||
closeIfNotNull(bgBatteryExemptionEnabled);
|
||||
closeIfNotNull(bgBatteryExemptionTypes);
|
||||
closeIfNotNull(bgPermissionMonitorEnabled);
|
||||
closeIfNotNull(bgPermissionsInMonitor);
|
||||
closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1792,6 +1912,15 @@ public final class BackgroundRestrictionTest {
|
||||
mAppBatteryExemptionTracker.reset();
|
||||
mAppBatteryPolicy.reset();
|
||||
}
|
||||
if (perm != null) {
|
||||
doReturn(PERMISSION_GRANTED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
|
||||
doReturn(PERMISSION_GRANTED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkUidPermission(uid, perm);
|
||||
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
|
||||
}
|
||||
runExemptionTestOnce(
|
||||
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
|
||||
perm, mediaControllers, topStateChanges, resetFGSTracker, false,
|
||||
@@ -1841,6 +1970,15 @@ public final class BackgroundRestrictionTest {
|
||||
);
|
||||
}
|
||||
);
|
||||
if (perm != null) {
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkPermission(packageName, perm, UserHandle.getUserId(uid));
|
||||
doReturn(PERMISSION_DENIED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
.checkUidPermission(uid, perm);
|
||||
mInjector.getAppPermissionTracker().onPermissionsChanged(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2406,6 +2544,11 @@ public final class BackgroundRestrictionTest {
|
||||
BackgroundRestrictionTest.class),
|
||||
BackgroundRestrictionTest.this);
|
||||
controller.addAppStateTracker(mAppBindServiceEventsTracker);
|
||||
mAppPermissionTracker = new AppPermissionTracker(mContext, controller,
|
||||
TestAppPermissionTrackerInjector.class.getDeclaredConstructor(
|
||||
BackgroundRestrictionTest.class),
|
||||
BackgroundRestrictionTest.this);
|
||||
controller.addAppStateTracker(mAppPermissionTracker);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Won't happen.
|
||||
}
|
||||
@@ -2500,6 +2643,11 @@ public final class BackgroundRestrictionTest {
|
||||
AppBatteryExemptionTracker getAppBatteryExemptionTracker() {
|
||||
return mAppBatteryExemptionTracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
AppPermissionTracker getAppPermissionTracker() {
|
||||
return mAppPermissionTracker;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestBaseTrackerInjector<T extends BaseAppStatePolicy>
|
||||
@@ -2564,6 +2712,14 @@ public final class BackgroundRestrictionTest {
|
||||
return BackgroundRestrictionTest.this.mNotificationManagerInternal;
|
||||
}
|
||||
|
||||
PackageManagerInternal getPackageManagerInternal() {
|
||||
return BackgroundRestrictionTest.this.mPackageManagerInternal;
|
||||
}
|
||||
|
||||
PermissionManager getPermissionManager() {
|
||||
return BackgroundRestrictionTest.this.mPermissionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
long getServiceStartForegroundTimeout() {
|
||||
return 1_000; // ms
|
||||
@@ -2594,6 +2750,10 @@ public final class BackgroundRestrictionTest {
|
||||
extends TestBaseTrackerInjector<AppMediaSessionPolicy> {
|
||||
}
|
||||
|
||||
private class TestAppPermissionTrackerInjector
|
||||
extends TestBaseTrackerInjector<AppPermissionPolicy> {
|
||||
}
|
||||
|
||||
private class TestAppBroadcastEventsTrackerInjector
|
||||
extends TestBaseTrackerInjector<AppBroadcastEventsPolicy> {
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user