Move more common methods to TarBackupReader.
This moves rest of common methods in FullRestoreEngine and PerformAdbRestoreTask to TarBackupReader and FileMetadata. Bug: 37519282 Test: gts Change-Id: Iff1f95e87721e74c9c5764ab98c64026604eee9b
This commit is contained in:
@@ -16,6 +16,12 @@
|
||||
|
||||
package com.android.server.backup;
|
||||
|
||||
import android.app.backup.BackupAgent;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Description of a file in the restore datastream.
|
||||
*/
|
||||
@@ -46,4 +52,33 @@ public class FileMetadata {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
StringBuilder b = new StringBuilder(128);
|
||||
|
||||
// mode string
|
||||
b.append((type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
|
||||
b.append(((mode & 0400) != 0) ? 'r' : '-');
|
||||
b.append(((mode & 0200) != 0) ? 'w' : '-');
|
||||
b.append(((mode & 0100) != 0) ? 'x' : '-');
|
||||
b.append(((mode & 0040) != 0) ? 'r' : '-');
|
||||
b.append(((mode & 0020) != 0) ? 'w' : '-');
|
||||
b.append(((mode & 0010) != 0) ? 'x' : '-');
|
||||
b.append(((mode & 0004) != 0) ? 'r' : '-');
|
||||
b.append(((mode & 0002) != 0) ? 'w' : '-');
|
||||
b.append(((mode & 0001) != 0) ? 'x' : '-');
|
||||
b.append(String.format(" %9d ", size));
|
||||
|
||||
Date stamp = new Date(mtime);
|
||||
b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
|
||||
|
||||
b.append(packageName);
|
||||
b.append(" :: ");
|
||||
b.append(domain);
|
||||
b.append(" :: ");
|
||||
b.append(path);
|
||||
|
||||
Slog.i(RefactoredBackupManagerService.TAG, b.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3654,38 +3654,6 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
|
||||
}
|
||||
}
|
||||
|
||||
public Bundle putMonitoringExtra(Bundle extras, String key, String value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putString(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
private Bundle putMonitoringExtra(Bundle extras, String key, int value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putInt(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
public Bundle putMonitoringExtra(Bundle extras, String key, long value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putLong(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
|
||||
public Bundle putMonitoringExtra(Bundle extras, String key, boolean value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putBoolean(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBackupManager getBackupManagerBinder() {
|
||||
|
||||
@@ -364,7 +364,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
|
||||
BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT,
|
||||
mCurrentPackage,
|
||||
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService.putMonitoringExtra(null,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR,
|
||||
preflightResult));
|
||||
backupPackageStatus = (int) preflightResult;
|
||||
@@ -545,7 +545,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
|
||||
BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP,
|
||||
mCurrentPackage,
|
||||
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService.putMonitoringExtra(null,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP,
|
||||
Log.getStackTraceString(e)));
|
||||
|
||||
|
||||
@@ -842,7 +842,7 @@ public class PerformBackupTask implements BackupRestoreTask {
|
||||
mCurrentPackage,
|
||||
BackupManagerMonitor
|
||||
.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService.putMonitoringExtra(null,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY,
|
||||
key));
|
||||
backupManagerService.getBackupHandler().removeMessages(
|
||||
@@ -1027,7 +1027,7 @@ public class PerformBackupTask implements BackupRestoreTask {
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
|
||||
mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
|
||||
backupManagerService.putMonitoringExtra(null,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL,
|
||||
mCancelAll));
|
||||
errorCleanup();
|
||||
|
||||
@@ -16,29 +16,9 @@
|
||||
|
||||
package com.android.server.backup.restore;
|
||||
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_MANIFEST_PACKAGE_NAME;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OLD_VERSION;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_POLICY_ALLOW_APKS;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER;
|
||||
|
||||
import android.app.ApplicationThreadConstants;
|
||||
import android.app.IBackupAgent;
|
||||
import android.app.PackageInstallObserver;
|
||||
import android.app.backup.BackupAgent;
|
||||
import android.app.backup.BackupManagerMonitor;
|
||||
import android.app.backup.FullBackup;
|
||||
import android.app.backup.IBackupManagerMonitor;
|
||||
import android.app.backup.IFullBackupRestoreObserver;
|
||||
@@ -60,17 +40,12 @@ import com.android.server.backup.FileMetadata;
|
||||
import com.android.server.backup.RefactoredBackupManagerService;
|
||||
import com.android.server.backup.fullbackup.FullBackupObbConnection;
|
||||
import com.android.server.backup.utils.AppBackupUtils;
|
||||
import com.android.server.backup.utils.BackupManagerMonitorUtils;
|
||||
import com.android.server.backup.utils.TarBackupReader;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -206,7 +181,7 @@ public class FullRestoreEngine extends RestoreEngine {
|
||||
public void onBytesRead(long bytesRead) {
|
||||
mBytes += bytesRead;
|
||||
}
|
||||
});
|
||||
}, mMonitor);
|
||||
|
||||
FileMetadata info;
|
||||
try {
|
||||
@@ -216,7 +191,7 @@ public class FullRestoreEngine extends RestoreEngine {
|
||||
info = tarBackupReader.readTarHeaders();
|
||||
if (info != null) {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
dumpFileMetadata(info);
|
||||
info.dump();
|
||||
}
|
||||
|
||||
final String pkg = info.packageName;
|
||||
@@ -256,7 +231,10 @@ public class FullRestoreEngine extends RestoreEngine {
|
||||
}
|
||||
|
||||
if (info.path.equals(RefactoredBackupManagerService.BACKUP_MANIFEST_FILENAME)) {
|
||||
mPackagePolicies.put(pkg, readAppManifest(info, instream));
|
||||
RestorePolicy appManifest = tarBackupReader.readAppManifest(
|
||||
backupManagerService.getPackageManager(), mAllowApks,
|
||||
mManifestSignatures, info);
|
||||
mPackagePolicies.put(pkg, appManifest);
|
||||
mPackageInstallers.put(pkg, info.installerPackageName);
|
||||
// We've read only the manifest content itself at this point,
|
||||
// so consume the footer before looping around to the next
|
||||
@@ -266,7 +244,16 @@ public class FullRestoreEngine extends RestoreEngine {
|
||||
} else if (info.path.equals(
|
||||
RefactoredBackupManagerService.BACKUP_METADATA_FILENAME)) {
|
||||
// Metadata blobs!
|
||||
readMetadata(info, instream);
|
||||
tarBackupReader.readMetadata(info);
|
||||
|
||||
// The following only exist because we want to keep refactoring as safe as
|
||||
// possible, without changing too much.
|
||||
// TODO: Refactor, so that there are no funny things like this.
|
||||
// This is read during TarBackupReader.readMetadata().
|
||||
mWidgetData = tarBackupReader.getWidgetData();
|
||||
// This can be nulled during TarBackupReader.readMetadata().
|
||||
mMonitor = tarBackupReader.getMonitor();
|
||||
|
||||
tarBackupReader.skipTarPadding(info.size);
|
||||
} else {
|
||||
// Non-manifest, so it's actual file data. Is this a package
|
||||
@@ -812,374 +799,6 @@ public class FullRestoreEngine extends RestoreEngine {
|
||||
return okay;
|
||||
}
|
||||
|
||||
// Read a widget metadata file, returning the restored blob
|
||||
void readMetadata(FileMetadata info, InputStream instream) throws IOException {
|
||||
// Fail on suspiciously large widget dump files
|
||||
if (info.size > 64 * 1024) {
|
||||
throw new IOException("Metadata too big; corrupt? size=" + info.size);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) info.size];
|
||||
if (TarBackupReader.readExactly(instream, buffer, 0, (int) info.size) == info.size) {
|
||||
mBytes += info.size;
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in widget data");
|
||||
}
|
||||
|
||||
String[] str = new String[1];
|
||||
int offset = TarBackupReader.extractLine(buffer, 0, str);
|
||||
int version = Integer.parseInt(str[0]);
|
||||
if (version == RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
final String pkg = str[0];
|
||||
if (info.packageName.equals(pkg)) {
|
||||
// Data checks out -- the rest of the buffer is a concatenation of
|
||||
// binary blobs as described in the comment at writeAppWidgetData()
|
||||
ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
|
||||
offset, buffer.length - offset);
|
||||
DataInputStream in = new DataInputStream(bin);
|
||||
while (bin.available() > 0) {
|
||||
int token = in.readInt();
|
||||
int size = in.readInt();
|
||||
if (size > 64 * 1024) {
|
||||
throw new IOException("Datum "
|
||||
+ Integer.toHexString(token)
|
||||
+ " too big; corrupt? size=" + info.size);
|
||||
}
|
||||
switch (token) {
|
||||
case RefactoredBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN: {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Got widget metadata for " + info.packageName);
|
||||
}
|
||||
mWidgetData = new byte[size];
|
||||
in.read(mWidgetData);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG, "Ignoring metadata blob "
|
||||
+ Integer.toHexString(token)
|
||||
+ " for " + info.packageName);
|
||||
}
|
||||
in.skipBytes(size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Metadata mismatch: package " + info.packageName
|
||||
+ " but widget data for " + pkg);
|
||||
|
||||
Bundle monitoringExtras = backupManagerService.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(monitoringExtras,
|
||||
BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG, "Unsupported metadata version " + version);
|
||||
|
||||
Bundle monitoringExtras = backupManagerService
|
||||
.putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
|
||||
info.packageName);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(monitoringExtras,
|
||||
EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a policy constant
|
||||
RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
|
||||
throws IOException {
|
||||
// Fail on suspiciously large manifest files
|
||||
if (info.size > 64 * 1024) {
|
||||
throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) info.size];
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
" readAppManifest() looking for " + info.size + " bytes, "
|
||||
+ mBytes + " already consumed");
|
||||
}
|
||||
if (TarBackupReader.readExactly(instream, buffer, 0, (int) info.size) == info.size) {
|
||||
mBytes += info.size;
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in manifest");
|
||||
}
|
||||
|
||||
RestorePolicy policy = RestorePolicy.IGNORE;
|
||||
String[] str = new String[1];
|
||||
int offset = 0;
|
||||
|
||||
try {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
int version = Integer.parseInt(str[0]);
|
||||
if (version == RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
String manifestPackage = str[0];
|
||||
// TODO: handle <original-package>
|
||||
if (manifestPackage.equals(info.packageName)) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
version = Integer.parseInt(str[0]); // app version
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
// This is the platform version, which we don't use, but we parse it
|
||||
// as a safety against corruption in the manifest.
|
||||
Integer.parseInt(str[0]);
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
boolean hasApk = str[0].equals("1");
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
int numSigs = Integer.parseInt(str[0]);
|
||||
if (numSigs > 0) {
|
||||
Signature[] sigs = new Signature[numSigs];
|
||||
for (int i = 0; i < numSigs; i++) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
sigs[i] = new Signature(str[0]);
|
||||
}
|
||||
mManifestSignatures.put(info.packageName, sigs);
|
||||
|
||||
// Okay, got the manifest info we need...
|
||||
try {
|
||||
PackageInfo pkgInfo =
|
||||
backupManagerService.getPackageManager().getPackageInfo(
|
||||
info.packageName, PackageManager.GET_SIGNATURES);
|
||||
// Fall through to IGNORE if the app explicitly disallows backup
|
||||
final int flags = pkgInfo.applicationInfo.flags;
|
||||
if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
|
||||
// Restore system-uid-space packages only if they have
|
||||
// defined a custom backup agent
|
||||
if ((pkgInfo.applicationInfo.uid
|
||||
>= Process.FIRST_APPLICATION_UID)
|
||||
|| (pkgInfo.applicationInfo.backupAgentName != null)) {
|
||||
// Verify signatures against any installed version; if they
|
||||
// don't match, then we fall though and ignore the data. The
|
||||
// signatureMatch() method explicitly ignores the signature
|
||||
// check for packages installed on the system partition, because
|
||||
// such packages are signed with the platform cert instead of
|
||||
// the app developer's cert, so they're different on every
|
||||
// device.
|
||||
if (AppBackupUtils.signaturesMatch(sigs,
|
||||
pkgInfo)) {
|
||||
if ((pkgInfo.applicationInfo.flags
|
||||
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Package has restoreAnyVersion; taking data");
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_RESTORE_ANY_VERSION,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
policy = RestorePolicy.ACCEPT;
|
||||
} else if (pkgInfo.versionCode >= version) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Sig + version match; taking data");
|
||||
policy = RestorePolicy.ACCEPT;
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_VERSIONS_MATCH,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
} else {
|
||||
// The data is from a newer version of the app than
|
||||
// is presently installed. That means we can only
|
||||
// use it if the matching apk is also supplied.
|
||||
if (mAllowApks) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Data version " + version
|
||||
+ " is newer than installed "
|
||||
+ "version "
|
||||
+ pkgInfo.versionCode
|
||||
+ " - requiring apk");
|
||||
policy = RestorePolicy.ACCEPT_IF_APK;
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Data requires newer version "
|
||||
+ version + "; ignoring");
|
||||
mMonitor = BackupManagerMonitorUtils
|
||||
.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService
|
||||
.putMonitoringExtra(
|
||||
null,
|
||||
EXTRA_LOG_OLD_VERSION,
|
||||
version));
|
||||
|
||||
policy = RestorePolicy.IGNORE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Restore manifest signatures do not match "
|
||||
+ "installed application for "
|
||||
+ info.packageName);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Package " + info.packageName
|
||||
+ " is system level with no agent");
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_SYSTEM_APP_NO_AGENT,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_AGENT,
|
||||
null);
|
||||
}
|
||||
} else {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Restore manifest from "
|
||||
+ info.packageName + " but allowBackup=false");
|
||||
}
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// Okay, the target app isn't installed. We can process
|
||||
// the restore properly only if the dataset provides the
|
||||
// apk file and we can successfully install it.
|
||||
if (mAllowApks) {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Package " + info.packageName
|
||||
+ " not installed; requiring apk in dataset");
|
||||
}
|
||||
policy = RestorePolicy.ACCEPT_IF_APK;
|
||||
} else {
|
||||
policy = RestorePolicy.IGNORE;
|
||||
}
|
||||
Bundle monitoringExtras = backupManagerService.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(
|
||||
monitoringExtras,
|
||||
EXTRA_LOG_POLICY_ALLOW_APKS, mAllowApks);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_APK_NOT_INSTALLED,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
|
||||
if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Cannot restore package " + info.packageName
|
||||
+ " without the matching .apk");
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Missing signature on backed-up package "
|
||||
+ info.packageName);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_MISSING_SIGNATURE,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Expected package " + info.packageName
|
||||
+ " but restore manifest claims " + manifestPackage);
|
||||
Bundle monitoringExtras = backupManagerService.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(monitoringExtras,
|
||||
EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Unknown restore manifest version " + version
|
||||
+ " for package " + info.packageName);
|
||||
Bundle monitoringExtras = backupManagerService.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(monitoringExtras,
|
||||
EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Corrupt restore manifest for package " + info.packageName);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
backupManagerService.putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
|
||||
info.packageName));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG, e.getMessage());
|
||||
}
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
void dumpFileMetadata(FileMetadata info) {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
StringBuilder b = new StringBuilder(128);
|
||||
|
||||
// mode string
|
||||
b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
|
||||
b.append(((info.mode & 0400) != 0) ? 'r' : '-');
|
||||
b.append(((info.mode & 0200) != 0) ? 'w' : '-');
|
||||
b.append(((info.mode & 0100) != 0) ? 'x' : '-');
|
||||
b.append(((info.mode & 0040) != 0) ? 'r' : '-');
|
||||
b.append(((info.mode & 0020) != 0) ? 'w' : '-');
|
||||
b.append(((info.mode & 0010) != 0) ? 'x' : '-');
|
||||
b.append(((info.mode & 0004) != 0) ? 'r' : '-');
|
||||
b.append(((info.mode & 0002) != 0) ? 'w' : '-');
|
||||
b.append(((info.mode & 0001) != 0) ? 'x' : '-');
|
||||
b.append(String.format(" %9d ", info.size));
|
||||
|
||||
Date stamp = new Date(info.mtime);
|
||||
b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
|
||||
|
||||
b.append(info.packageName);
|
||||
b.append(" :: ");
|
||||
b.append(info.domain);
|
||||
b.append(" :: ");
|
||||
b.append(info.path);
|
||||
|
||||
Slog.i(RefactoredBackupManagerService.TAG, b.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRestorableFile(FileMetadata info) {
|
||||
if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.server.backup.restore;
|
||||
import android.app.ApplicationThreadConstants;
|
||||
import android.app.IBackupAgent;
|
||||
import android.app.PackageInstallObserver;
|
||||
import android.app.backup.BackupAgent;
|
||||
import android.app.backup.FullBackup;
|
||||
import android.app.backup.IFullBackupRestoreObserver;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -45,7 +44,6 @@ import com.android.server.backup.utils.AppBackupUtils;
|
||||
import com.android.server.backup.utils.PasswordUtils;
|
||||
import com.android.server.backup.utils.TarBackupReader;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -55,9 +53,7 @@ import java.io.InputStream;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -436,13 +432,13 @@ public class PerformAdbRestoreTask implements Runnable {
|
||||
public void onBytesRead(long bytesRead) {
|
||||
mBytes += bytesRead;
|
||||
}
|
||||
});
|
||||
}, null /* monitor */);
|
||||
FileMetadata info;
|
||||
try {
|
||||
info = tarBackupReader.readTarHeaders();
|
||||
if (info != null) {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
dumpFileMetadata(info);
|
||||
info.dump();
|
||||
}
|
||||
|
||||
final String pkg = info.packageName;
|
||||
@@ -469,7 +465,10 @@ public class PerformAdbRestoreTask implements Runnable {
|
||||
}
|
||||
|
||||
if (info.path.equals(RefactoredBackupManagerService.BACKUP_MANIFEST_FILENAME)) {
|
||||
mPackagePolicies.put(pkg, readAppManifest(info, instream));
|
||||
RestorePolicy appManifest = tarBackupReader.readAppManifest(
|
||||
backupManagerService.getPackageManager(), true /* allowApks */,
|
||||
mManifestSignatures, info);
|
||||
mPackagePolicies.put(pkg, appManifest);
|
||||
mPackageInstallers.put(pkg, info.installerPackageName);
|
||||
// We've read only the manifest content itself at this point,
|
||||
// so consume the footer before looping around to the next
|
||||
@@ -479,7 +478,7 @@ public class PerformAdbRestoreTask implements Runnable {
|
||||
} else if (info.path.equals(
|
||||
RefactoredBackupManagerService.BACKUP_METADATA_FILENAME)) {
|
||||
// Metadata blobs!
|
||||
readMetadata(info, instream);
|
||||
tarBackupReader.readMetadata(info);
|
||||
tarBackupReader.skipTarPadding(info.size);
|
||||
} else {
|
||||
// Non-manifest, so it's actual file data. Is this a package
|
||||
@@ -835,26 +834,7 @@ public class PerformAdbRestoreTask implements Runnable {
|
||||
latch.await();
|
||||
}
|
||||
|
||||
// unbind and tidy up even on timeout or failure, just in case
|
||||
backupManagerService.getActivityManager().unbindBackupAgent(app);
|
||||
|
||||
// The agent was running with a stub Application object, so shut it down.
|
||||
// !!! We hardcode the confirmation UI's package name here rather than use a
|
||||
// manifest flag! TODO something less direct.
|
||||
if (app.uid >= Process.FIRST_APPLICATION_UID
|
||||
&& !app.packageName.equals("com.android.backupconfirm")) {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.d(RefactoredBackupManagerService.TAG, "Killing host process");
|
||||
}
|
||||
backupManagerService.getActivityManager().killApplicationProcess(
|
||||
app.processName,
|
||||
app.uid);
|
||||
} else {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.d(RefactoredBackupManagerService.TAG,
|
||||
"Not killing after full restore");
|
||||
}
|
||||
}
|
||||
backupManagerService.tearDownAgentAndKill(app);
|
||||
} catch (RemoteException e) {
|
||||
Slog.d(RefactoredBackupManagerService.TAG, "Lost app trying to shut down");
|
||||
}
|
||||
@@ -1053,250 +1033,6 @@ public class PerformAdbRestoreTask implements Runnable {
|
||||
return okay;
|
||||
}
|
||||
|
||||
// Read a widget metadata file, returning the restored blob
|
||||
void readMetadata(FileMetadata info, InputStream instream) throws IOException {
|
||||
// Fail on suspiciously large widget dump files
|
||||
if (info.size > 64 * 1024) {
|
||||
throw new IOException("Metadata too big; corrupt? size=" + info.size);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) info.size];
|
||||
if (TarBackupReader.readExactly(instream, buffer, 0, (int) info.size) == info.size) {
|
||||
mBytes += info.size;
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in widget data");
|
||||
}
|
||||
|
||||
String[] str = new String[1];
|
||||
int offset = TarBackupReader.extractLine(buffer, 0, str);
|
||||
int version = Integer.parseInt(str[0]);
|
||||
if (version == RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
final String pkg = str[0];
|
||||
if (info.packageName.equals(pkg)) {
|
||||
// Data checks out -- the rest of the buffer is a concatenation of
|
||||
// binary blobs as described in the comment at writeAppWidgetData()
|
||||
ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
|
||||
offset, buffer.length - offset);
|
||||
DataInputStream in = new DataInputStream(bin);
|
||||
while (bin.available() > 0) {
|
||||
int token = in.readInt();
|
||||
int size = in.readInt();
|
||||
if (size > 64 * 1024) {
|
||||
throw new IOException("Datum "
|
||||
+ Integer.toHexString(token)
|
||||
+ " too big; corrupt? size=" + info.size);
|
||||
}
|
||||
switch (token) {
|
||||
case RefactoredBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN: {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Got widget metadata for " + info.packageName);
|
||||
}
|
||||
mWidgetData = new byte[size];
|
||||
in.read(mWidgetData);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG, "Ignoring metadata blob "
|
||||
+ Integer.toHexString(token)
|
||||
+ " for " + info.packageName);
|
||||
}
|
||||
in.skipBytes(size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Metadata mismatch: package " + info.packageName
|
||||
+ " but widget data for " + pkg);
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG, "Unsupported metadata version " + version);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a policy constant; takes a buffer arg to reduce memory churn
|
||||
RestorePolicy readAppManifest(FileMetadata info, InputStream instream)
|
||||
throws IOException {
|
||||
// Fail on suspiciously large manifest files
|
||||
if (info.size > 64 * 1024) {
|
||||
throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) info.size];
|
||||
if (TarBackupReader.readExactly(instream, buffer, 0, (int) info.size) == info.size) {
|
||||
mBytes += info.size;
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in manifest");
|
||||
}
|
||||
|
||||
RestorePolicy policy = RestorePolicy.IGNORE;
|
||||
String[] str = new String[1];
|
||||
int offset = 0;
|
||||
|
||||
try {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
int version = Integer.parseInt(str[0]);
|
||||
if (version == RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
String manifestPackage = str[0];
|
||||
// TODO: handle <original-package>
|
||||
if (manifestPackage.equals(info.packageName)) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
version = Integer.parseInt(str[0]); // app version
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
// This is the platform version, which we don't use, but we parse it
|
||||
// as a safety against corruption in the manifest.
|
||||
Integer.parseInt(str[0]);
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
boolean hasApk = str[0].equals("1");
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
int numSigs = Integer.parseInt(str[0]);
|
||||
if (numSigs > 0) {
|
||||
Signature[] sigs = new Signature[numSigs];
|
||||
for (int i = 0; i < numSigs; i++) {
|
||||
offset = TarBackupReader.extractLine(buffer, offset, str);
|
||||
sigs[i] = new Signature(str[0]);
|
||||
}
|
||||
mManifestSignatures.put(info.packageName, sigs);
|
||||
|
||||
// Okay, got the manifest info we need...
|
||||
try {
|
||||
PackageInfo pkgInfo =
|
||||
backupManagerService.getPackageManager().getPackageInfo(
|
||||
info.packageName, PackageManager.GET_SIGNATURES);
|
||||
// Fall through to IGNORE if the app explicitly disallows backup
|
||||
final int flags = pkgInfo.applicationInfo.flags;
|
||||
if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
|
||||
// Restore system-uid-space packages only if they have
|
||||
// defined a custom backup agent
|
||||
if ((pkgInfo.applicationInfo.uid
|
||||
>= Process.FIRST_APPLICATION_UID)
|
||||
|| (pkgInfo.applicationInfo.backupAgentName != null)) {
|
||||
// Verify signatures against any installed version; if they
|
||||
// don't match, then we fall though and ignore the data. The
|
||||
// signatureMatch() method explicitly ignores the signature
|
||||
// check for packages installed on the system partition, because
|
||||
// such packages are signed with the platform cert instead of
|
||||
// the app developer's cert, so they're different on every
|
||||
// device.
|
||||
if (AppBackupUtils.signaturesMatch(sigs,
|
||||
pkgInfo)) {
|
||||
if ((pkgInfo.applicationInfo.flags
|
||||
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Package has restoreAnyVersion; taking data");
|
||||
policy = RestorePolicy.ACCEPT;
|
||||
} else if (pkgInfo.versionCode >= version) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Sig + version match; taking data");
|
||||
policy = RestorePolicy.ACCEPT;
|
||||
} else {
|
||||
// The data is from a newer version of the app than
|
||||
// is presently installed. That means we can only
|
||||
// use it if the matching apk is also supplied.
|
||||
Slog.d(RefactoredBackupManagerService.TAG,
|
||||
"Data version " + version
|
||||
+ " is newer than installed version "
|
||||
+ pkgInfo.versionCode
|
||||
+ " - requiring apk");
|
||||
policy = RestorePolicy.ACCEPT_IF_APK;
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Restore manifest signatures do not match "
|
||||
+ "installed application for "
|
||||
+ info.packageName);
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Package " + info.packageName
|
||||
+ " is system level with no agent");
|
||||
}
|
||||
} else {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Restore manifest from "
|
||||
+ info.packageName + " but allowBackup=false");
|
||||
}
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// Okay, the target app isn't installed. We can process
|
||||
// the restore properly only if the dataset provides the
|
||||
// apk file and we can successfully install it.
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Package " + info.packageName
|
||||
+ " not installed; requiring apk in dataset");
|
||||
}
|
||||
policy = RestorePolicy.ACCEPT_IF_APK;
|
||||
}
|
||||
|
||||
if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Cannot restore package " + info.packageName
|
||||
+ " without the matching .apk");
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Missing signature on backed-up package "
|
||||
+ info.packageName);
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Expected package " + info.packageName
|
||||
+ " but restore manifest claims " + manifestPackage);
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Unknown restore manifest version " + version
|
||||
+ " for package " + info.packageName);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Corrupt restore manifest for package " + info.packageName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG, e.getMessage());
|
||||
}
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
void dumpFileMetadata(FileMetadata info) {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
StringBuilder b = new StringBuilder(128);
|
||||
|
||||
// mode string
|
||||
b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
|
||||
b.append(((info.mode & 0400) != 0) ? 'r' : '-');
|
||||
b.append(((info.mode & 0200) != 0) ? 'w' : '-');
|
||||
b.append(((info.mode & 0100) != 0) ? 'x' : '-');
|
||||
b.append(((info.mode & 0040) != 0) ? 'r' : '-');
|
||||
b.append(((info.mode & 0020) != 0) ? 'w' : '-');
|
||||
b.append(((info.mode & 0010) != 0) ? 'x' : '-');
|
||||
b.append(((info.mode & 0004) != 0) ? 'r' : '-');
|
||||
b.append(((info.mode & 0002) != 0) ? 'w' : '-');
|
||||
b.append(((info.mode & 0001) != 0) ? 'x' : '-');
|
||||
b.append(String.format(" %9d ", info.size));
|
||||
|
||||
Date stamp = new Date(info.mtime);
|
||||
b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
|
||||
|
||||
b.append(info.packageName);
|
||||
b.append(" :: ");
|
||||
b.append(info.domain);
|
||||
b.append(" :: ");
|
||||
b.append(info.path);
|
||||
|
||||
Slog.i(RefactoredBackupManagerService.TAG, b.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void sendStartRestore() {
|
||||
if (mObserver != null) {
|
||||
try {
|
||||
|
||||
@@ -500,10 +500,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
|
||||
+ " > installed version " + mCurrentPackage.versionCode;
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Package " + pkgName + ": " + message);
|
||||
Bundle monitoringExtras = backupManagerService.putMonitoringExtra(null,
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
|
||||
metaInfo.versionCode);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(monitoringExtras,
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
|
||||
BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, false);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
|
||||
@@ -521,10 +521,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
|
||||
+ " > installed version " + mCurrentPackage.versionCode
|
||||
+ " but restoreAnyVersion");
|
||||
}
|
||||
Bundle monitoringExtras = backupManagerService.putMonitoringExtra(null,
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
|
||||
metaInfo.versionCode);
|
||||
monitoringExtras = backupManagerService.putMonitoringExtra(monitoringExtras,
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
|
||||
BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, true);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
|
||||
|
||||
@@ -53,4 +53,36 @@ public class BackupManagerMonitorUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Bundle putMonitoringExtra(Bundle extras, String key, String value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putString(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
private static Bundle putMonitoringExtra(Bundle extras, String key, int value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putInt(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
public static Bundle putMonitoringExtra(Bundle extras, String key, long value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putLong(key, value);
|
||||
return extras;
|
||||
}
|
||||
|
||||
public static Bundle putMonitoringExtra(Bundle extras, String key, boolean value) {
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
}
|
||||
extras.putBoolean(key, value);
|
||||
return extras;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,44 @@
|
||||
package com.android.server.backup.utils;
|
||||
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_MANIFEST_PACKAGE_NAME;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OLD_VERSION;
|
||||
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_POLICY_ALLOW_APKS;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH;
|
||||
import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER;
|
||||
|
||||
import android.app.backup.BackupAgent;
|
||||
import android.app.backup.BackupManagerMonitor;
|
||||
import android.app.backup.FullBackup;
|
||||
import android.app.backup.IBackupManagerMonitor;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.backup.FileMetadata;
|
||||
import com.android.server.backup.RefactoredBackupManagerService;
|
||||
import com.android.server.backup.restore.RestorePolicy;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Utility methods to read backup tar file.
|
||||
@@ -30,6 +60,11 @@ public class TarBackupReader {
|
||||
private final InputStream mInputStream;
|
||||
private final BytesReadListener mBytesReadListener;
|
||||
|
||||
private IBackupManagerMonitor mMonitor;
|
||||
|
||||
// Widget blob to be restored out-of-band.
|
||||
private byte[] mWidgetData = null;
|
||||
|
||||
/**
|
||||
* Listener for bytes reading.
|
||||
*/
|
||||
@@ -37,75 +72,11 @@ public class TarBackupReader {
|
||||
void onBytesRead(long bytesRead);
|
||||
}
|
||||
|
||||
public TarBackupReader(InputStream inputStream, BytesReadListener bytesReadListener) {
|
||||
public TarBackupReader(InputStream inputStream, BytesReadListener bytesReadListener,
|
||||
IBackupManagerMonitor monitor) {
|
||||
mInputStream = inputStream;
|
||||
mBytesReadListener = bytesReadListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read exactly the given number of bytes into a buffer at the stated offset.
|
||||
*
|
||||
* @param in - input stream to read bytes from..
|
||||
* @param buffer - where to write bytes to.
|
||||
* @param offset - offset in buffer to write bytes to.
|
||||
* @param size - number of bytes to read.
|
||||
* @return number of bytes actually read.
|
||||
* @throws IOException in case of an error.
|
||||
*/
|
||||
public static int readExactly(InputStream in, byte[] buffer, int offset, int size)
|
||||
throws IOException {
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException("size must be > 0");
|
||||
}
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG, " ... readExactly(" + size + ") called");
|
||||
}
|
||||
int soFar = 0;
|
||||
while (soFar < size) {
|
||||
int nRead = in.read(buffer, offset + soFar, size - soFar);
|
||||
if (nRead <= 0) {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"- wanted exactly " + size + " but got only " + soFar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
soFar += nRead;
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.v(RefactoredBackupManagerService.TAG,
|
||||
" + got " + nRead + "; now wanting " + (size - soFar));
|
||||
}
|
||||
}
|
||||
return soFar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a line from a byte buffer starting at 'offset'.
|
||||
*
|
||||
* @param buffer - where to read a line from.
|
||||
* @param offset - offset in buffer to read a line from.
|
||||
* @param outStr - an output parameter, the result will be put in outStr.
|
||||
* @return the index of the next unconsumed data in the buffer.
|
||||
* @throws IOException in case of an error.
|
||||
*/
|
||||
public static int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
|
||||
final int end = buffer.length;
|
||||
if (offset >= end) {
|
||||
throw new IOException("Incomplete data");
|
||||
}
|
||||
|
||||
int pos;
|
||||
for (pos = offset; pos < end; pos++) {
|
||||
byte c = buffer[pos];
|
||||
// at LF we declare end of line, and return the next char as the
|
||||
// starting point for the next time through
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
outStr[0] = new String(buffer, offset, pos - offset);
|
||||
pos++; // may be pointing an extra byte past the end but that's okay
|
||||
return pos;
|
||||
mMonitor = monitor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,6 +218,454 @@ public class TarBackupReader {
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to read exactly the given number of bytes into a buffer at the stated offset.
|
||||
*
|
||||
* @param in - input stream to read bytes from..
|
||||
* @param buffer - where to write bytes to.
|
||||
* @param offset - offset in buffer to write bytes to.
|
||||
* @param size - number of bytes to read.
|
||||
* @return number of bytes actually read.
|
||||
* @throws IOException in case of an error.
|
||||
*/
|
||||
private static int readExactly(InputStream in, byte[] buffer, int offset, int size)
|
||||
throws IOException {
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException("size must be > 0");
|
||||
}
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG, " ... readExactly(" + size + ") called");
|
||||
}
|
||||
int soFar = 0;
|
||||
while (soFar < size) {
|
||||
int nRead = in.read(buffer, offset + soFar, size - soFar);
|
||||
if (nRead <= 0) {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"- wanted exactly " + size + " but got only " + soFar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
soFar += nRead;
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.v(RefactoredBackupManagerService.TAG,
|
||||
" + got " + nRead + "; now wanting " + (size - soFar));
|
||||
}
|
||||
}
|
||||
return soFar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads app manifest and returns a policy constant.
|
||||
*
|
||||
* @param packageManager - PackageManager instance.
|
||||
* @param allowApks - allow restore set to include apks.
|
||||
* @param manifestSignatures - parsed signatures will be put here.
|
||||
* @param info - file metadata.
|
||||
* @return a policy constant.
|
||||
* @throws IOException in case of an error.
|
||||
*/
|
||||
public RestorePolicy readAppManifest(PackageManager packageManager,
|
||||
boolean allowApks, HashMap<String, Signature[]> manifestSignatures,
|
||||
FileMetadata info)
|
||||
throws IOException {
|
||||
// Fail on suspiciously large manifest files
|
||||
if (info.size > 64 * 1024) {
|
||||
throw new IOException("Restore manifest too big; corrupt? size=" + info.size);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) info.size];
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
" readAppManifest() looking for " + info.size + " bytes");
|
||||
}
|
||||
if (readExactly(mInputStream, buffer, 0, (int) info.size) == info.size) {
|
||||
mBytesReadListener.onBytesRead(info.size);
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in manifest");
|
||||
}
|
||||
|
||||
RestorePolicy policy = RestorePolicy.IGNORE;
|
||||
String[] str = new String[1];
|
||||
int offset = 0;
|
||||
|
||||
try {
|
||||
offset = extractLine(buffer, offset, str);
|
||||
int version = Integer.parseInt(str[0]);
|
||||
if (version == RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION) {
|
||||
offset = extractLine(buffer, offset, str);
|
||||
String manifestPackage = str[0];
|
||||
// TODO: handle <original-package>
|
||||
if (manifestPackage.equals(info.packageName)) {
|
||||
offset = extractLine(buffer, offset, str);
|
||||
version = Integer.parseInt(str[0]); // app version
|
||||
offset = extractLine(buffer, offset, str);
|
||||
// This is the platform version, which we don't use, but we parse it
|
||||
// as a safety against corruption in the manifest.
|
||||
Integer.parseInt(str[0]);
|
||||
offset = extractLine(buffer, offset, str);
|
||||
info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
|
||||
offset = extractLine(buffer, offset, str);
|
||||
boolean hasApk = str[0].equals("1");
|
||||
offset = extractLine(buffer, offset, str);
|
||||
int numSigs = Integer.parseInt(str[0]);
|
||||
if (numSigs > 0) {
|
||||
Signature[] sigs = new Signature[numSigs];
|
||||
for (int i = 0; i < numSigs; i++) {
|
||||
offset = extractLine(buffer, offset, str);
|
||||
sigs[i] = new Signature(str[0]);
|
||||
}
|
||||
manifestSignatures.put(info.packageName, sigs);
|
||||
|
||||
// Okay, got the manifest info we need...
|
||||
try {
|
||||
PackageInfo pkgInfo = packageManager.getPackageInfo(
|
||||
info.packageName, PackageManager.GET_SIGNATURES);
|
||||
// Fall through to IGNORE if the app explicitly disallows backup
|
||||
final int flags = pkgInfo.applicationInfo.flags;
|
||||
if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
|
||||
// Restore system-uid-space packages only if they have
|
||||
// defined a custom backup agent
|
||||
if ((pkgInfo.applicationInfo.uid
|
||||
>= Process.FIRST_APPLICATION_UID)
|
||||
|| (pkgInfo.applicationInfo.backupAgentName != null)) {
|
||||
// Verify signatures against any installed version; if they
|
||||
// don't match, then we fall though and ignore the data. The
|
||||
// signatureMatch() method explicitly ignores the signature
|
||||
// check for packages installed on the system partition, because
|
||||
// such packages are signed with the platform cert instead of
|
||||
// the app developer's cert, so they're different on every
|
||||
// device.
|
||||
if (AppBackupUtils.signaturesMatch(sigs,
|
||||
pkgInfo)) {
|
||||
if ((pkgInfo.applicationInfo.flags
|
||||
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Package has restoreAnyVersion; taking data");
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_RESTORE_ANY_VERSION,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
policy = RestorePolicy.ACCEPT;
|
||||
} else if (pkgInfo.versionCode >= version) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Sig + version match; taking data");
|
||||
policy = RestorePolicy.ACCEPT;
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_VERSIONS_MATCH,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
} else {
|
||||
// The data is from a newer version of the app than
|
||||
// is presently installed. That means we can only
|
||||
// use it if the matching apk is also supplied.
|
||||
if (allowApks) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Data version " + version
|
||||
+ " is newer than installed "
|
||||
+ "version "
|
||||
+ pkgInfo.versionCode
|
||||
+ " - requiring apk");
|
||||
policy = RestorePolicy.ACCEPT_IF_APK;
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Data requires newer version "
|
||||
+ version + "; ignoring");
|
||||
mMonitor = BackupManagerMonitorUtils
|
||||
.monitorEvent(mMonitor,
|
||||
LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
BackupManagerMonitorUtils
|
||||
.putMonitoringExtra(
|
||||
null,
|
||||
EXTRA_LOG_OLD_VERSION,
|
||||
version));
|
||||
|
||||
policy = RestorePolicy.IGNORE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Restore manifest signatures do not match "
|
||||
+ "installed application for "
|
||||
+ info.packageName);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Package " + info.packageName
|
||||
+ " is system level with no agent");
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
|
||||
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_SYSTEM_APP_NO_AGENT,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_AGENT,
|
||||
null);
|
||||
}
|
||||
} else {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Restore manifest from "
|
||||
+ info.packageName + " but allowBackup=false");
|
||||
}
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE,
|
||||
pkgInfo,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
null);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// Okay, the target app isn't installed. We can process
|
||||
// the restore properly only if the dataset provides the
|
||||
// apk file and we can successfully install it.
|
||||
if (allowApks) {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Package " + info.packageName
|
||||
+ " not installed; requiring apk in dataset");
|
||||
}
|
||||
policy = RestorePolicy.ACCEPT_IF_APK;
|
||||
} else {
|
||||
policy = RestorePolicy.IGNORE;
|
||||
}
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
|
||||
null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
|
||||
monitoringExtras,
|
||||
EXTRA_LOG_POLICY_ALLOW_APKS, allowApks);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_APK_NOT_INSTALLED,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
|
||||
if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Cannot restore package " + info.packageName
|
||||
+ " without the matching .apk");
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Missing signature on backed-up package "
|
||||
+ info.packageName);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_MISSING_SIGNATURE,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Expected package " + info.packageName
|
||||
+ " but restore manifest claims " + manifestPackage);
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(
|
||||
monitoringExtras,
|
||||
EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
} else {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Unknown restore manifest version " + version
|
||||
+ " for package " + info.packageName);
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
|
||||
EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Corrupt restore manifest for package " + info.packageName);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
BackupManagerMonitorUtils.putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
|
||||
info.packageName));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.w(RefactoredBackupManagerService.TAG, e.getMessage());
|
||||
}
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
// Given an actual file content size, consume the post-content padding mandated
|
||||
// by the tar format.
|
||||
public void skipTarPadding(long size) throws IOException {
|
||||
long partial = (size + 512) % 512;
|
||||
if (partial > 0) {
|
||||
final int needed = 512 - (int) partial;
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Skipping tar padding: " + needed + " bytes");
|
||||
}
|
||||
byte[] buffer = new byte[needed];
|
||||
if (readExactly(mInputStream, buffer, 0, needed) == needed) {
|
||||
mBytesReadListener.onBytesRead(needed);
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in padding");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a widget metadata file, returning the restored blob.
|
||||
*/
|
||||
public void readMetadata(FileMetadata info) throws IOException {
|
||||
// Fail on suspiciously large widget dump files
|
||||
if (info.size > 64 * 1024) {
|
||||
throw new IOException("Metadata too big; corrupt? size=" + info.size);
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[(int) info.size];
|
||||
if (readExactly(mInputStream, buffer, 0, (int) info.size) == info.size) {
|
||||
mBytesReadListener.onBytesRead(info.size);
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in widget data");
|
||||
}
|
||||
|
||||
String[] str = new String[1];
|
||||
int offset = extractLine(buffer, 0, str);
|
||||
int version = Integer.parseInt(str[0]);
|
||||
if (version == RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION) {
|
||||
offset = extractLine(buffer, offset, str);
|
||||
final String pkg = str[0];
|
||||
if (info.packageName.equals(pkg)) {
|
||||
// Data checks out -- the rest of the buffer is a concatenation of
|
||||
// binary blobs as described in the comment at writeAppWidgetData()
|
||||
ByteArrayInputStream bin = new ByteArrayInputStream(buffer,
|
||||
offset, buffer.length - offset);
|
||||
DataInputStream in = new DataInputStream(bin);
|
||||
while (bin.available() > 0) {
|
||||
int token = in.readInt();
|
||||
int size = in.readInt();
|
||||
if (size > 64 * 1024) {
|
||||
throw new IOException("Datum "
|
||||
+ Integer.toHexString(token)
|
||||
+ " too big; corrupt? size=" + info.size);
|
||||
}
|
||||
switch (token) {
|
||||
case RefactoredBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN: {
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Got widget metadata for " + info.packageName);
|
||||
}
|
||||
mWidgetData = new byte[size];
|
||||
in.read(mWidgetData);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (RefactoredBackupManagerService.DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG, "Ignoring metadata blob "
|
||||
+ Integer.toHexString(token)
|
||||
+ " for " + info.packageName);
|
||||
}
|
||||
in.skipBytes(size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG,
|
||||
"Metadata mismatch: package " + info.packageName
|
||||
+ " but widget data for " + pkg);
|
||||
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
|
||||
EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
|
||||
BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
} else {
|
||||
Slog.w(RefactoredBackupManagerService.TAG, "Unsupported metadata version " + version);
|
||||
|
||||
Bundle monitoringExtras = BackupManagerMonitorUtils
|
||||
.putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
|
||||
info.packageName);
|
||||
monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(monitoringExtras,
|
||||
EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
|
||||
mMonitor = BackupManagerMonitorUtils.monitorEvent(
|
||||
mMonitor,
|
||||
BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION,
|
||||
null,
|
||||
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
|
||||
monitoringExtras);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a line from a byte buffer starting at 'offset'.
|
||||
*
|
||||
* @param buffer - where to read a line from.
|
||||
* @param offset - offset in buffer to read a line from.
|
||||
* @param outStr - an output parameter, the result will be put in outStr.
|
||||
* @return the index of the next unconsumed data in the buffer.
|
||||
* @throws IOException in case of an error.
|
||||
*/
|
||||
private static int extractLine(byte[] buffer, int offset, String[] outStr) throws IOException {
|
||||
final int end = buffer.length;
|
||||
if (offset >= end) {
|
||||
throw new IOException("Incomplete data");
|
||||
}
|
||||
|
||||
int pos;
|
||||
for (pos = offset; pos < end; pos++) {
|
||||
byte c = buffer[pos];
|
||||
// at LF we declare end of line, and return the next char as the
|
||||
// starting point for the next time through
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
outStr[0] = new String(buffer, offset, pos - offset);
|
||||
pos++; // may be pointing an extra byte past the end but that's okay
|
||||
return pos;
|
||||
}
|
||||
|
||||
private boolean readTarHeader(byte[] block) throws IOException {
|
||||
final int got = readExactly(mInputStream, block, 0, 512);
|
||||
if (got == 0) {
|
||||
@@ -323,25 +742,6 @@ public class TarBackupReader {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given an actual file content size, consume the post-content padding mandated
|
||||
// by the tar format.
|
||||
public void skipTarPadding(long size) throws IOException {
|
||||
long partial = (size + 512) % 512;
|
||||
if (partial > 0) {
|
||||
final int needed = 512 - (int) partial;
|
||||
if (RefactoredBackupManagerService.MORE_DEBUG) {
|
||||
Slog.i(RefactoredBackupManagerService.TAG,
|
||||
"Skipping tar padding: " + needed + " bytes");
|
||||
}
|
||||
byte[] buffer = new byte[needed];
|
||||
if (readExactly(mInputStream, buffer, 0, needed) == needed) {
|
||||
mBytesReadListener.onBytesRead(needed);
|
||||
} else {
|
||||
throw new IOException("Unexpected EOF in padding");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long extractRadix(byte[] data, int offset, int maxChars, int radix)
|
||||
throws IOException {
|
||||
long value = 0;
|
||||
@@ -388,4 +788,11 @@ public class TarBackupReader {
|
||||
}
|
||||
}
|
||||
|
||||
public IBackupManagerMonitor getMonitor() {
|
||||
return mMonitor;
|
||||
}
|
||||
|
||||
public byte[] getWidgetData() {
|
||||
return mWidgetData;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user