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

Commit d1a18160 authored by Azhara Assanova's avatar Azhara Assanova
Browse files

[AAPM] Disallow Install Unknown Sources Hook

Implement an AdvancedProtectionHook class for disallowing install unknown
sources via DevicePolicyManager restriction
DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY.

To do the above, this change introduces two hidden APIs in
DevicePolicyManager that allow setting global restrictions for system
components. They mimic the existing hidden APIs for setting local
restricitons for system components.

Bug: 369361373
Test: manually tested the restriction is set even after reboot
Test: atest AdvancedProtectionManagerTest
Test: atest AdvancedProtectionServiceTest
Test: atest DisallowInstallUnknownSourcesTest
Flag: android.security.aapm_feature_disable_install_unknown_sources
Change-Id: I80722ee489a79a316cd54f171a180b609effd80f
parent 913e30ed
Loading
Loading
Loading
Loading
+54 −0
Original line number Diff line number Diff line
@@ -12101,6 +12101,33 @@ public class DevicePolicyManager {
        }
    }
    /**
     * Adds a user restriction globally, specified by the {@code key}.
     *
     * <p>Called by a system service only, meaning that the caller's UID must be equal to
     * {@link Process#SYSTEM_UID}.
     *
     * @param systemEntity The service entity that adds the restriction. A user restriction set by
     *                     a service entity can only be cleared by the same entity. This can be
     *                     just the calling package name, or any string of the caller's choice
     *                     can be used.
     * @param key The key of the restriction.
     * @throws SecurityException if the caller is not a system service.
     *
     * @hide
     */
    public void addUserRestrictionGlobally(@NonNull String systemEntity,
            @NonNull @UserManager.UserRestrictionKey String key) {
        if (mService != null) {
            try {
                mService.setUserRestrictionGloballyFromSystem(systemEntity, key,
                        /* enable= */ true);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
    /**
     * Called by a profile owner, device owner or a holder of any permission that is associated with
     * a user restriction to clear a user restriction specified by the key.
@@ -12186,6 +12213,33 @@ public class DevicePolicyManager {
        }
    }
    /**
     * Clears a user restriction globally, specified by the {@code key}.
     *
     * <p>Called by a system service only, meaning that the caller's UID must be equal to
     * {@link Process#SYSTEM_UID}.
     *
     * @param systemEntity The system entity that clears the restriction. A user restriction
     *                     set by a system entity can only be cleared by the same entity. This
     *                     can be just the calling package name, or any string of the caller's
     *                     choice can be used.
     * @param key The key of the restriction.
     * @throws SecurityException if the caller is not a system service.
     *
     * @hide
     */
    public void clearUserRestrictionGlobally(@NonNull String systemEntity,
            @NonNull @UserManager.UserRestrictionKey String key) {
        if (mService != null) {
            try {
                mService.setUserRestrictionGloballyFromSystem(systemEntity, key,
                        /* enable= */ false);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
    /**
     * Called by an admin to get user restrictions set by themselves with
     * {@link #addUserRestriction(ComponentName, String)}.
+1 −0
Original line number Diff line number Diff line
@@ -257,6 +257,7 @@ interface IDevicePolicyManager {
    void setUserRestriction(in ComponentName who, in String callerPackage, in String key, boolean enable, boolean parent);
    void setUserRestrictionForUser(in String systemEntity, in String key, boolean enable, int targetUser);
    void setUserRestrictionGlobally(in String callerPackage, in String key);
    void setUserRestrictionGloballyFromSystem(in String systemEntity, in String key, boolean enable);
    Bundle getUserRestrictions(in ComponentName who, in String callerPackage, boolean parent);
    Bundle getUserRestrictionsGlobally(in String callerPackage);

+7 −0
Original line number Diff line number Diff line
@@ -103,3 +103,10 @@ flag {
    description: "Applies intentMatchingFlags while matching intents to application components"
    bug: "364354494"
}

flag {
    name: "aapm_feature_disable_install_unknown_sources"
    namespace: "responsible_apis"
    description: "Android Advanced Protection Mode Feature: Disable Install Unknown Sources"
    bug: "369361373"
}
+4 −4
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.security.advancedprotection.features.AdvancedProtectionHook;
import com.android.server.security.advancedprotection.features.AdvancedProtectionProvider;
import com.android.server.security.advancedprotection.features.DisallowInstallUnknownSourcesAdvancedProtectionHook;

import java.io.FileDescriptor;
import java.util.ArrayList;
@@ -76,10 +77,9 @@ public class AdvancedProtectionService extends IAdvancedProtectionService.Stub
    }

    private void initFeatures(boolean enabled) {
        // Empty until features are added.
        // Examples:
        // mHooks.add(new SideloadingAdvancedProtectionHook(mContext, enabled));
        // mProviders.add(new WifiAdvancedProtectionProvider());
        if (android.security.Flags.aapmFeatureDisableInstallUnknownSources()) {
            mHooks.add(new DisallowInstallUnknownSourcesAdvancedProtectionHook(mContext, enabled));
        }
    }

    // Only for tests
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.security.advancedprotection.features;

import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;

import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.UserManager;
import android.security.advancedprotection.AdvancedProtectionFeature;
import android.util.Slog;

/** @hide */
public final class DisallowInstallUnknownSourcesAdvancedProtectionHook
        extends AdvancedProtectionHook {
    private static final String TAG = "AdvancedProtectionDisallowInstallUnknown";

    private final AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature(
            FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES);
    private final DevicePolicyManager mDevicePolicyManager;

    public DisallowInstallUnknownSourcesAdvancedProtectionHook(@NonNull Context context,
            boolean enabled) {
        super(context, enabled);
        mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
        onAdvancedProtectionChanged(enabled);
    }

    @NonNull
    @Override
    public AdvancedProtectionFeature getFeature() {
        return mFeature;
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public void onAdvancedProtectionChanged(boolean enabled) {
        if (enabled) {
            Slog.d(TAG, "Setting DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
            mDevicePolicyManager.addUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
                    UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
            return;
        }
        Slog.d(TAG, "Clearing DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY restriction");
        mDevicePolicyManager.clearUserRestrictionGlobally(ADVANCED_PROTECTION_SYSTEM_ENTITY,
                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);

        // TODO(b/369361373):
        //  1. After clearing the restriction, set AppOpsManager.OP_REQUEST_INSTALL_PACKAGES to
        //  disabled.
        //  2. Update dialog strings.
    }
}
Loading