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

Unverified Commit a47ea6a1 authored by Oliver Scott's avatar Oliver Scott Committed by Michael Bestas
Browse files

Implement backup/restore for network policy

Modify network policy XML parser helper functions for backup/restore
scenarios, including secondary users

Bug: https://issuetracker.google.com/issues/207800947
Change-Id: I77158b344a47138a17fbce72d3ecb3be6927b870
parent 8dacadc8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -94,4 +94,7 @@ interface INetworkPolicyManager {
    boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
    @EnforcePermission("OBSERVE_NETWORK_POLICY")
    boolean isUidRestrictedOnMeteredNetworks(int uid);

    byte[] getBackupPayload(int user);
    void applyRestore(in byte[] payload, int user);
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Calyx Institute
 *
 * 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.backup;

import android.app.backup.BlobBackupHelper;
import android.content.Context;
import android.net.INetworkPolicyManager;
import android.os.ServiceManager;
import android.util.Log;
import android.util.Slog;

public class NetworkPolicyBackupHelper extends BlobBackupHelper {
    private static final String TAG = "NetworkPolicyBackupHelper";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    // Current version of the blob schema
    static final int BLOB_VERSION = 1;

    // Key under which the payload blob is stored
    static final String KEY_NETWORK_POLICY = "network_policy";

    private final int mUserId;

    public NetworkPolicyBackupHelper(int userId) {
        super(BLOB_VERSION, KEY_NETWORK_POLICY);
        mUserId = userId;
    }

    @Override
    protected byte[] getBackupPayload(String key) {
        byte[] newPayload = null;
        if (KEY_NETWORK_POLICY.equals(key)) {
            try {
                INetworkPolicyManager npm = INetworkPolicyManager.Stub.asInterface(
                        ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
                newPayload = npm.getBackupPayload(mUserId);
            } catch (Exception e) {
                // Treat as no data
                Slog.e(TAG, "Couldn't communicate with network policy manager", e);
                newPayload = null;
            }
        }
        return newPayload;
    }

    @Override
    protected void applyRestoredPayload(String key, byte[] payload) {
        if (DEBUG) {
            Slog.v(TAG, "Got restore of " + key);
        }

        if (KEY_NETWORK_POLICY.equals(key)) {
            try {
                INetworkPolicyManager.Stub.asInterface(
                        ServiceManager.getService(Context.NETWORK_POLICY_SERVICE))
                        .applyRestore(payload, mUserId);
            } catch (Exception e) {
                Slog.e(TAG, "Couldn't communicate with network policy manager", e);
            }
        }
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    private static final String APP_GENDER_HELPER = "app_gender";
    private static final String COMPANION_HELPER = "companion";
    private static final String SYSTEM_GENDER_HELPER = "system_gender";
    private static final String NETWORK_POLICY_HELPER = "network_policy";

    // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
    // are also used in the full-backup file format, so must not change unless steps are
@@ -103,7 +104,8 @@ public class SystemBackupAgent extends BackupAgentHelper {
                    APP_LOCALES_HELPER,
                    COMPANION_HELPER,
                    APP_GENDER_HELPER,
                    SYSTEM_GENDER_HELPER);
                    SYSTEM_GENDER_HELPER,
                    NETWORK_POLICY_HELPER);

    /** Helpers that are enabled for full, non-system users. */
    private static final Set<String> sEligibleHelpersForNonSystemUser =
@@ -145,6 +147,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
        addHelperIfEligibleForUser(COMPANION_HELPER, new CompanionBackupHelper(mUserId));
        addHelperIfEligibleForUser(SYSTEM_GENDER_HELPER,
                new SystemGrammaticalGenderBackupHelper(mUserId));
        addHelperIfEligibleForUser(NETWORK_POLICY_HELPER, new NetworkPolicyBackupHelper(mUserId));
    }

    @Override
+114 −30
Original line number Diff line number Diff line
@@ -288,15 +288,22 @@ import dalvik.annotation.optimization.NeverCompile;

import libcore.io.IoUtils;

import org.xmlpull.v1.XmlPullParserException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
@@ -2854,7 +2861,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                                lastLimitSnooze, metered, inferred));
                    }
                } else if (TAG_UID_POLICY.equals(tag)) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore, userId);
                    final int policy = readIntAttribute(in, ATTR_POLICY);

                    if (UserHandle.isApp(uid)) {
@@ -2877,10 +2884,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                } else if (TAG_ALLOWLIST.equals(tag)) {
                    insideAllowlist = true;
                } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore, userId);
                    restrictBackgroundAllowedUids.append(uid, true);
                } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore, userId);
                    mRestrictBackgroundAllowlistRevokedUids.put(uid, true);
                }
            } else if (type == END_TAG) {
@@ -3003,6 +3010,59 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

        out.startDocument(null, true);

        // only write UID-independent attributes during normal operation or system user backups
        if (!forBackup || userId == UserHandle.USER_SYSTEM) {
            writeUidIndependentAttributes(out);
        }

        // write all known uid policies
        for (int i = 0; i < mUidPolicy.size(); i++) {
            final int uid = mUidPolicy.keyAt(i);
            final int policy = mUidPolicy.valueAt(i);

            // skip writing policies belonging to other users
            if (forBackup && UserHandle.getUserId(uid) != userId) {
                continue;
            }
            // skip writing empty policies
            if (policy == POLICY_NONE) continue;

            out.startTag(null, TAG_UID_POLICY);
            if (!forBackup) {
                writeIntAttribute(out, ATTR_UID, uid);
            } else {
                writeStringAttribute(out, ATTR_XML_UTILS_NAME, getPackageForUid(uid));
            }
            writeIntAttribute(out, ATTR_POLICY, policy);
            out.endTag(null, TAG_UID_POLICY);
        }

        // write all allowlists
        out.startTag(null, TAG_ALLOWLIST);

        // revoked restrict background allowlist
        int size = mRestrictBackgroundAllowlistRevokedUids.size();
        for (int i = 0; i < size; i++) {
            final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i);
            // skip writing policies belonging to other users
            if (forBackup && UserHandle.getUserId(uid) != userId) {
                continue;
            }
            out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
            if (!forBackup) {
                writeIntAttribute(out, ATTR_UID, uid);
            } else {
                writeStringAttribute(out, ATTR_XML_UTILS_NAME, getPackageForUid(uid));
            }
            out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
        }

        out.endTag(null, TAG_ALLOWLIST);

        out.endDocument();
    }

    private void writeUidIndependentAttributes(TypedXmlSerializer out) throws IOException {
        out.startTag(null, TAG_POLICY_LIST);
        writeIntAttribute(out, ATTR_VERSION, VERSION_LATEST);
        writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
@@ -3044,38 +3104,39 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            writeBooleanAttribute(out, ATTR_INFERRED, policy.inferred);
            out.endTag(null, TAG_NETWORK_POLICY);
        }

        // write all known uid policies
        for (int i = 0; i < mUidPolicy.size(); i++) {
            final int uid = mUidPolicy.keyAt(i);
            final int policy = mUidPolicy.valueAt(i);

            // skip writing empty policies
            if (policy == POLICY_NONE) continue;

            out.startTag(null, TAG_UID_POLICY);
            writeIntAttribute(out, ATTR_UID, uid);
            writeIntAttribute(out, ATTR_POLICY, policy);
            out.endTag(null, TAG_UID_POLICY);
        }

        out.endTag(null, TAG_POLICY_LIST);
    }

        // write all allowlists
        out.startTag(null, TAG_ALLOWLIST);

        // revoked restrict background allowlist
        int size = mRestrictBackgroundAllowlistRevokedUids.size();
        for (int i = 0; i < size; i++) {
            final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i);
            out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
            writeIntAttribute(out, ATTR_UID, uid);
            out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
    @Override
    public byte[] getBackupPayload(int user) {
        enforceSystemCaller();
        if (LOGD) Slog.d(TAG, "getBackupPayload u= " + user);
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            writePolicyXml(baos, true, user);
            return baos.toByteArray();
        } catch (IOException e) {
            Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
        }
        return null;
    }

        out.endTag(null, TAG_ALLOWLIST);
    @Override
    public void applyRestore(byte[] payload, int user) {
        enforceSystemCaller();
        if (LOGD) Slog.d(TAG, "applyRestore u=" + user + " payload="
                + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
        if (payload == null) {
            Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
            return;
        }

        out.endDocument();
        final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
        try {
            readPolicyXml(bais, true, user);
        } catch (IOException | XmlPullParserException e) {
            Slog.w(TAG, "applyRestore: error reading payload for user " + user, e);
        }
    }

    @EnforcePermission(MANAGE_NETWORK_POLICY)
@@ -3277,6 +3338,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private void enforceSystemCaller() {
        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
            throw new SecurityException("Caller must be system");
        }
    }

    @Override
    public void registerListener(@NonNull INetworkPolicyListener listener) {
        Objects.requireNonNull(listener);
@@ -6719,6 +6786,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private int readUidAttribute(TypedXmlPullParser in, boolean forRestore, int userId)
            throws IOException {
        if (!forRestore) {
            return readIntAttribute(in, ATTR_UID);
        } else {
            return getUidForPackage(readStringAttribute(in, ATTR_XML_UTILS_NAME), userId);
        }
    }

    private String getPackageForUid(int uid) {
        try {
            return mContext.getPackageManager().getPackagesForUid(uid)[0];
        } catch (Exception e) {
            return null;
        }
    }

    private int getUidForPackage(String packageName, int userId) {
        try {
            return mContext.getPackageManager().getPackageUidAsUser(packageName,