Merge "Change exact alarm permission to be denied by default"

This commit is contained in:
TreeHugger Robot
2022-12-08 19:36:13 +00:00
committed by Android (Google) Code Review
4 changed files with 1075 additions and 55 deletions

View File

@@ -27,7 +27,6 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -285,11 +284,10 @@ public class AlarmManager {
* The permission {@link Manifest.permission#SCHEDULE_EXACT_ALARM} will be denied, unless the
* user explicitly allows it from Settings.
*
* TODO (b/226439802): Either enable it in the next SDK or replace it with a better alternative.
* @hide
*/
@ChangeId
@Disabled
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
public static final long SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = 226439802L;
@UnsupportedAppUsage

View File

@@ -44,6 +44,7 @@ import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.app.AppOpsManager.OP_SCHEDULE_EXACT_ALARM;
import static android.app.AppOpsManager.OP_VIBRATE;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
@@ -130,6 +131,8 @@ import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.component.ParsedAttribution;
@@ -163,12 +166,30 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
static final String TAG = "AppOps";
static final boolean DEBUG = false;
/**
* Sentinel integer version to denote that there was no appops.xml found on boot.
* This will happen when a device boots with no existing userdata.
*/
private static final int NO_FILE_VERSION = -2;
/**
* Sentinel integer version to denote that there was no version in the appops.xml found on boot.
* This means the file is coming from a build before versioning was added.
*/
private static final int NO_VERSION = -1;
/**
* Increment by one every time and add the corresponding upgrade logic in
* {@link #upgradeLocked(int)} below. The first version was 1
* {@link #upgradeLocked(int)} below. The first version was 1.
*/
private static final int CURRENT_VERSION = 1;
@VisibleForTesting
static final int CURRENT_VERSION = 2;
/**
* This stores the version of appops.xml seen at boot. If this is smaller than
* {@link #CURRENT_VERSION}, then we will run {@link #upgradeLocked(int)} on startup.
*/
private int mVersionAtBoot = NO_FILE_VERSION;
// Write at most every 30 minutes.
static final long WRITE_DELAY = DEBUG ? 1000 : 30 * 60 * 1000;
@@ -936,6 +957,10 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
@Override
public void systemReady() {
synchronized (this) {
upgradeLocked(mVersionAtBoot);
}
mConstants.startMonitoring(mContext.getContentResolver());
mHistoricalRegistry.systemReady(mContext.getContentResolver());
@@ -3191,7 +3216,6 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
@Override
public void readState() {
int oldVersion = NO_VERSION;
synchronized (mFile) {
synchronized (this) {
FileInputStream stream;
@@ -3216,7 +3240,7 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
throw new IllegalStateException("no start tag found");
}
oldVersion = parser.getAttributeInt(null, "v", NO_VERSION);
mVersionAtBoot = parser.getAttributeInt(null, "v", NO_VERSION);
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -3261,12 +3285,11 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
}
}
}
synchronized (this) {
upgradeLocked(oldVersion);
}
}
private void upgradeRunAnyInBackgroundLocked() {
@VisibleForTesting
@GuardedBy("this")
void upgradeRunAnyInBackgroundLocked() {
for (int i = 0; i < mUidStates.size(); i++) {
final UidState uidState = mUidStates.valueAt(i);
if (uidState == null) {
@@ -3303,8 +3326,45 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
}
}
/**
* The interpretation of the default mode - MODE_DEFAULT - for OP_SCHEDULE_EXACT_ALARM is
* changing. Simultaneously, we want to change this op's mode from MODE_DEFAULT to MODE_ALLOWED
* for already installed apps. For newer apps, it will stay as MODE_DEFAULT.
*/
@VisibleForTesting
@GuardedBy("this")
void upgradeScheduleExactAlarmLocked() {
final PermissionManagerServiceInternal pmsi = LocalServices.getService(
PermissionManagerServiceInternal.class);
final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
final PackageManagerInternal pmi = getPackageManagerInternal();
final String[] packagesDeclaringPermission = pmsi.getAppOpPermissionPackages(
AppOpsManager.opToPermission(OP_SCHEDULE_EXACT_ALARM));
final int[] userIds = umi.getUserIds();
for (final String pkg : packagesDeclaringPermission) {
for (int userId : userIds) {
final int uid = pmi.getPackageUid(pkg, 0, userId);
UidState uidState = mUidStates.get(uid);
if (uidState == null) {
uidState = new UidState(uid);
mUidStates.put(uid, uidState);
}
final int oldMode = uidState.getUidMode(OP_SCHEDULE_EXACT_ALARM);
if (oldMode == AppOpsManager.opToDefaultMode(OP_SCHEDULE_EXACT_ALARM)) {
uidState.setUidMode(OP_SCHEDULE_EXACT_ALARM, MODE_ALLOWED);
}
}
// This appop is meant to be controlled at a uid level. So we leave package modes as
// they are.
}
}
@GuardedBy("this")
private void upgradeLocked(int oldVersion) {
if (oldVersion >= CURRENT_VERSION) {
if (oldVersion == NO_FILE_VERSION || oldVersion >= CURRENT_VERSION) {
return;
}
Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
@@ -3313,6 +3373,9 @@ class AppOpsServiceImpl implements AppOpsServiceInterface {
upgradeRunAnyInBackgroundLocked();
// fall through
case 1:
upgradeScheduleExactAlarmLocked();
// fall through
case 2:
// for future upgrades
}
scheduleFastWriteLocked();

View File

@@ -0,0 +1,781 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<app-ops v="1">
<uid n="1001">
<op n="0" m="4" />
<op n="1" m="4" />
<op n="15" m="0" />
<op n="27" m="4" />
<op n="87" m="1" />
</uid>
<uid n="1002">
<op n="0" m="4" />
<op n="1" m="4" />
<op n="15" m="0" />
<op n="87" m="1" />
</uid>
<uid n="10077">
<op n="87" m="1" />
</uid>
<uid n="10079">
<op n="116" m="1" />
</uid>
<uid n="10080">
<op n="87" m="1" />
</uid>
<uid n="10081">
<op n="87" m="1" />
</uid>
<uid n="10086">
<op n="87" m="1" />
</uid>
<uid n="10087">
<op n="59" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10090">
<op n="0" m="4" />
<op n="1" m="4" />
</uid>
<uid n="10096">
<op n="0" m="1" />
<op n="1" m="1" />
</uid>
<uid n="10112">
<op n="11" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="62" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10113">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="51" m="1" />
<op n="62" m="1" />
</uid>
<uid n="10114">
<op n="4" m="1" />
</uid>
<uid n="10115">
<op n="0" m="1" />
</uid>
<uid n="10116">
<op n="0" m="1" />
</uid>
<uid n="10117">
<op n="0" m="4" />
<op n="1" m="4" />
<op n="13" m="1" />
<op n="14" m="1" />
<op n="16" m="1" />
<op n="26" m="4" />
<op n="27" m="4" />
</uid>
<uid n="10118">
<op n="51" m="1" />
</uid>
<uid n="10119">
<op n="11" m="1" />
<op n="77" m="1" />
<op n="111" m="1" />
</uid>
<uid n="10120">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="4" m="1" />
<op n="6" m="1" />
<op n="7" m="1" />
<op n="11" m="1" />
<op n="13" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="54" m="1" />
<op n="59" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10121">
<op n="59" m="1" />
<op n="60" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10122">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10123">
<op n="0" m="4" />
<op n="1" m="4" />
<op n="87" m="1" />
</uid>
<uid n="10124">
<op n="11" m="1" />
<op n="26" m="1" />
</uid>
<uid n="10125">
<op n="11" m="1" />
</uid>
<uid n="10127">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="26" m="4" />
<op n="27" m="4" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="65" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
<op n="111" m="1" />
</uid>
<uid n="10129">
<op n="0" m="1" />
<op n="1" m="1" />
</uid>
<uid n="10130">
<op n="51" m="1" />
</uid>
<uid n="10131">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10132">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="69" m="1" />
<op n="79" m="1" />
</uid>
<uid n="10133">
<op n="11" m="1" />
</uid>
<uid n="10136">
<op n="0" m="1" />
<op n="4" m="1" />
<op n="77" m="1" />
<op n="87" m="1" />
<op n="111" m="1" />
<op n="114" m="1" />
</uid>
<uid n="10137">
<op n="62" m="1" />
</uid>
<uid n="10138">
<op n="26" m="4" />
</uid>
<uid n="10140">
<op n="26" m="4" />
<op n="27" m="4" />
<op n="87" m="1" />
</uid>
<uid n="10141">
<op n="11" m="1" />
<op n="27" m="1" />
<op n="111" m="1" />
</uid>
<uid n="10142">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="11" m="1" />
</uid>
<uid n="10144">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="4" m="1" />
<op n="11" m="1" />
<op n="27" m="4" />
<op n="111" m="1" />
</uid>
<uid n="10145">
<op n="11" m="1" />
</uid>
<uid n="10149">
<op n="11" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10150">
<op n="51" m="1" />
</uid>
<uid n="10151">
<op n="11" m="1" />
</uid>
<uid n="10152">
<op n="11" m="1" />
</uid>
<uid n="10154">
<op n="0" m="4" />
<op n="1" m="4" />
<op n="27" m="4" />
</uid>
<uid n="10155">
<op n="0" m="1" />
<op n="1" m="1" />
</uid>
<uid n="10157">
<op n="13" m="1" />
</uid>
<uid n="10158">
<op n="11" m="1" />
</uid>
<uid n="10160">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="11" m="1" />
<op n="26" m="4" />
<op n="27" m="4" />
<op n="87" m="1" />
</uid>
<uid n="10161">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="11" m="1" />
<op n="51" m="1" />
<op n="77" m="1" />
<op n="87" m="1" />
<op n="111" m="1" />
<op n="114" m="1" />
</uid>
<uid n="10162">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="15" m="0" />
<op n="26" m="4" />
<op n="27" m="4" />
<op n="87" m="1" />
<op n="89" m="0" />
</uid>
<uid n="10163">
<op n="26" m="4" />
<op n="27" m="4" />
<op n="56" m="4" />
<op n="87" m="1" />
</uid>
<uid n="10164">
<op n="26" m="1" />
<op n="27" m="4" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="69" m="1" />
<op n="79" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10169">
<op n="11" m="1" />
</uid>
<uid n="10170">
<op n="87" m="1" />
</uid>
<uid n="10171">
<op n="26" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10172">
<op n="11" m="1" />
</uid>
<uid n="10173">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="23" m="0" />
<op n="26" m="1" />
<op n="51" m="1" />
<op n="62" m="1" />
<op n="65" m="1" />
</uid>
<uid n="10175">
<op n="0" m="1" />
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
</uid>
<uid n="10178">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="11" m="1" />
<op n="27" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10179">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="4" m="1" />
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="62" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10180">
<op n="11" m="1" />
</uid>
<uid n="10181">
<op n="4" m="1" />
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="59" m="1" />
<op n="62" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="1110181">
<op n="4" m="1" />
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
<op n="107" m="2" />
</uid>
<uid n="10182">
<op n="27" m="4" />
</uid>
<uid n="10183">
<op n="11" m="1" />
<op n="26" m="4" />
</uid>
<uid n="10184">
<op n="4" m="1" />
<op n="11" m="1" />
<op n="13" m="1" />
<op n="26" m="1" />
<op n="27" m="4" />
</uid>
<uid n="10185">
<op n="8" m="1" />
<op n="59" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10187">
<op n="11" m="1" />
</uid>
<uid n="10189">
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="51" m="1" />
</uid>
<uid n="10190">
<op n="0" m="1" />
<op n="13" m="1" />
</uid>
<uid n="10191">
<op n="11" m="1" />
</uid>
<uid n="10192">
<op n="11" m="1" />
<op n="13" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10193">
<op n="11" m="1" />
</uid>
<uid n="10197">
<op n="11" m="1" />
</uid>
<uid n="10198">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="4" m="1" />
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="77" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
<op n="90" m="1" />
<op n="107" m="0" />
<op n="111" m="1" />
</uid>
<uid n="10199">
<op n="4" m="1" />
<op n="11" m="1" />
<op n="26" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="62" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10200">
<op n="11" m="1" />
<op n="65" m="1" />
<op n="107" m="1" />
</uid>
<uid n="1110200">
<op n="11" m="1" />
<op n="65" m="1" />
<op n="107" m="2" />
</uid>
<uid n="10201">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="4" m="1" />
<op n="11" m="1" />
<op n="51" m="1" />
<op n="62" m="1" />
<op n="84" m="0" />
<op n="86" m="0" />
<op n="87" m="1" />
</uid>
<uid n="10206">
<op n="0" m="4" />
<op n="1" m="4" />
<op n="26" m="4" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10209">
<op n="11" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10210">
<op n="51" m="1" />
</uid>
<uid n="10212">
<op n="11" m="1" />
<op n="62" m="1" />
</uid>
<uid n="10214">
<op n="26" m="4" />
</uid>
<uid n="10216">
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10225">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="51" m="1" />
<op n="59" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10229">
<op n="11" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="62" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10231">
<op n="51" m="1" />
</uid>
<uid n="10232">
<op n="51" m="1" />
</uid>
<uid n="10234">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="11" m="1" />
<op n="13" m="1" />
<op n="20" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10235">
<op n="59" m="1" />
<op n="60" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10237">
<op n="0" m="4" />
<op n="1" m="4" />
</uid>
<uid n="10238">
<op n="26" m="4" />
<op n="27" m="4" />
<op n="87" m="1" />
</uid>
<uid n="10240">
<op n="112" m="1" />
</uid>
<uid n="10241">
<op n="59" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10245">
<op n="13" m="1" />
<op n="51" m="1" />
</uid>
<uid n="10247">
<op n="0" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="0" />
<op n="90" m="1" />
</uid>
<uid n="10254">
<op n="11" m="1" />
</uid>
<uid n="10255">
<op n="11" m="1" />
</uid>
<uid n="10256">
<op n="87" m="1" />
</uid>
<uid n="10258">
<op n="11" m="1" />
</uid>
<uid n="10260">
<op n="51" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="87" m="1" />
</uid>
<uid n="10262">
<op n="15" m="0" />
</uid>
<uid n="10266">
<op n="0" m="4" />
</uid>
<uid n="10267">
<op n="0" m="1" />
<op n="1" m="1" />
<op n="4" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="62" m="1" />
<op n="77" m="1" />
<op n="81" m="1" />
<op n="83" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
<op n="107" m="2" />
<op n="111" m="1" />
</uid>
<uid n="10268">
<op n="4" m="1" />
<op n="11" m="1" />
<op n="62" m="1" />
</uid>
<uid n="10269">
<op n="11" m="1" />
<op n="26" m="1" />
<op n="27" m="1" />
<op n="59" m="1" />
<op n="60" m="1" />
<op n="85" m="1" />
<op n="87" m="1" />
</uid>
<pkg n="com.google.android.iwlan">
<uid n="0">
<op n="1" />
<op n="75" m="0" />
</uid>
</pkg>
<pkg n="com.android.phone">
<uid n="0">
<op n="1" />
<op n="75" m="0" />
</uid>
</pkg>
<pkg n="android">
<uid n="1000">
<op n="0">
<st n="214748364801" t="1670287941040" />
</op>
<op n="4">
<st n="214748364801" t="1670289665522" />
</op>
<op n="6">
<st n="214748364801" t="1670287946650" />
</op>
<op n="8">
<st n="214748364801" t="1670289624396" />
</op>
<op n="14">
<st n="214748364801" t="1670287951031" />
</op>
<op n="40">
<st n="214748364801" t="1670291786337" d="156" />
</op>
<op n="41">
<st id="SensorNotificationService" n="214748364801" t="1670287585567" d="4251183" />
<st id="CountryDetector" n="214748364801" t="1670287583306" d="6700" />
</op>
<op n="43">
<st n="214748364801" r="1670291755062" />
</op>
<op n="61">
<st n="214748364801" r="1670291754997" />
</op>
<op n="105">
<st n="214748364801" r="1670291473903" />
<st id="GnssService" n="214748364801" r="1670288044920" />
</op>
<op n="111">
<st n="214748364801" t="1670291441554" />
</op>
</uid>
</pkg>
<pkg n="com.android.server.telecom">
<uid n="1000">
<op n="6">
<st n="214748364801" t="1670287609092" />
</op>
<op n="111">
<st n="214748364801" t="1670287583728" />
</op>
</uid>
</pkg>
<pkg n="com.android.settings">
<uid n="1000">
<op n="43">
<st n="214748364801" r="1670291447349" />
</op>
<op n="105">
<st n="214748364801" r="1670291399231" />
</op>
<op n="111">
<st n="214748364801" t="1670291756910" />
</op>
</uid>
</pkg>
<pkg n="com.android.phone">
<uid n="1001">
<op n="15">
<st n="214748364801" t="1670287951022" />
</op>
<op n="40">
<st n="214748364801" t="1670291786177" />
</op>
<op n="105">
<st n="214748364801" r="1670291756403" />
</op>
</uid>
</pkg>
<pkg n="com.android.bluetooth">
<uid n="1002">
<op n="4">
<st n="214748364801" t="1670289671076" />
</op>
<op n="40">
<st n="214748364801" t="1670287585676" d="8" />
</op>
<op n="43">
<st n="214748364801" r="1670287585818" />
</op>
<op n="77">
<st n="214748364801" t="1670288037629" />
</op>
<op n="111">
<st n="214748364801" t="1670287592081" />
</op>
</uid>
</pkg>
<pkg n="com.android.vending">
<uid n="10136">
<op n="40">
<st n="429496729601" t="1670289621210" d="114" />
<st n="858993459201" t="1670289879730" d="349" />
<st n="1288490188801" t="1670287942622" d="937" />
</op>
<op n="43">
<st n="429496729601" r="1670289755305" />
<st n="858993459201" r="1670288019246" />
<st n="1073741824001" r="1670289571783" />
<st n="1288490188801" r="1670289373336" />
</op>
<op n="76">
<st n="429496729601" t="1670289748735" d="15991" />
<st n="858993459201" t="1670291395180" d="79201" />
<st n="1073741824001" t="1670291395168" d="12" />
<st n="1288490188801" t="1670291526029" d="3" />
<st n="1503238553601" t="1670291526032" d="310718" />
</op>
<op n="105">
<st n="429496729601" r="1670289538910" />
<st n="858993459201" r="1670288054519" />
<st n="1073741824001" r="1670287599379" />
<st n="1288490188801" r="1670289526854" />
<st n="1503238553601" r="1670289528242" />
</op>
</uid>
</pkg>
<pkg n="com.android.nfc">
<uid n="1027">
<op n="40">
<st n="214748364801" t="1670291786330" d="22" />
</op>
</uid>
</pkg>
</app-ops>

View File

@@ -16,23 +16,32 @@
package com.android.server.appop;
import static android.app.AppOpsManager.OP_SCHEDULE_EXACT_ALARM;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.AssetManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -42,11 +51,20 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.LocalServices;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
import org.xmlpull.v1.XmlPullParser;
import java.io.File;
@@ -64,29 +82,39 @@ public class AppOpsUpgradeTest {
private static final String TAG = AppOpsUpgradeTest.class.getSimpleName();
private static final String APP_OPS_UNVERSIONED_ASSET_PATH =
"AppOpsUpgradeTest/appops-unversioned.xml";
private static final String APP_OPS_VERSION_1_ASSET_PATH =
"AppOpsUpgradeTest/appops-version-1.xml";
private static final String APP_OPS_FILENAME = "appops-test.xml";
private static final int NON_DEFAULT_OPS_IN_FILE = 4;
private static final int CURRENT_VERSION = 1;
private File mAppOpsFile;
private Context mContext;
private static final Context sContext = InstrumentationRegistry.getTargetContext();
private static final File sAppOpsFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME);
private Context mTestContext;
private MockitoSession mMockitoSession;
@Mock
private PackageManagerInternal mPackageManagerInternal;
@Mock
private PackageManager mPackageManager;
@Mock
private UserManagerInternal mUserManagerInternal;
@Mock
private PermissionManagerServiceInternal mPermissionManagerInternal;
@Mock
private Handler mHandler;
private void extractAppOpsFile() {
mAppOpsFile.getParentFile().mkdirs();
if (mAppOpsFile.exists()) {
mAppOpsFile.delete();
}
try (FileOutputStream out = new FileOutputStream(mAppOpsFile);
InputStream in = mContext.getAssets().open(APP_OPS_UNVERSIONED_ASSET_PATH,
AssetManager.ACCESS_BUFFER)) {
private static void extractAppOpsFile(String assetPath) {
sAppOpsFile.getParentFile().mkdirs();
try (FileOutputStream out = new FileOutputStream(sAppOpsFile);
InputStream in = sContext.getAssets().open(assetPath, AssetManager.ACCESS_BUFFER)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
out.flush();
Log.d(TAG, "Successfully copied xml to " + mAppOpsFile.getAbsolutePath());
Log.d(TAG, "Successfully copied xml to " + sAppOpsFile.getAbsolutePath());
} catch (IOException exc) {
Log.e(TAG, "Exception while copying appops xml", exc);
fail();
@@ -98,7 +126,7 @@ public class AppOpsUpgradeTest {
int numberOfNonDefaultOps = 0;
final int defaultModeOp1 = AppOpsManager.opToDefaultMode(op1);
final int defaultModeOp2 = AppOpsManager.opToDefaultMode(op2);
for(int i = 0; i < uidStates.size(); i++) {
for (int i = 0; i < uidStates.size(); i++) {
final AppOpsServiceImpl.UidState uidState = uidStates.valueAt(i);
SparseIntArray opModes = uidState.getNonDefaultUidModes();
if (opModes != null) {
@@ -132,41 +160,191 @@ public class AppOpsUpgradeTest {
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
extractAppOpsFile();
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
if (sAppOpsFile.exists()) {
sAppOpsFile.delete();
}
mMockitoSession = mockitoSession()
.initMocks(this)
.spyStatic(LocalServices.class)
.mockStatic(SystemServerInitThreadPool.class)
.strictness(Strictness.LENIENT)
.startMocking();
doReturn(mPermissionManagerInternal).when(
() -> LocalServices.getService(PermissionManagerServiceInternal.class));
doReturn(mUserManagerInternal).when(
() -> LocalServices.getService(UserManagerInternal.class));
doReturn(mPackageManagerInternal).when(
() -> LocalServices.getService(PackageManagerInternal.class));
mTestContext = spy(sContext);
// Pretend everybody has all permissions
doNothing().when(mTestContext).enforcePermission(anyString(), anyInt(), anyInt(),
nullable(String.class));
doReturn(mPackageManager).when(mTestContext).getPackageManager();
// Stub out package calls to disable AppOpsService#updatePermissionRevokedCompat
doReturn(null).when(mPackageManager).getPackagesForUid(anyInt());
}
@After
public void tearDown() {
mMockitoSession.finishMocking();
}
@Test
public void testUpgradeFromNoVersion() throws Exception {
AppOpsDataParser parser = new AppOpsDataParser(mAppOpsFile);
public void upgradeRunAnyInBackground() {
extractAppOpsFile(APP_OPS_UNVERSIONED_ASSET_PATH);
AppOpsServiceImpl testService = new AppOpsServiceImpl(sAppOpsFile, mHandler, mTestContext);
testService.upgradeRunAnyInBackgroundLocked();
assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND,
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
}
private static int getModeInFile(int uid) {
switch (uid) {
case 10198:
return 0;
case 10200:
return 1;
case 1110200:
case 10267:
case 1110181:
return 2;
default:
return AppOpsManager.opToDefaultMode(OP_SCHEDULE_EXACT_ALARM);
}
}
@Test
public void upgradeScheduleExactAlarm() {
extractAppOpsFile(APP_OPS_VERSION_1_ASSET_PATH);
String[] packageNames = {"p1", "package2", "pkg3", "package.4", "pkg-5", "pkg.6"};
int[] appIds = {10267, 10181, 10198, 10199, 10200, 4213};
int[] userIds = {0, 10, 11};
doReturn(userIds).when(mUserManagerInternal).getUserIds();
doReturn(packageNames).when(mPermissionManagerInternal).getAppOpPermissionPackages(
AppOpsManager.opToPermission(OP_SCHEDULE_EXACT_ALARM));
doAnswer(invocation -> {
String pkg = invocation.getArgument(0);
int index = ArrayUtils.indexOf(packageNames, pkg);
if (index < 0) {
return index;
}
int userId = invocation.getArgument(2);
return UserHandle.getUid(userId, appIds[index]);
}).when(mPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
AppOpsServiceImpl testService = new AppOpsServiceImpl(sAppOpsFile, mHandler, mTestContext);
testService.upgradeScheduleExactAlarmLocked();
for (int userId : userIds) {
for (int appId : appIds) {
final int uid = UserHandle.getUid(userId, appId);
final int previousMode = getModeInFile(uid);
final int expectedMode;
if (previousMode == AppOpsManager.opToDefaultMode(OP_SCHEDULE_EXACT_ALARM)) {
expectedMode = AppOpsManager.MODE_ALLOWED;
} else {
expectedMode = previousMode;
}
final AppOpsServiceImpl.UidState uidState = testService.mUidStates.get(uid);
assertEquals(expectedMode, uidState.getUidMode(OP_SCHEDULE_EXACT_ALARM));
}
}
// These uids don't even declare the permission. So should stay as default / empty.
int[] unrelatedUidsInFile = {10225, 10178};
for (int uid : unrelatedUidsInFile) {
final AppOpsServiceImpl.UidState uidState = testService.mUidStates.get(uid);
assertEquals(AppOpsManager.opToDefaultMode(OP_SCHEDULE_EXACT_ALARM),
uidState.getUidMode(OP_SCHEDULE_EXACT_ALARM));
}
}
@Test
public void upgradeFromNoFile() {
assertFalse(sAppOpsFile.exists());
AppOpsServiceImpl testService = spy(
new AppOpsServiceImpl(sAppOpsFile, mHandler, mTestContext));
doNothing().when(testService).upgradeRunAnyInBackgroundLocked();
doNothing().when(testService).upgradeScheduleExactAlarmLocked();
// trigger upgrade
testService.systemReady();
verify(testService, never()).upgradeRunAnyInBackgroundLocked();
verify(testService, never()).upgradeScheduleExactAlarmLocked();
testService.writeState();
assertTrue(sAppOpsFile.exists());
AppOpsDataParser parser = new AppOpsDataParser(sAppOpsFile);
assertTrue(parser.parse());
assertEquals(AppOpsServiceImpl.CURRENT_VERSION, parser.mVersion);
}
@Test
public void upgradeFromNoVersion() {
extractAppOpsFile(APP_OPS_UNVERSIONED_ASSET_PATH);
AppOpsDataParser parser = new AppOpsDataParser(sAppOpsFile);
assertTrue(parser.parse());
assertEquals(AppOpsDataParser.NO_VERSION, parser.mVersion);
// Use mock context and package manager to fake permision package manager calls.
Context testContext = spy(mContext);
// Pretent everybody has all permissions
doNothing().when(testContext).enforcePermission(anyString(), anyInt(), anyInt(),
nullable(String.class));
PackageManager testPM = mock(PackageManager.class);
when(testContext.getPackageManager()).thenReturn(testPM);
// Stub out package calls to disable AppOpsService#updatePermissionRevokedCompat
when(testPM.getPackagesForUid(anyInt())).thenReturn(null);
AppOpsServiceImpl testService = spy(
new AppOpsServiceImpl(mAppOpsFile, mHandler, testContext)); // trigger upgrade
assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND,
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
mHandler.removeCallbacks(testService.mWriteRunner);
new AppOpsServiceImpl(sAppOpsFile, mHandler, mTestContext));
doNothing().when(testService).upgradeRunAnyInBackgroundLocked();
doNothing().when(testService).upgradeScheduleExactAlarmLocked();
// trigger upgrade
testService.systemReady();
verify(testService).upgradeRunAnyInBackgroundLocked();
verify(testService).upgradeScheduleExactAlarmLocked();
testService.writeState();
assertTrue(parser.parse());
assertEquals(CURRENT_VERSION, parser.mVersion);
assertEquals(AppOpsServiceImpl.CURRENT_VERSION, parser.mVersion);
}
@Test
public void upgradeFromVersion1() {
extractAppOpsFile(APP_OPS_VERSION_1_ASSET_PATH);
AppOpsDataParser parser = new AppOpsDataParser(sAppOpsFile);
assertTrue(parser.parse());
assertEquals(1, parser.mVersion);
AppOpsServiceImpl testService = spy(
new AppOpsServiceImpl(sAppOpsFile, mHandler, mTestContext));
doNothing().when(testService).upgradeRunAnyInBackgroundLocked();
doNothing().when(testService).upgradeScheduleExactAlarmLocked();
// trigger upgrade
testService.systemReady();
verify(testService, never()).upgradeRunAnyInBackgroundLocked();
verify(testService).upgradeScheduleExactAlarmLocked();
testService.writeState();
assertTrue(parser.parse());
assertEquals(AppOpsServiceImpl.CURRENT_VERSION, parser.mVersion);
}
/**
@@ -174,7 +352,7 @@ public class AppOpsUpgradeTest {
* Other fields may be added as and when required for testing.
*/
private static final class AppOpsDataParser {
static final int NO_VERSION = -1;
static final int NO_VERSION = -123;
int mVersion;
private File mFile;