All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.backup.fullbackup.AppMetadataBackupWriter Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
package com.android.server.backup.fullbackup;

import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
import static com.android.server.backup.BackupManagerService.TAG;
import static com.android.server.backup.UserBackupManagerService.BACKUP_MANIFEST_VERSION;
import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA_VERSION;
import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN;

import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.util.StringBuilderPrinter;

import com.android.internal.util.Preconditions;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Writes the backup of app-specific metadata to {@link FullBackupDataOutput}. This data is not
 * backed up by the app's backup agent and is written before the agent writes its own data. This
 * includes the app's:
 *
 * 
    *
  • manifest *
  • widget data *
  • apk *
  • obb content *
*/ // TODO(b/113807190): Fix or remove apk and obb implementation (only used for adb). public class AppMetadataBackupWriter { private final FullBackupDataOutput mOutput; private final PackageManager mPackageManager; /** The destination of the backup is specified by {@code output}. */ public AppMetadataBackupWriter(FullBackupDataOutput output, PackageManager packageManager) { mOutput = output; mPackageManager = packageManager; } /** * Back up the app's manifest without specifying a pseudo-directory for the TAR stream. * * @see #backupManifest(PackageInfo, File, File, String, String, boolean) */ public void backupManifest( PackageInfo packageInfo, File manifestFile, File filesDir, boolean withApk) throws IOException { backupManifest( packageInfo, manifestFile, filesDir, /* domain */ null, /* linkDomain */ null, withApk); } /** * Back up the app's manifest. * *
    *
  1. Write the app's manifest data to the specified temporary file {@code manifestFile}. *
  2. Backup the file in TAR format to the backup destination {@link #mOutput}. *
* *

Note: {@code domain} and {@code linkDomain} are only used by adb to specify a * pseudo-directory for the TAR stream. */ // TODO(b/113806991): Look into streaming the backup data directly. public void backupManifest( PackageInfo packageInfo, File manifestFile, File filesDir, @Nullable String domain, @Nullable String linkDomain, boolean withApk) throws IOException { byte[] manifestBytes = getManifestBytes(packageInfo, withApk); FileOutputStream outputStream = new FileOutputStream(manifestFile); outputStream.write(manifestBytes); outputStream.close(); // We want the manifest block in the archive stream to be constant each time we generate // a backup stream for the app. However, the underlying TAR mechanism sees it as a file and // will propagate its last modified time. We pin the last modified time to zero to prevent // the TAR header from varying. manifestFile.setLastModified(0); FullBackup.backupToTar( packageInfo.packageName, domain, linkDomain, filesDir.getAbsolutePath(), manifestFile.getAbsolutePath(), mOutput); } /** * Gets the app's manifest as a byte array. All data are strings ending in LF. * *

The manifest format is: * *

     *     BACKUP_MANIFEST_VERSION
     *     package name
     *     package version code
     *     platform version code
     *     installer package name (can be empty)
     *     boolean (1 if archive includes .apk, otherwise 0)
     *     # of signatures N
     *     N* (signature byte array in ascii format per Signature.toCharsString())
     * 
*/ private byte[] getManifestBytes(PackageInfo packageInfo, boolean withApk) { String packageName = packageInfo.packageName; StringBuilder builder = new StringBuilder(4096); StringBuilderPrinter printer = new StringBuilderPrinter(builder); printer.println(Integer.toString(BACKUP_MANIFEST_VERSION)); printer.println(packageName); printer.println(Long.toString(packageInfo.getLongVersionCode())); printer.println(Integer.toString(Build.VERSION.SDK_INT)); String installerName = mPackageManager.getInstallerPackageName(packageName); printer.println((installerName != null) ? installerName : ""); printer.println(withApk ? "1" : "0"); // Write the signature block. SigningInfo signingInfo = packageInfo.signingInfo; if (signingInfo == null) { printer.println("0"); } else { // Retrieve the newest signatures to write. // TODO (b/73988180) use entire signing history in case of rollbacks. Signature[] signatures = signingInfo.getApkContentsSigners(); printer.println(Integer.toString(signatures.length)); for (Signature sig : signatures) { printer.println(sig.toCharsString()); } } return builder.toString().getBytes(); } /** * Backup specified widget data. The widget data is prefaced by a metadata header. * *
    *
  1. Write a metadata header to the specified temporary file {@code metadataFile}. *
  2. Write widget data bytes to the same file. *
  3. Backup the file in TAR format to the backup destination {@link #mOutput}. *
* * @throws IllegalArgumentException if the widget data provided is empty. */ // TODO(b/113806991): Look into streaming the backup data directly. public void backupWidget( PackageInfo packageInfo, File metadataFile, File filesDir, byte[] widgetData) throws IOException { Preconditions.checkArgument(widgetData.length > 0, "Can't backup widget with no data."); String packageName = packageInfo.packageName; FileOutputStream fileOutputStream = new FileOutputStream(metadataFile); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream); byte[] metadata = getMetadataBytes(packageName); bufferedOutputStream.write(metadata); // bypassing DataOutputStream writeWidgetData(dataOutputStream, widgetData); bufferedOutputStream.flush(); dataOutputStream.close(); // As with the manifest file, guarantee consistency of the archive metadata for the widget // block by using a fixed last modified time on the metadata file. metadataFile.setLastModified(0); FullBackup.backupToTar( packageName, /* domain */ null, /* linkDomain */ null, filesDir.getAbsolutePath(), metadataFile.getAbsolutePath(), mOutput); } /** * Gets the app's metadata as a byte array. All entries are strings ending in LF. * *

The metadata format is: * *

     *     BACKUP_METADATA_VERSION
     *     package name
     * 
*/ private byte[] getMetadataBytes(String packageName) { StringBuilder builder = new StringBuilder(512); StringBuilderPrinter printer = new StringBuilderPrinter(builder); printer.println(Integer.toString(BACKUP_METADATA_VERSION)); printer.println(packageName); return builder.toString().getBytes(); } /** * Write a byte array of widget data to the specified output stream. All integers are binary in * network byte order. * *

The widget data format: * *

     *     4 : Integer token identifying the widget data blob.
     *     4 : Integer size of the widget data.
     *     N : Raw bytes of the widget data.
     * 
*/ private void writeWidgetData(DataOutputStream out, byte[] widgetData) throws IOException { out.writeInt(BACKUP_WIDGET_METADATA_TOKEN); out.writeInt(widgetData.length); out.write(widgetData); } /** * Backup the app's .apk to the backup destination {@link #mOutput}. Currently only used for * 'adb backup'. */ // TODO(b/113807190): Investigate and potentially remove. public void backupApk(PackageInfo packageInfo) { // TODO: handle backing up split APKs String appSourceDir = packageInfo.applicationInfo.getBaseCodePath(); String apkDir = new File(appSourceDir).getParent(); FullBackup.backupToTar( packageInfo.packageName, FullBackup.APK_TREE_TOKEN, /* linkDomain */ null, apkDir, appSourceDir, mOutput); } /** * Backup the app's .obb files to the backup destination {@link #mOutput}. Currently only used * for 'adb backup'. */ // TODO(b/113807190): Investigate and potentially remove. public void backupObb(@UserIdInt int userId, PackageInfo packageInfo) { // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM doesn't have access to // external storage. Environment.UserEnvironment userEnv = new Environment.UserEnvironment(userId); File obbDir = userEnv.buildExternalStorageAppObbDirs(packageInfo.packageName)[0]; if (obbDir != null) { if (MORE_DEBUG) { Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath()); } File[] obbFiles = obbDir.listFiles(); if (obbFiles != null) { String obbDirName = obbDir.getAbsolutePath(); for (File obb : obbFiles) { FullBackup.backupToTar( packageInfo.packageName, FullBackup.OBB_TREE_TOKEN, /* linkDomain */ null, obbDirName, obb.getAbsolutePath(), mOutput); } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy