summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2015-04-07 00:38:39 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-07 00:38:40 +0000
commitcd70621f92869f1a48a0d67d4edf68c3ba456b58 (patch)
treeec195f1e6929433848a1e4ed910581773da177b3 /core/java
parent7cf828ca64728e41fca0f84f297aa48a21830fd6 (diff)
parente012a235569fe307d165dfd0784ae847d0b13739 (diff)
downloadframeworks_base-cd70621f92869f1a48a0d67d4edf68c3ba456b58.zip
frameworks_base-cd70621f92869f1a48a0d67d4edf68c3ba456b58.tar.gz
frameworks_base-cd70621f92869f1a48a0d67d4edf68c3ba456b58.tar.bz2
Merge "Back up / restore preferred app configuration"
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/backup/BackupTransport.java2
-rw-r--r--core/java/android/app/backup/RecentsBackupHelper.java16
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl6
-rw-r--r--core/java/com/android/server/backup/PreferredActivityBackupHelper.java175
-rw-r--r--core/java/com/android/server/backup/SystemBackupAgent.java26
5 files changed, 214 insertions, 11 deletions
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index ca6dc69..1131ff9 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -464,7 +464,7 @@ public class BackupTransport {
* transport level).
*
* <p>After this method returns zero, the system will then call
- * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+ * {@link #nextRestorePackage()} to begin the restore process for the next
* application, and the sequence begins again.
*
* <p>The transport should always close this socket when returning from this method.
diff --git a/core/java/android/app/backup/RecentsBackupHelper.java b/core/java/android/app/backup/RecentsBackupHelper.java
index fd69d20..1a64da6 100644
--- a/core/java/android/app/backup/RecentsBackupHelper.java
+++ b/core/java/android/app/backup/RecentsBackupHelper.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 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 android.app.backup;
import android.content.Context;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fb7c96d..649bb47 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -269,6 +269,12 @@ interface IPackageManager {
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
/**
+ * Backup/restore support - only the system uid may use these.
+ */
+ byte[] getPreferredActivityBackup(int userId);
+ void restorePreferredActivities(in byte[] backup, int userId);
+
+ /**
* Report the set of 'Home' activity candidates, plus (if any) which of them
* is the current "always use this one" setting.
*/
diff --git a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
new file mode 100644
index 0000000..6ac0d89
--- /dev/null
+++ b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 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.AppGlobals;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.org.bouncycastle.util.Arrays;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class PreferredActivityBackupHelper implements BackupHelper {
+ private static final String TAG = "PreferredBackup";
+ private static final boolean DEBUG = true;
+
+ // current schema of the backup state blob
+ private static final int STATE_VERSION = 1;
+
+ // key under which the preferred-activity state blob is committed to backup
+ private static final String KEY_PREFERRED = "preferred-activity";
+
+ final Context mContext;
+
+ public PreferredActivityBackupHelper(Context context) {
+ mContext = context;
+ }
+
+ // The fds passed here are shared among all helpers, so we mustn't close them
+ private void writeState(ParcelFileDescriptor stateFile, byte[] payload) {
+ try {
+ FileOutputStream fos = new FileOutputStream(stateFile.getFileDescriptor());
+
+ // We explicitly don't close 'out' because we must not close the backing fd.
+ // The FileOutputStream will not close it implicitly.
+ @SuppressWarnings("resource")
+ DataOutputStream out = new DataOutputStream(fos);
+
+ out.writeInt(STATE_VERSION);
+ if (payload == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(payload.length);
+ out.write(payload);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to write updated state", e);
+ }
+ }
+
+ private byte[] readState(ParcelFileDescriptor oldStateFd) {
+ FileInputStream fis = new FileInputStream(oldStateFd.getFileDescriptor());
+ BufferedInputStream bis = new BufferedInputStream(fis);
+
+ @SuppressWarnings("resource")
+ DataInputStream in = new DataInputStream(bis);
+
+ byte[] oldState = null;
+ try {
+ int version = in.readInt();
+ if (version == STATE_VERSION) {
+ int size = in.readInt();
+ if (size > 0) {
+ if (size > 200*1024) {
+ Slog.w(TAG, "Suspiciously large state blog; ignoring. N=" + size);
+ } else {
+ // size looks okay; make the return buffer and fill it
+ oldState = new byte[size];
+ in.read(oldState);
+ }
+ }
+ } else {
+ Slog.w(TAG, "Prior state from unrecognized version " + version);
+ }
+ } catch (EOFException e) {
+ // Empty file is expected on first backup, so carry on. If the state
+ // is truncated we just treat it the same way.
+ oldState = null;
+ } catch (Exception e) {
+ Slog.w(TAG, "Error examing prior backup state " + e.getMessage());
+ oldState = null;
+ }
+
+ return oldState;
+ }
+
+ @Override
+ public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) {
+ byte[] payload = null;
+ try {
+ byte[] oldPayload = readState(oldState);
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ byte[] newPayload = pm.getPreferredActivityBackup(UserHandle.USER_OWNER);
+ if (!Arrays.areEqual(oldPayload, newPayload)) {
+ if (DEBUG) {
+ Slog.i(TAG, "State has changed => writing new preferred app payload");
+ }
+ data.writeEntityHeader(KEY_PREFERRED, newPayload.length);
+ data.writeEntityData(newPayload, newPayload.length);
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "No change to state => not writing to wire");
+ }
+ }
+
+ // Always need to re-record the state, even if nothing changed
+ payload = newPayload;
+ } catch (Exception e) {
+ // On failures we'll wind up committing a zero-size state payload. This is
+ // a forward-safe situation because we know we commit the entire new payload
+ // on prior-state mismatch.
+ Slog.w(TAG, "Unable to record preferred activities", e);
+ } finally {
+ writeState(newState, payload);
+ }
+ }
+
+ @Override
+ public void restoreEntity(BackupDataInputStream data) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ byte[] payload = new byte[data.size()];
+ data.read(payload);
+ if (DEBUG) {
+ Slog.i(TAG, "Restoring preferred activities; size=" + payload.length);
+ }
+ pm.restorePreferredActivities(payload, UserHandle.USER_OWNER);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception reading restore data", e);
+ }
+ }
+
+ @Override
+ public void writeNewStateDescription(ParcelFileDescriptor newState) {
+ writeState(newState, null);
+ }
+
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 037fd66..19d9e29 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -16,7 +16,6 @@
package com.android.server.backup;
-
import android.app.ActivityManagerNative;
import android.app.IWallpaperManager;
import android.app.backup.BackupDataInput;
@@ -43,6 +42,13 @@ import java.io.IOException;
public class SystemBackupAgent extends BackupAgentHelper {
private static final String TAG = "SystemBackupAgent";
+ // Names of the helper tags within the dataset. Changing one of these names will
+ // break the ability to restore from datasets that predate the change.
+ private static final String WALLPAPER_HELPER = "wallpaper";
+ private static final String RECENTS_HELPER = "recents";
+ private static final String SYNC_SETTINGS_HELPER = "account_sync_settings";
+ private static final String PREFERRED_HELPER = "preferred_activities";
+
// 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
// taken to support the legacy backed-up datasets.
@@ -84,10 +90,10 @@ public class SystemBackupAgent extends BackupAgentHelper {
Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
}
}
- addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
- addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
- addHelper("account_sync_settings",
- new AccountSyncSettingsBackupHelper(SystemBackupAgent.this));
+ addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
+ addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
+ addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
+ addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(this));
super.onBackup(oldState, data, newState);
}
@@ -113,15 +119,15 @@ public class SystemBackupAgent extends BackupAgentHelper {
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException {
// On restore, we also support a previous data schema "system_files"
- addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
+ addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this,
new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
- addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
+ addHelper("system_files", new WallpaperBackupHelper(this,
new String[] { WALLPAPER_IMAGE },
new String[] { WALLPAPER_IMAGE_KEY} ));
- addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
- addHelper("account_sync_settings",
- new AccountSyncSettingsBackupHelper(SystemBackupAgent.this));
+ addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
+ addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
+ addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(this));
try {
super.onRestore(data, appVersionCode, newState);