Skip to content

Instantly share code, notes, and snippets.

@SeeFlowerX
Created April 30, 2023 07:42
Show Gist options
  • Save SeeFlowerX/2887756e37ac2e7cce5f6fc65f6a7c00 to your computer and use it in GitHub Desktop.
Save SeeFlowerX/2887756e37ac2e7cce5f6fc65f6a7c00 to your computer and use it in GitHub Desktop.
com.miui.backup.restore.FullBackup
package com.miui.backup.restore;
import android.content.Context;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import com.miui.backup.BackupLog;
import com.miui.backup.utils.FileUtils;
import com.miui.backup.utils.StorageManagerCompat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class FullBackup {
public static class BackupScheme {
private String mClonePath;
private String mExternalPath;
private String mPackageName;
final StorageManager mStorageManager;
private StorageVolume[] mVolumes;
BackupScheme(Context context, String packageName, int userId) {
this.mVolumes = null;
this.mStorageManager = (StorageManager)context.getSystemService("storage");
this.mPackageName = packageName;
this.mClonePath = FullBackup.getSourcePath(packageName, userId);
this.mExternalPath = FullBackup.getSourceExternalPath(packageName, userId);
}
private StorageVolume[] getVolumeList() {
if(this.mStorageManager == null) {
Log.e("FullBackup", "Unable to access Storage Manager");
}
return this.mVolumes;
}
private String sharedDomainToPath(String domain) throws IOException {
BackupLog.e("FullBackup", "sharedDomainToPath error" + domain);
this.getVolumeList();
int v = this.mVolumes.length;
if(Integer.parseInt(domain.substring(7)) < v) {
BackupLog.e("FullBackup", "sharedDomainToPath error" + domain);
}
return null;
}
public String tokenToDirectoryPath(String domainToken) {
if(!domainToken.equals("f")) {
goto label_2;
}
try {
return this.mClonePath + File.separator + "files";
label_2:
if(domainToken.equals("db")) {
return this.mClonePath + File.separator + "databases";
}
if(domainToken.equals("r")) {
return this.mClonePath;
}
if(domainToken.equals("sp")) {
return this.mClonePath + File.separator + "shared_prefs";
}
if(domainToken.equals("c")) {
return this.mClonePath + File.separator + "cache";
}
if(domainToken.equals("nb")) {
return this.mClonePath + File.separator + "no_backup";
}
if(domainToken.equals("d_f")) {
return this.mClonePath + File.separator + "user_de" + File.separator + "files";
}
if(domainToken.equals("d_db")) {
return this.mClonePath + File.separator + "user_de" + File.separator + "databases";
}
if(domainToken.equals("d_r")) {
return this.mClonePath + File.separator + "user_de";
}
if(domainToken.equals("d_sp")) {
return this.mClonePath + File.separator + "user_de" + File.separator + "shared_prefs";
}
if(domainToken.equals("d_c")) {
return this.mClonePath + File.separator + "user_de" + File.separator + "cache";
}
if(domainToken.equals("d_nb")) {
return this.mClonePath + File.separator + "user_de" + File.separator + "no_backup";
}
if(domainToken.equals("ef")) {
return this.mExternalPath;
}
if(domainToken.startsWith("shared/")) {
return this.sharedDomainToPath(domainToken);
}
Log.i("FullBackup", "Unrecognized domain " + domainToken);
}
catch(Exception e) {
Log.i("FullBackup", "Error reading directory for domain: " + domainToken);
}
return null;
}
}
public static final String APK_TREE_TOKEN = "a";
public static final String APPS_PREFIX = "apps/";
public static final int BACKUP_FILE_VERSION = 2;
private static final String CACHE_TREE_TOKEN = "c";
private static final String DATABASE_TREE_TOKEN = "db";
private static final String DEVICE_CACHE_TREE_TOKEN = "d_c";
private static final String DEVICE_DATABASE_TREE_TOKEN = "d_db";
private static final String DEVICE_FILES_TREE_TOKEN = "d_f";
private static final String DEVICE_NO_BACKUP_TREE_TOKEN = "d_nb";
private static final String DEVICE_ROOT_TREE_TOKEN = "d_r";
private static final String DEVICE_SHAREDPREFS_TREE_TOKEN = "d_sp";
private static final String FILES_TREE_TOKEN = "f";
public static final String KEY_VALUE_DATA_TOKEN = "k";
public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
private static final String NO_BACKUP_TREE_TOKEN = "nb";
public static final String OBB_TREE_TOKEN = "obb";
private static final String ROOT_TREE_TOKEN = "r";
private static final String SHAREDPREFS_TREE_TOKEN = "sp";
public static final String SHARED_PREFIX = "shared/";
public static final String SHARED_STORAGE_TOKEN = "shared";
private static final String TAG = "FullBackup";
public static BackupScheme getBackupScheme(Context context, String packageName, int userId) {
return new BackupScheme(context, packageName, userId);
}
public static String getDestExternalPath(String packageName, int userId) {
return "/storage/emulated/" + userId + File.separator + "Android" + File.separator + "data" + File.separator + packageName + File.separator + "files";
}
public static String getDestObbPath(String packageName, int userId) {
return "/storage/emulated/" + userId + File.separator + "Android" + File.separator + "obb" + File.separator + packageName;
}
public static String getDestPath(String packageName, int userId) {
return "/data/user/" + userId + File.separator + packageName;
}
private static String getPreorderString(String pkg, int userId) {
StringBuilder sb = new StringBuilder();
sb.append("/storage/emulated/").append(userId).append("/Android/data/com.miui.backup/files/clone/u").append(userId + File.separator + pkg);
return sb.toString();
}
public static String getSourceExternalPath(String pkg, int userId) {
return FullBackup.getPreorderString(pkg, userId) + File.separator + "files";
}
public static String getSourceObbPath(String pkg, int userId) {
return FullBackup.getPreorderString(pkg, userId) + File.separator + "obb";
}
public static String getSourcePath(String pkg, int userId) {
StringBuilder sb = new StringBuilder();
sb.append("/data/user/").append(userId).append("/com.miui.backup/files/clone/u").append(userId + File.separator + pkg);
return sb.toString();
}
public static boolean moveAndFixData(Context context, String packageName, int userId) {
BackupLog.d("FullBackup", "onRestoreDataEnd start move sdcard data");
StorageManager mStorageManager = (StorageManager)context.getSystemService("storage");
boolean z = FileUtils.startMoveDir(FullBackup.getSourceExternalPath(packageName, userId), FullBackup.getDestExternalPath(packageName, userId));
StorageManagerCompat.fixAppDir(mStorageManager, FullBackup.getDestExternalPath(packageName, userId));
boolean z1 = FileUtils.startMoveDir(FullBackup.getSourceObbPath(packageName, userId), FullBackup.getDestObbPath(packageName, userId));
StorageManagerCompat.fixAppDir(mStorageManager, FullBackup.getDestObbPath(packageName, userId));
BackupLog.i("FullBackup", "package : " + packageName + " data has moved");
return (z) && (z1);
}
public static void restoreFile(InputStream data, long size, int type, long mode, long mtime, File outFile) throws IOException {
FileOutputStream fileOutputStream1;
if(type != 2) {
FileOutputStream out = null;
if(outFile != null) {
try {
File file1 = outFile.getParentFile();
if(!file1.exists()) {
file1.mkdirs();
}
fileOutputStream1 = new FileOutputStream(outFile);
}
catch(IOException e) {
Log.e("FullBackup", "Unable to create/open file " + outFile.getPath(), e);
goto label_16;
}
out = fileOutputStream1;
}
label_16:
byte[] buffer = new byte[0x8000];
for(long size = size; size > 0L; size -= (long)v5) {
int v5 = data.read(buffer, 0, (size <= 0x8000L ? ((int)size) : 0x8000));
if(v5 <= 0) {
Log.w("FullBackup", "Incomplete read: expected " + size + " but got " + (size - size));
break;
}
if(out != null) {
try {
out.write(buffer, 0, v5);
}
catch(IOException iOException1) {
Log.e("FullBackup", "Unable to write to file " + outFile.getPath(), iOException1);
out.close();
outFile.delete();
out = null;
}
}
}
if(out != null) {
out.close();
}
}
else if(outFile != null) {
outFile.mkdirs();
}
if(mode >= 0L && outFile != null) {
try {
Os.chmod(outFile.getPath(), ((int)(mode & 0x1C0L)));
}
catch(ErrnoException e) {
BackupLog.d("FullBackup", "chmod file fail:" + e);
outFile.setLastModified(mtime);
return;
}
outFile.setLastModified(mtime);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment