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

Unverified Commit 61fac218 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

Issue: calyxos#384
Change-Id: I77158b344a47138a17fbce72d3ecb3be6927b870
(cherry picked from commit 9ac27e3b850921a83c52aaa0da798320517b0d5e)
parent 22ad5e7d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -78,4 +78,7 @@ interface INetworkPolicyManager {
    void factoryReset(String subscriber);

    boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);

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

    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 Diff line number Diff line
@@ -56,6 +56,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
    private static final String SLICES_HELPER = "slices";
    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
    // are also used in the full-backup file format, so must not change unless steps are
@@ -101,6 +102,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
        addHelper(PEOPLE_HELPER, new PeopleBackupHelper(mUserId));
        addHelper(NETWORK_POLICY_HELPER, new NetworkPolicyBackupHelper());
    }

    @Override
+80 −11
Original line number Diff line number Diff line
@@ -252,6 +252,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -377,6 +379,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final String ATTR_OWNER_PACKAGE = "ownerPackage";
    private static final String ATTR_NETWORK_TYPES = "networkTypes";
    private static final String ATTR_XML_UTILS_NAME = "name";
    private static final String ATTR_USER_ID = "userId";

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

    private void readPolicyXml(InputStream inputStream) {
    private void readPolicyXml(InputStream inputStream, boolean forRestore) throws IOException,
            XmlPullParserException {
        final XmlPullParser in = Xml.newPullParser();
        in.setInput(inputStream, StandardCharsets.UTF_8.name());

@@ -2366,7 +2370,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                            SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan));
                    mSubscriptionPlansOwner.put(subId, ownerPackage);
                } 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);

                    if (UserHandle.isApp(uid)) {
@@ -2389,10 +2393,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                } else if (TAG_WHITELIST.equals(tag)) {
                    insideWhitelist = true;
                } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore);
                    whitelistedRestrictBackground.append(uid, true);
                } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
                    final int uid = readIntAttribute(in, ATTR_UID);
                    int uid = readUidAttribute(in, forRestore);
                    mRestrictBackgroundWhitelistRevokedUids.put(uid, true);
                }
            } else if (type == END_TAG) {
@@ -2487,9 +2491,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        FileOutputStream fos = null;
        try {
            fos = mPolicyFile.startWrite();

            writePolicyXml(fos);

            writePolicyXml(fos, false);
            mPolicyFile.finishWrite(fos);
        } catch (IOException e) {
            if (fos != null) {
@@ -2498,7 +2500,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private void writePolicyXml(OutputStream outputStream) {
    private void writePolicyXml(OutputStream outputStream, boolean forBackup) throws IOException {
        XmlSerializer out = new FastXmlSerializer();
        out.setOutput(outputStream, StandardCharsets.UTF_8.name());
        out.startDocument(null, true);
@@ -2578,7 +2580,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            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_USER_ID, UserHandle.getUserId(uid));
            }
            writeIntAttribute(out, ATTR_POLICY, policy);
            out.endTag(null, TAG_UID_POLICY);
        }
@@ -2593,7 +2600,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        for (int i = 0; i < size; i++) {
            final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i);
            out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
            if (!forBackup) {
                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);
        }

@@ -2602,6 +2614,44 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        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
    public void setUidPolicy(int uid, int policy) {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
@@ -2810,6 +2860,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(INetworkPolicyListener listener) {
        // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
@@ -5502,6 +5558,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private int readUidAttribute(XmlPullParser 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) {
        try {
            return mContext.getPackageManager().getPackageUidAsUser(packageName,