Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0fe6a8ba authored by Pavel Grafov's avatar Pavel Grafov
Browse files

Use Owners in PolicyVersionUpgrader

Currently PolicyVersionUpgrader operates on device_policies.xml
files, that contain ActiveAdmin objects and some of the device state
Owners data is accessed during the upgrade but cannot be modified
thus making it impossible to migrate a field from Owners to
ActiveAdmin. With this change PolicyVersionUpgrader will access
Owners data directly by reading and writing XML files, which allows
such field migrations and more.

Also extracted path getters from DPMS Injector to reduce duplication
(separate path getters were used in Owners) and make it possible to
override those paths once and for all in tests.

Bug: 218639412
Test: atest com.android.server.devicepolicy
Change-Id: I26013c00f3422522fbf0b6b119fe23953756c6d0
parent 6b0d330d
Loading
Loading
Loading
Loading
+37 −46
Original line number Diff line number Diff line
@@ -279,7 +279,6 @@ import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -679,6 +678,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    final Context mContext;
    final Injector mInjector;
    final PolicyPathProvider mPathProvider;
    final IPackageManager mIPackageManager;
    final IPermissionManager mIPermissionManager;
    final UserManager mUserManager;
@@ -890,7 +890,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    @GuardedBy("getLockObject()")
    final SparseArray<DevicePolicyData> mUserData = new SparseArray<>();
    final SparseArray<DevicePolicyData> mUserData;
    @GuardedBy("getLockObject()")
@@ -1365,7 +1365,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        public final Context mContext;
        private @Nullable DevicePolicySafetyChecker mSafetyChecker;
        @Nullable private DevicePolicySafetyChecker mSafetyChecker;
        Injector(Context context) {
            mContext = context;
@@ -1384,12 +1384,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return mContext.getResources();
        }
        Owners newOwners() {
            return new Owners(getUserManager(), getUserManagerInternal(),
                    getPackageManagerInternal(), getActivityTaskManagerInternal(),
                    getActivityManagerInternal());
        }
        UserManager getUserManager() {
            return UserManager.get(mContext);
        }
@@ -1595,10 +1589,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return UserHandle.getUserId(binderGetCallingUid());
        }
        File environmentGetUserSystemDirectory(int userId) {
            return Environment.getUserSystemDirectory(userId);
        }
        void powerManagerGoToSleep(long time, int reason, int flags) {
            mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
        }
@@ -1641,10 +1631,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return UserManager.isHeadlessSystemUserMode();
        }
        String getDevicePolicyFilePathForSystemUser() {
            return "/data/system/";
        }
        @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
        PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode,
                @NonNull Intent intent, int flags, Bundle options, UserHandle user) {
@@ -1777,14 +1763,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
     * Instantiates the service.
     */
    public DevicePolicyManagerService(Context context) {
        this(new Injector(context.createAttributionContext(ATTRIBUTION_TAG)));
        this(new Injector(
                context.createAttributionContext(ATTRIBUTION_TAG)), new PolicyPathProvider() {});
    }
    @VisibleForTesting
    DevicePolicyManagerService(Injector injector) {
    DevicePolicyManagerService(Injector injector, PolicyPathProvider pathProvider) {
        DevicePolicyManager.disableLocalCaches();
        mInjector = injector;
        mPathProvider = pathProvider;
        mContext = Objects.requireNonNull(injector.mContext);
        mHandler = new Handler(Objects.requireNonNull(injector.getMyLooper()));
@@ -1792,8 +1780,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        mConstantsObserver.register();
        mConstants = loadConstants();
        mOwners = Objects.requireNonNull(injector.newOwners());
        mUserManager = Objects.requireNonNull(injector.getUserManager());
        mUserManagerInternal = Objects.requireNonNull(injector.getUserManagerInternal());
        mUsageStatsManagerInternal = Objects.requireNonNull(
@@ -1831,12 +1817,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        // "Lite" interface is available even when the device doesn't have the feature
        LocalServices.addService(DevicePolicyManagerLiteInternal.class, mLocalService);
        // Policy version upgrade must not depend on either mOwners or mUserData, so they are
        // initialized only after performing the upgrade.
        if (mHasFeature) {
            performPolicyVersionUpgrade();
        }
        mUserData = new SparseArray<>();
        mOwners = makeOwners(injector, pathProvider);
        if (!mHasFeature) {
            // Skip the rest of the initialization
            mSetupContentObserver = null;
            return;
        }
        loadOwners();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
        filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
@@ -1872,16 +1869,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                new RestrictionsListener(mContext, mUserManagerInternal, this));
        mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
        loadOwners();
        performPolicyVersionUpgrade();
        mDeviceManagementResourcesProvider.load();
        // The binder caches are not enabled until the first invalidation.
        invalidateBinderCaches();
    }
    private Owners makeOwners(Injector injector, PolicyPathProvider pathProvider) {
        return new Owners(injector.getUserManager(), injector.getUserManagerInternal(),
                injector.getPackageManagerInternal(),
                injector.getActivityTaskManagerInternal(),
                injector.getActivityManagerInternal(), pathProvider);
    }
    /**
     * Invalidate the binder API caches. The invalidation itself does not require any
     * locking, but this specific call should be protected by getLockObject() to ensure
@@ -1975,8 +1975,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                mUserData.remove(userHandle);
            }
            File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
                    DEVICE_POLICIES_XML);
            File policyFile =
                    new File(mPathProvider.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML);
            policyFile.delete();
            Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
        }
@@ -2879,8 +2879,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    private File getPolicyFileDirectory(@UserIdInt int userId) {
        return userId == UserHandle.USER_SYSTEM
                ? new File(mInjector.getDevicePolicyFilePathForSystemUser())
                : mInjector.environmentGetUserSystemDirectory(userId);
                ? mPathProvider.getDataSystemDirectory()
                : mPathProvider.getUserSystemDirectory(userId);
    }
    private JournaledFile makeJournaledFile(@UserIdInt int userId, String fileName) {
@@ -3087,13 +3087,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        updateUsbDataSignal();
    }
    // TODO(b/230841522) Make it static.
    private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider {
        @Override
        public boolean isDeviceOwner(int userId, ComponentName who) {
            return mOwners.isDeviceOwnerUserId(userId)
                    && mOwners.getDeviceOwnerComponent().equals(who);
        }
        @Override
        public boolean storageManagerIsFileBasedEncryptionEnabled() {
            return mInjector.storageManagerIsFileBasedEncryptionEnabled();
@@ -3109,15 +3104,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return DevicePolicyManagerService.this.makeJournaledFile(userId, POLICIES_VERSION_XML);
        }
        @Override
        public ComponentName getOwnerComponent(int userId) {
            return DevicePolicyManagerService.this.getOwnerComponent(userId);
        }
        @Override
        public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) {
            return component -> findAdmin(component, userId, /* throwForMissingPermission= */
                    false);
            return component ->
                    findAdmin(component, userId, /* throwForMissingPermission= */ false);
        }
        @Override
@@ -3128,7 +3118,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    private void performPolicyVersionUpgrade() {
        PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader(new DpmsUpgradeDataProvider());
        PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader(
                new DpmsUpgradeDataProvider(), mPathProvider);
        upgrader.upgradePolicy(DPMS_VERSION);
    }
@@ -16280,7 +16271,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        synchronized (getLockObject()) {
            final int callingUserId = caller.getUserId();
            final File bundleFile = new File(
                    mInjector.environmentGetUserSystemDirectory(callingUserId),
                    mPathProvider.getUserSystemDirectory(callingUserId),
                    TRANSFER_OWNERSHIP_PARAMETERS_XML);
            if (!bundleFile.exists()) {
                return null;
@@ -16474,7 +16465,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    @VisibleForTesting
    void saveTransferOwnershipBundleLocked(PersistableBundle bundle, int userId) {
        final File parametersFile = new File(
                mInjector.environmentGetUserSystemDirectory(userId),
                mPathProvider.getUserSystemDirectory(userId),
                TRANSFER_OWNERSHIP_PARAMETERS_XML);
        final AtomicFile atomicFile = new AtomicFile(parametersFile);
        FileOutputStream stream = null;
@@ -16496,7 +16487,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    void deleteTransferOwnershipBundleLocked(int userId) {
        final File parametersFile = new File(mInjector.environmentGetUserSystemDirectory(userId),
        final File parametersFile = new File(mPathProvider.getUserSystemDirectory(userId),
                TRANSFER_OWNERSHIP_PARAMETERS_XML);
        parametersFile.delete();
    }
+2 −12
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.devicepolicy.OwnersData.Injector;
import com.android.server.devicepolicy.OwnersData.OwnerInfo;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -78,28 +77,19 @@ class Owners {

    private boolean mSystemReady;

    public Owners(UserManager userManager,
            UserManagerInternal userManagerInternal,
            PackageManagerInternal packageManagerInternal,
            ActivityTaskManagerInternal activityTaskManagerInternal,
            ActivityManagerInternal activityManagerInternal) {
        this(userManager, userManagerInternal, packageManagerInternal,
                activityTaskManagerInternal, activityManagerInternal, new Injector());
    }

    @VisibleForTesting
    Owners(UserManager userManager,
            UserManagerInternal userManagerInternal,
            PackageManagerInternal packageManagerInternal,
            ActivityTaskManagerInternal activityTaskManagerInternal,
            ActivityManagerInternal activityManagerInternal,
            Injector injector) {
            PolicyPathProvider pathProvider) {
        mUserManager = userManager;
        mUserManagerInternal = userManagerInternal;
        mPackageManagerInternal = packageManagerInternal;
        mActivityTaskManagerInternal = activityTaskManagerInternal;
        mActivityManagerInternal = activityManagerInternal;
        mData = new OwnersData(injector);
        mData = new OwnersData(pathProvider);
    }

    /**
+19 −23
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
import android.os.Environment;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -106,10 +105,10 @@ class OwnersData {
    // Pending OTA info if there is one.
    @Nullable
    SystemUpdateInfo mSystemUpdateInfo;
    private final Injector mInjector;
    private final PolicyPathProvider mPathProvider;

    OwnersData(Injector injector) {
        mInjector = injector;
    OwnersData(PolicyPathProvider pathProvider) {
        mPathProvider = pathProvider;
    }

    void load(int[] allUsers) {
@@ -127,18 +126,24 @@ class OwnersData {
        }
    }

    void writeDeviceOwner() {
    /**
     * @return true upon success, false otherwise.
     */
    boolean writeDeviceOwner() {
        if (DEBUG) {
            Log.d(TAG, "Writing to device owner file");
        }
        new DeviceOwnerReadWriter().writeToFileLocked();
        return new DeviceOwnerReadWriter().writeToFileLocked();
    }

    void writeProfileOwner(int userId) {
    /**
     * @return true upon success, false otherwise.
     */
    boolean writeProfileOwner(int userId) {
        if (DEBUG) {
            Log.d(TAG, "Writing to profile owner file for user " + userId);
        }
        new ProfileOwnerReadWriter(userId).writeToFileLocked();
        return new ProfileOwnerReadWriter(userId).writeToFileLocked();
    }

    void dump(IndentingPrintWriter pw) {
@@ -206,12 +211,12 @@ class OwnersData {

    @VisibleForTesting
    File getDeviceOwnerFile() {
        return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML);
        return new File(mPathProvider.getDataSystemDirectory(), DEVICE_OWNER_XML);
    }

    @VisibleForTesting
    File getProfileOwnerFile(int userId) {
        return new File(mInjector.environmentGetUserSystemDirectory(userId), PROFILE_OWNER_XML);
        return new File(mPathProvider.getUserSystemDirectory(userId), PROFILE_OWNER_XML);
    }

    private abstract static class FileReadWriter {
@@ -223,7 +228,7 @@ class OwnersData {

        abstract boolean shouldWrite();

        void writeToFileLocked() {
        boolean writeToFileLocked() {
            if (!shouldWrite()) {
                if (DEBUG) {
                    Log.d(TAG, "No need to write to " + mFile);
@@ -237,7 +242,7 @@ class OwnersData {
                        Slog.e(TAG, "Failed to remove " + mFile.getPath());
                    }
                }
                return;
                return true;
            }
            if (DEBUG) {
                Log.d(TAG, "Writing to " + mFile);
@@ -270,7 +275,9 @@ class OwnersData {
                if (outputStream != null) {
                    f.failWrite(outputStream);
                }
                return false;
            }
            return true;
        }

        void readFromFileLocked() {
@@ -569,15 +576,4 @@ class OwnersData {
            pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice);
        }
    }

    @VisibleForTesting
    static class Injector {
        File environmentGetDataSystemDirectory() {
            return Environment.getDataSystemDirectory();
        }

        File environmentGetUserSystemDirectory(int userId) {
            return Environment.getUserSystemDirectory(userId);
        }
    }
}
+42 −0
Original line number Diff line number Diff line
/*
 * 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.devicepolicy;

import android.os.Environment;

import java.io.File;

/**
 * Interface providing directories for various DPMS files.
 */
public interface PolicyPathProvider {
    /**
     * Returns policy data directory for system user, typically /data/system
     * Used for SYSTEM_USER policies, device owner file and policy version file.
     */
    default File getDataSystemDirectory() {
        return Environment.getDataSystemDirectory();
    }

    /**
     * Returns policy data directory for a given user, typically /data/system/users/$userId
     * Used for non-system user policies and profile owner files.
     */
    default File getUserSystemDirectory(int userId) {
        return Environment.getUserSystemDirectory(userId);
    }
}
+0 −12
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.devicepolicy;

import android.annotation.Nullable;
import android.app.admin.DeviceAdminInfo;
import android.content.ComponentName;

@@ -29,12 +28,6 @@ import java.util.function.Function;
 * to go through the upgrade process.
 */
public interface PolicyUpgraderDataProvider {
    /**
     * Returns true if the provided {@code userId} is a device owner. May affect some policy
     * defaults.
     */
    boolean isDeviceOwner(int userId, ComponentName who);

    /**
     * Returns true if the storage manager indicates file-based encryption is enabled.
     */
@@ -50,11 +43,6 @@ public interface PolicyUpgraderDataProvider {
     */
    JournaledFile makePoliciesVersionJournaledFile(int userId);

    /**
     * Returns the {@code ComponentName} of the owner component for a user.
     */
    @Nullable ComponentName getOwnerComponent(int userId);

    /**
     * Returns a function which provides the component name and device admin info for a given
     * user.
Loading