Loading core/java/android/app/slice/ISliceManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -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); } core/java/com/android/server/backup/SliceBackupHelper.java 0 → 100644 +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"); } } } } core/java/com/android/server/backup/SystemBackupAgent.java +3 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } Loading Loading @@ -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); } Loading services/core/java/com/android/server/slice/SliceFullAccessList.java +5 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); Loading @@ -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) { Loading @@ -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); Loading services/core/java/com/android/server/slice/SliceManagerService.java +62 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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 Loading
core/java/android/app/slice/ISliceManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -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); }
core/java/com/android/server/backup/SliceBackupHelper.java 0 → 100644 +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"); } } } }
core/java/com/android/server/backup/SystemBackupAgent.java +3 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } Loading Loading @@ -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); } Loading
services/core/java/com/android/server/slice/SliceFullAccessList.java +5 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)); Loading @@ -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) { Loading @@ -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); Loading
services/core/java/com/android/server/slice/SliceManagerService.java +62 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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