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

Commit b715b047 authored by Jason Monk's avatar Jason Monk
Browse files

Add backup/restore for slices access

Test: various "adb shell bmgr" commands to verify behavior
Change-Id: Ic4439e0e17516462acdb8d28fe49095209a2ed6f
Fixes: 68751119
parent 34b58512
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -31,4 +31,7 @@ interface ISliceManager {
    SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
    int checkSlicePermission(in Uri uri, String pkg, int pid, int uid);
    void grantPermissionFromUser(in Uri uri, String pkg, String callingPkg, boolean allSlices);

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

import android.app.backup.BlobBackupHelper;
import android.app.slice.ISliceManager;
import android.content.Context;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;

public class SliceBackupHelper extends BlobBackupHelper {
    static final String TAG = "SliceBackupHelper";
    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_SLICES = "slices";

    public SliceBackupHelper(Context context) {
        super(BLOB_VERSION, KEY_SLICES);
        // context is currently unused
    }

    @Override
    protected byte[] getBackupPayload(String key) {
        byte[] newPayload = null;
        if (KEY_SLICES.equals(key)) {
            try {
                ISliceManager sm = ISliceManager.Stub.asInterface(
                        ServiceManager.getService(Context.SLICE_SERVICE));
                // TODO: http://b/22388012
                newPayload = sm.getBackupPayload(UserHandle.USER_SYSTEM);
            } catch (Exception e) {
                // Treat as no data
                Slog.e(TAG, "Couldn't communicate with slice manager");
                newPayload = null;
            }
        }
        return newPayload;
    }

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

        if (KEY_SLICES.equals(key)) {
            try {
                ISliceManager sm = ISliceManager.Stub.asInterface(
                        ServiceManager.getService(Context.SLICE_SERVICE));
                // TODO: http://b/22388012
                sm.applyRestore(payload, UserHandle.USER_SYSTEM);
            } catch (Exception e) {
                Slog.e(TAG, "Couldn't communicate with slice manager");
            }
        }
    }

}
+3 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    private static final String USAGE_STATS_HELPER = "usage_stats";
    private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager";
    private static final String ACCOUNT_MANAGER_HELPER = "account_manager";
    private static final String SLICES_HELPER = "slices";

    // 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
@@ -88,6 +89,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
        addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
        addHelper(SLICES_HELPER, new SliceBackupHelper(this));
        super.onBackup(oldState, data, newState);
    }

@@ -116,6 +118,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
        addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
        addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
        addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper());
        addHelper(SLICES_HELPER, new SliceBackupHelper(this));

        super.onRestore(data, appVersionCode, newState);
    }
+5 −3
Original line number Diff line number Diff line
@@ -16,9 +16,9 @@ package com.android.server.slice;

import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;

import com.android.internal.util.XmlUtils;
@@ -72,7 +72,7 @@ public class SliceFullAccessList {
        pkgs.remove(pkg);
    }

    public void writeXml(XmlSerializer out) throws IOException {
    public void writeXml(XmlSerializer out, int user) throws IOException {
        out.startTag(null, TAG_LIST);
        out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));

@@ -80,6 +80,9 @@ public class SliceFullAccessList {
        for (int i = 0 ; i < N; i++) {
            final int userId = mFullAccessPkgs.keyAt(i);
            final ArraySet<String> pkgs = mFullAccessPkgs.valueAt(i);
            if (user != UserHandle.USER_ALL && user != userId) {
                continue;
            }
            out.startTag(null, TAG_USER);
            out.attribute(null, ATT_USER_ID, Integer.toString(userId));
            if (pkgs != null) {
@@ -88,7 +91,6 @@ public class SliceFullAccessList {
                        out.startTag(null, TAG_PKG);
                        out.text(pkgs.valueAt(j));
                        out.endTag(null, TAG_PKG);

                }
            }
            out.endTag(null, TAG_USER);
+62 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.ContentProvider.getUserIdFromUri;
import static android.content.ContentProvider.maybeAddUserId;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;

import android.Manifest.permission;
import android.app.ActivityManager;
@@ -68,8 +69,9 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -93,6 +95,7 @@ public class SliceManagerService extends ISliceManager.Stub {
    private final ArraySet<SliceGrant> mUserGrants = new ArraySet<>();
    private final Handler mHandler;
    private final ContentObserver mObserver;
    @GuardedBy("mSliceAccessFile")
    private final AtomicFile mSliceAccessFile;
    @GuardedBy("mAccessList")
    private final SliceFullAccessList mAccessList;
@@ -257,6 +260,63 @@ public class SliceManagerService extends ISliceManager.Stub {
        }
    }

    // Backup/restore interface
    @Override
    public byte[] getBackupPayload(int user) {
        if (Binder.getCallingUid() != SYSTEM_UID) {
            throw new SecurityException("Caller must be system");
        }
        //TODO: http://b/22388012
        if (user != UserHandle.USER_SYSTEM) {
            Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
            return null;
        }
        synchronized(mSliceAccessFile) {
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
                out.setOutput(baos, Encoding.UTF_8.name());
                synchronized (mAccessList) {
                    mAccessList.writeXml(out, user);
                }
                out.flush();
                return baos.toByteArray();
            } catch (IOException | XmlPullParserException e) {
                Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
            }
        }
        return null;
    }

    @Override
    public void applyRestore(byte[] payload, int user) {
        if (Binder.getCallingUid() != SYSTEM_UID) {
            throw new SecurityException("Caller must be system");
        }
        if (payload == null) {
            Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
            return;
        }
        //TODO: http://b/22388012
        if (user != UserHandle.USER_SYSTEM) {
            Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
            return;
        }
        synchronized(mSliceAccessFile) {
            final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
            try {
                XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
                parser.setInput(bais, Encoding.UTF_8.name());
                synchronized (mAccessList) {
                    mAccessList.readXml(parser);
                }
                mHandler.post(mSaveAccessList);
            } catch (NumberFormatException | XmlPullParserException | IOException e) {
                Slog.w(TAG, "applyRestore: error reading payload", e);
            }
        }
    }

    ///  ----- internal code -----
    private void removeFullAccess(String pkg, int userId) {
        synchronized (mAccessList) {
@@ -492,7 +552,7 @@ public class SliceManagerService extends ISliceManager.Stub {
                    XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
                    out.setOutput(stream, Encoding.UTF_8.name());
                    synchronized (mAccessList) {
                        mAccessList.writeXml(out);
                        mAccessList.writeXml(out, UserHandle.USER_ALL);
                    }
                    out.flush();
                    mSliceAccessFile.finishWrite(stream);
Loading