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

Commit 9880c403 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

Bug: https://issuetracker.google.com/issues/207800947
Change-Id: I77158b344a47138a17fbce72d3ecb3be6927b870
(cherry picked from commit cba1961538ba723a8661d9e9b8389a82e9045b49)
parent bd5f6a92
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -78,4 +78,7 @@ interface INetworkPolicyManager {


    boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
    boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
    boolean isUidRestrictedOnMeteredNetworks(int uid);
    boolean isUidRestrictedOnMeteredNetworks(int uid);

    byte[] getBackupPayload();
    void applyRestore(in byte[] payload);
}
}
+73 −0
Original line number Original line 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";

    public NetworkPolicyBackupHelper() {
        super(BLOB_VERSION, KEY_NETWORK_POLICY);
    }

    @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();
            } catch (Exception e) {
                // Treat as no data
                Slog.e(TAG, "Couldn't communicate with network policy manager");
                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);
            } catch (Exception e) {
                Slog.e(TAG, "Couldn't communicate with network policy manager");
            }
        }
    }
}
+2 −0
Original line number Original line Diff line number Diff line
@@ -57,6 +57,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
    private static final String SLICES_HELPER = "slices";
    private static final String SLICES_HELPER = "slices";
    private static final String PEOPLE_HELPER = "people";
    private static final String PEOPLE_HELPER = "people";
    private static final String NETWORK_POLICY_HELPER = "network_policy";


    // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
    // 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
    // are also used in the full-backup file format, so must not change unless steps are
@@ -102,6 +103,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
        addHelper(PEOPLE_HELPER, new PeopleBackupHelper(mUserId));
        addHelper(PEOPLE_HELPER, new PeopleBackupHelper(mUserId));
        addHelper(NETWORK_POLICY_HELPER, new NetworkPolicyBackupHelper());
    }
    }


    @Override
    @Override
+85 −11
Original line number Original line Diff line number Diff line
@@ -287,6 +287,8 @@ import libcore.io.IoUtils;


import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserException;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileInputStream;
@@ -298,6 +300,7 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Clock;
import java.time.Instant;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneId;
@@ -307,6 +310,8 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
@@ -415,6 +420,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final String ATTR_OWNER_PACKAGE = "ownerPackage";
    private static final String ATTR_OWNER_PACKAGE = "ownerPackage";
    private static final String ATTR_NETWORK_TYPES = "networkTypes";
    private static final String ATTR_NETWORK_TYPES = "networkTypes";
    private static final String ATTR_XML_UTILS_NAME = "name";
    private static final String ATTR_XML_UTILS_NAME = "name";
    private static final String ATTR_USER_ID = "userId";


    private static final String ACTION_ALLOW_BACKGROUND =
    private static final String ACTION_ALLOW_BACKGROUND =
            "com.android.server.net.action.ALLOW_BACKGROUND";
            "com.android.server.net.action.ALLOW_BACKGROUND";
@@ -2393,7 +2399,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        FileInputStream fis = null;
        FileInputStream fis = null;
        try {
        try {
            fis = mPolicyFile.openRead();
            fis = mPolicyFile.openRead();
            readPolicyXml(fis);
            readPolicyXml(fis, false);
        } catch (FileNotFoundException e) {
        } catch (FileNotFoundException e) {
            // missing policy is okay, probably first boot
            // missing policy is okay, probably first boot
            upgradeDefaultBackgroundDataUL();
            upgradeDefaultBackgroundDataUL();
@@ -2404,8 +2410,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
        }
    }
    }


    private void readPolicyXml(FileInputStream fis) {
    private void readPolicyXml(InputStream inputStream, boolean forRestore) throws IOException,
        final TypedXmlPullParser in = Xml.resolvePullParser(fis);
            XmlPullParserException {
        final TypedXmlPullParser in = Xml.resolvePullParser(inputStream);


         // Must save the <restrict-background> tags and convert them to <uid-policy> later,
         // Must save the <restrict-background> tags and convert them to <uid-policy> later,
         // to skip UIDs that were explicitly denied.
         // to skip UIDs that were explicitly denied.
@@ -2564,7 +2571,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                            SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan));
                            SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan));
                    mSubscriptionPlansOwner.put(subId, ownerPackage);
                    mSubscriptionPlansOwner.put(subId, ownerPackage);
                } else if (TAG_UID_POLICY.equals(tag)) {
                } else if (TAG_UID_POLICY.equals(tag)) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore);
                    final int policy = readIntAttribute(in, ATTR_POLICY);
                    final int policy = readIntAttribute(in, ATTR_POLICY);


                    if (UserHandle.isApp(uid)) {
                    if (UserHandle.isApp(uid)) {
@@ -2587,10 +2594,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                } else if (TAG_WHITELIST.equals(tag)) {
                } else if (TAG_WHITELIST.equals(tag)) {
                    insideAllowlist = true;
                    insideAllowlist = true;
                } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore);
                    restrictBackgroundAllowedUids.append(uid, true);
                    restrictBackgroundAllowedUids.append(uid, true);
                } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore);
                    mRestrictBackgroundAllowlistRevokedUids.put(uid, true);
                    mRestrictBackgroundAllowlistRevokedUids.put(uid, true);
                }
                }
            } else if (type == END_TAG) {
            } else if (type == END_TAG) {
@@ -2694,7 +2701,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        FileOutputStream fos = null;
        FileOutputStream fos = null;
        try {
        try {
            fos = mPolicyFile.startWrite();
            fos = mPolicyFile.startWrite();
            writePolicyXml(fos);
            writePolicyXml(fos, false);
            mPolicyFile.finishWrite(fos);
            mPolicyFile.finishWrite(fos);
        } catch (IOException e) {
        } catch (IOException e) {
            if (fos != null) {
            if (fos != null) {
@@ -2703,8 +2710,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
        }
    }
    }


    private void writePolicyXml(FileOutputStream fos) {
    private void writePolicyXml(OutputStream outputStream, boolean forBackup) throws IOException {
        TypedXmlSerializer out = Xml.resolveSerializer(fos);
        TypedXmlSerializer out = Xml.resolveSerializer(outputStream);
        out.startDocument(null, true);
        out.startDocument(null, true);


        out.startTag(null, TAG_POLICY_LIST);
        out.startTag(null, TAG_POLICY_LIST);
@@ -2787,7 +2794,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            if (policy == POLICY_NONE) continue;
            if (policy == POLICY_NONE) continue;


            out.startTag(null, TAG_UID_POLICY);
            out.startTag(null, TAG_UID_POLICY);
            if (!forBackup) {
                writeIntAttribute(out, ATTR_UID, uid);
                writeIntAttribute(out, ATTR_UID, uid);
            } else {
                writeStringAttribute(out, ATTR_XML_UTILS_NAME, getPackageForUid(uid));
                writeIntAttribute(out, ATTR_USER_ID, UserHandle.getUserId(uid));
            }
            writeIntAttribute(out, ATTR_POLICY, policy);
            writeIntAttribute(out, ATTR_POLICY, policy);
            out.endTag(null, TAG_UID_POLICY);
            out.endTag(null, TAG_UID_POLICY);
        }
        }
@@ -2802,7 +2814,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        for (int i = 0; i < size; i++) {
        for (int i = 0; i < size; i++) {
            final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i);
            final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i);
            out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
            out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
            if (!forBackup) {
                writeIntAttribute(out, ATTR_UID, uid);
                writeIntAttribute(out, ATTR_UID, uid);
            } else {
                writeStringAttribute(out, ATTR_XML_UTILS_NAME, getPackageForUid(uid));
                writeIntAttribute(out, ATTR_USER_ID, UserHandle.getUserId(uid));
            }
            out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
            out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
        }
        }


@@ -2811,6 +2828,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        out.endDocument();
        out.endDocument();
    }
    }


    @Override
    public byte[] getBackupPayload() {
        enforceSystemCaller();
        if (LOGD) Slog.d(TAG, "getBackupPayload");
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            writePolicyXml(baos, true);
            return baos.toByteArray();
        } catch (IOException e) {
            Slog.w(TAG, "getBackupPayload: error writing payload", e);
        }
        return null;
    }

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

        // clear any existing policy and read from disk
        mNetworkPolicy.clear();
        mSubscriptionPlans.clear();
        mSubscriptionPlansOwner.clear();
        mUidPolicy.clear();

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

    @Override
    @Override
    public void setUidPolicy(int uid, int policy) {
    public void setUidPolicy(int uid, int policy) {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
@@ -3005,6 +3060,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
    @Override
    public void registerListener(@NonNull INetworkPolicyListener listener) {
    public void registerListener(@NonNull INetworkPolicyListener listener) {
        Objects.requireNonNull(listener);
        Objects.requireNonNull(listener);
@@ -5905,6 +5966,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
        }
    }
    }


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

    private String getPackageForUid(int uid) {
        return mContext.getPackageManager().getPackagesForUid(uid)[0];
    }

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