Android之备份服务(Bacackupanagerervice)

代码路径

注:
Android 7.1源码

frameworks/base/core/java/android/app/backup
frameworks/base/core/java/com/android/internal/backup
frameworks/base/services/backup

启动

com.android.server.SystemServer
    private static final String BACKUP_MANAGER_SERVICE_CLASS =
            "com.android.server.backup.BackupManagerService$Lifecycle";
            
    private void startOtherServices() {
        ···
        if (!disableNonCoreServices) {
            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {//这个是软功能,通过system/etc下面的xml文件控制
                mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
            }
            ····
        }
        ···
    
    }
    
com.android.server.backup.BackupManagerService

    static Trampoline sInstance;
    static Trampoline getInstance() {
        // Always constructed during system bringup, so no need to lazy-init
        return sInstance;
    }

    public static final class Lifecycle extends SystemService {

        public Lifecycle(Context context) {
            super(context);
            sInstance = new Trampoline(context);
        }

        @Override
        public void onStart() {
            publishBinderService(Context.BACKUP_SERVICE, sInstance);//将BACKUP_SERVICE注册到ServiceManager,注意sInstance是Trampoline对象
        }
        
        @Override
        public void onUnlockUser(int userId) {
            if (userId == UserHandle.USER_SYSTEM) {
                sInstance.initialize(userId);//初始化状态,这里涉及BackupManagerService的初始化
                ····
            }
        }
        ···
    }


com.android.server.backup.Trampoline

1)Trampoline extends IBackupManager.Stub
2)
    volatile BackupManagerService mService;

    public Trampoline(Context context) {
        mContext = context;
        File dir = new File(Environment.getDataDirectory(), "backup");
        dir.mkdirs();
        mSuppressFile = new File(dir, BACKUP_SUPPRESS_FILENAME);
        mGlobalDisable = SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
    }

    // internal control API
    public void initialize(final int whichUser) {
        // Note that only the owner user is currently involved in backup/restore
        // TODO: http://b/22388012
        if (whichUser == UserHandle.USER_SYSTEM) {
            // Does this product support backup/restore at all?
            if (mGlobalDisable) {//通过此值可以判断是否初始化成功
                Slog.i(TAG, "Backup/restore not supported");
                return;
            }

            synchronized (this) {
                if (!mSuppressFile.exists()) {//mSuppressFile 也会抑制mService初始化
                    mService = new BackupManagerService(mContext, this);
                } else {
                    Slog.i(TAG, "Backup inactive in user " + whichUser);
                }
            }
        }
    }
    
小结
控制BackupManagerService启动的因素有几种:
a.config.disable_noncore 是否正常 默认false
b.android.software.backup 是否在/system/etc/**.xml定义
c.a和b正常,则可通过命令检查:
adb shell dumpsys backup  是否有Inactive
d.如果是不激活状态,可查具体原因:
a)adb shell getprop ro.backup.disable true代表不激活服务
b)/data/backup/backup-suppress 文件存在代表不激活服务

接口分析 fullBackup -- 全量备份接口
案例

IBackupManager bm = IBackupManager.Stub.asInterface(
                        ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
    ParcelFileDescriptor pf = ParcelFileDescriptor.open(mAppBackupFile, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE |
                            ParcelFileDescriptor.MODE_TRUNCATE);
    bm.fullBackup(pf, true, false, false, false, false, true, false, new String[]{mCurrentUpgradeItem.getName()});
}

问题:接口具体备份了哪些文件?怎么实现的?

a)简介

    /**
     * Write a full backup of the given package to the supplied file descriptor.
     * The fd may be a socket or other non-seekable destination.  If no package names
     * are supplied, then every application on the device will be backed up to the output.
     *
     * 

This method is synchronous -- it does not return until the backup has * completed. * *

Callers must hold the android.permission.BACKUP permission to use this method. * * @param fd The file descriptor to which a 'tar' file stream is to be written * @param includeApks If true, the resulting tar stream will include the * application .apk files themselves as well as their data. * @param includeObbs If true, the resulting tar stream will include any * application expansion (OBB) files themselves belonging to each application. * @param includeShared If true, the resulting tar stream will include * the contents of the device's shared storage (SD card or equivalent). * @param allApps If true, the resulting tar stream will include all * installed applications' data, not just those named in the packageNames * parameter. * @param allIncludesSystem If {@code true}, then {@code allApps} will be interpreted * as including packages pre-installed as part of the system. If {@code false}, * then setting {@code allApps} to {@code true} will mean only that all 3rd-party * applications will be included in the dataset. * @param packageNames The package names of the apps whose data (and optionally .apk files) * are to be backed up. The allApps parameter supersedes this. */ void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem, boolean doCompress, in String[] packageNames);

b)具体流程
1)Trampoline.fullBackup -- > BackupManagerService.fullBackup

    public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
            boolean includeObbs, boolean includeShared, boolean doWidgets,
            boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) {
        ······
        try {
            ······
            FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
                    includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList);
            final int token = generateToken();
            synchronized (mFullConfirmations) {
                mFullConfirmations.put(token, params);//高级用法,将自定义变量放在本地,只是把标签跨进程传出去
            }
            ······

            // start up the confirmation UI
            if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) {//增加用户体验:调用UI进程让用户自行选择是否需要备份
                mFullConfirmations.delete(token);
                return;
            }
            ·······

            // start the confirmation countdown
            startConfirmationTimeout(token, params);//监听UI进程的反馈

            // wait for the backup to be performed
            waitForCompletion(params);//等待
        } finally {
            ······
        }
    }
    
    boolean startConfirmationUi(int token, String action) {//注意:这里可以定制化
        try {
            Intent confIntent = new Intent(action);
            confIntent.setClassName("com.android.backupconfirm",
                    "com.android.backupconfirm.BackupRestoreConfirmation");
            confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);//注意只传了一个token
            confIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM);
        } catch (ActivityNotFoundException e) {
            return false;
        }
        return true;
    }
    
关注进程间通信:
    A-->System_server
    System_server-->B
    B-->System_server
    此过程在没有回调方法的前提下,怎么实现数据对接的?又是怎么监听跨进程的任务完成?

2)BackupRestoreConfirmation.sendAcknowledgement

代码路径:
frameworks/base/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java

public class BackupRestoreConfirmation extends Activity {
    
    @Override
    public void onCreate(Bundle icicle) {
        ······
        mAllowButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendAcknowledgement(mToken, true, mObserver);
                ······
            }
        });
        ······
    }
    
    void sendAcknowledgement(int token, boolean allow, IFullBackupRestoreObserver observer) {
        try {
            mBackupManager.acknowledgeFullBackupOrRestore(mToken,
                    allow,
                    String.valueOf(mCurPassword.getText()),
                    String.valueOf(encPassword),
                    mObserver);//UI进程调进system_server进程,关注mToken
        } catch (RemoteException e) {
                
        }
    }
}

3)Trampoline.acknowledgeFullBackupOrRestore -- > BackupManagerService.acknowledgeFullBackupOrRestore

    public void acknowledgeFullBackupOrRestore(int token, boolean allow,
            String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
        ······
        try {

            FullParams params;
            synchronized (mFullConfirmations) {
                params = mFullConfirmations.get(token);//通过token获取保存的对象
                if (params != null) {
                    mBackupHandler.removeMessages(MSG_FULL_CONFIRMATION_TIMEOUT, params);//移除超时监听
                    mFullConfirmations.delete(token);//从队列中删除保存对象

                    if (allow) {
                        final int verb = params instanceof FullBackupParams
                                ? MSG_RUN_ADB_BACKUP//因为params为FullBackupParams,所以是MSG_RUN_ADB_BACKUP
                                : MSG_RUN_ADB_RESTORE;

                        params.observer = observer;//跨进程的回调对象
                        ······
                        Message msg = mBackupHandler.obtainMessage(verb, params);
                        mBackupHandler.sendMessage(msg);
                    } else {
                        ······
                    }
                } else {
                    Slog.w(TAG, "Attempted to ack full backup/restore with invalid token");
                }
            }
        } finally {
            ······
        }
    }

4)BackupManagerService.BackupHandler(what=MSG_RUN_ADB_BACKUP)

BackupHandler
   public void handleMessage(Message msg)
        case MSG_RUN_ADB_BACKUP:
        {
                FullBackupParams params = (FullBackupParams)msg.obj;
                PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd,
                        params.observer, params.includeApks, params.includeObbs,
                        params.includeShared, params.doWidgets,
                        params.curPassword, params.encryptPassword,
                        params.allApps, params.includeSystem, params.doCompress,
                        params.packages, params.latch);
                (new Thread(task, "adb-backup")).start();//执行线程,关注task
                break;
        }
5)BackupManagerService.PerformAdbBackupTask.run

PerformAdbBackupTask
        public void run() {
            ······
            
            sendStartBackup();//通知回调方法onStartBackup
            
            ······
            if (mPackages != null) {
                addPackagesToSet(packagesToBackup, mPackages);//packagesToBackup初始化需要备份的app
            }
            
            ······

            ArrayList backupQueue =
                    new ArrayList(packagesToBackup.values());//需要备份的队列
            FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());//mOutputFile就是fullBackup传入的fd
            OutputStream out = null;
            ······
            try {
                ······
                OutputStream finalOutput = ofstream;
                ······
                try {
                    ······
                    out = finalOutput;
                } catch (Exception e) {
                    ······
                }
                ······
                int N = backupQueue.size();
                for (int i = 0; i < N; i++) {
                    pkg = backupQueue.get(i);
                    final boolean isSharedStorage =
                            pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);

                    mBackupEngine = new FullBackupEngine(out, null, pkg, mIncludeApks, this);
                    sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);//通知回调方法onBackupPackage

                    mBackupEngine.backupOnePackage();//执行app的备份工作
                    ······
                }

            } catch (RemoteException e) {
                
            } catch (Exception e) {
                
            } finally {
                ······
                synchronized (mLatch) {
                    mLatch.set(true);
                    mLatch.notifyAll();//这里就是解除fullBackup的等待
                }
                sendEndBackup();//通知回调方法onEndBackup
                ·······
            }
        }

5)BackupManagerService.FullBackupEngine.backupOnePackage

FullBackupEngine
        public int backupOnePackage() throws RemoteException {
            int result = BackupTransport.AGENT_ERROR;

            if (initializeAgent()) {//初始化需要备份的app的mAgent。后面专题特殊说明
                ParcelFileDescriptor[] pipes = null;
                try {
                    pipes = ParcelFileDescriptor.createPipe();//创建管道,[0]读 [1]写
                    
                    ······

                    final int token = generateToken();
                    FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1],
                            token, sendApk, !isSharedStorage, widgetBlob);
                    pipes[1].close();   // the runner has dup'd it
                    pipes[1] = null;
                    Thread t = new Thread(runner, "app-data-runner");
                    t.start();//将数据写入管道[1]中,这也是一种跨进程的通信。解决跨进程间获取资源文件问题

                    routeSocketDataToOutput(pipes[0], mOutput);//从管道[0]中读出来的数据,写入我们fullBackup制定的fd中
                    ······
                } catch (IOException e) {
                    
                } finally {
                    
                }
            } else {
                Slog.w(TAG, "Unable to bind to full agent for " + mPkg.packageName);
            }
            ······
            return result;
        }
高级用法:
采用匿名管道实现跨进程获取资源文件

6)BackupManagerService.FullBackupEngine.FullBackupRunner.run

FullBackupRunner
            public void run() {
                try {
                    FullBackupDataOutput output = new FullBackupDataOutput(mPipe);

                    ·······

                    if (mSendApk) {
                        writeApkToBackup(mPackage, output);//备份apk
                    }

                    ······
                    mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);//备份apk的用户数据
                } catch (IOException e) {
                    
                } catch (RemoteException e) {
                    
                } finally {
                    
                }
            }

        private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
            ······
            final String appSourceDir = pkg.applicationInfo.getBaseCodePath();//路径,例如/data/app/com.test.test-1/base.apk
            final String apkDir = new File(appSourceDir).getParent();
            FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
                    apkDir, appSourceDir, output);//打包apk
            ······
        }
        
注意:
1.output仅仅是管道[1]的载体,真正写到我们指定的文件是通过从管道[0]中读出数据,填充到指定fd
2.备份的apk文件路径为:
/data/app/***/base.apk
3.调用android.app.backup.FullBackup.backupToTar方法

7)BackupManagerService.FullBackupEngine.mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder); 注: 此业务代码路线比较长,需要特别拿出来说
(a)先说重点,此方法打包的就是app运行的用户资源。例如:

/data/user/0/包名/*

(b)代码实现
(1)mAgent初始化:BackupManagerService.FullBackupEngine.initializeAgent

BackupManagerService.FullBackupEngine.backupOnePackage可知:
        BackupManagerService.FullBackupEngine.initializeAgent
        private boolean initializeAgent() {
            if (mAgent == null) {
                mAgent = bindToAgentSynchronous(mPkg.applicationInfo,
                        IApplicationThread.BACKUP_MODE_FULL);
            }
            return mAgent != null;
        }

(2)BackupManagerService.bindToAgentSynchronous

    IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
        IBackupAgent agent = null;
        synchronized(mAgentConnectLock) {
            mConnecting = true;
            mConnectedAgent = null;
            try {
                if (mActivityManager.bindBackupAgent(app.packageName, mode,
                        UserHandle.USER_OWNER)) {//通过Ams绑定app获取mConnectedAgent
                    
                    long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
                    while (mConnecting && mConnectedAgent == null
                            && (System.currentTimeMillis() < timeoutMark)) {//等待mConnectedAgent被赋值
                        try {
                            mAgentConnectLock.wait(5000);//休眠等待被通知
                        } catch (InterruptedException e) {
                            // just bail
                            Slog.w(TAG, "Interrupted: " + e);
                            mConnecting = false;
                            mConnectedAgent = null;
                        }
                    }
                    ······
                    agent = mConnectedAgent;//期待在等待的时间内,mConnectedAgent被赋予成功
                }
            } catch (RemoteException e) {
                
            }
        }
        if (agent == null) {
            try {
                mActivityManager.clearPendingBackup();
            } catch (RemoteException e) {
                // can't happen - ActivityManager is local
            }
        }
        return agent;
    }

(3)ActivityManagerService.bindBackupAgent

    public boolean bindBackupAgent(String packageName, int backupMode, int userId) {
        ······
        synchronized(this) {
            ······
            ProcessRecord proc = startProcessLocked(app.processName, app,
                    false, 0, "backup", hostingName, false, false, false);//启动app
            if (proc == null) {
                Slog.e(TAG, "Unable to start backup agent process " + r);
                return false;
            }

            ······
            if (proc.thread != null) {
                ······
                try {
                    proc.thread.scheduleCreateBackupAgent(app,
                            compatibilityInfoForPackageLocked(app), backupMode);//执行IApplicationThread,scheduleCreateBackupAgent
                } catch (RemoteException e) {
                    // Will time out on the backup manager side
                }
            } else {
                
            }
            ······
        }

        return true;
    }

(4)ApplicationThreadNative.java ApplicationThreadProxy.scheduleCreateBackupAgent

代码路径:
frameworks/base/core/java/android/app/ApplicatinThreadNative
ApplicationThreadProxy
    public final void scheduleCreateBackupAgent(ApplicationInfo app,
            CompatibilityInfo compatInfo, int backupMode) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        app.writeToParcel(data, 0);
        compatInfo.writeToParcel(data, 0);
        data.writeInt(backupMode);
        mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }

ApplicationThreadNative
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        ······
        case SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION:
        {
            data.enforceInterface(IApplicationThread.descriptor);
            ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(data);
            CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
            int backupMode = data.readInt();
            scheduleCreateBackupAgent(appInfo, compatInfo, backupMode);//执行ActivityThread.scheduleCreateBackupAgent
            return true;
        }
    }

(5)ActivityThread.scheduleCreateBackupAgent

代码路径:
frameworks/base/core/java/android/app/ActivityThread

        public final void scheduleCreateBackupAgent(ApplicationInfo app,
                CompatibilityInfo compatInfo, int backupMode) {
            CreateBackupAgentData d = new CreateBackupAgentData();
            d.appInfo = app;
            d.compatInfo = compatInfo;
            d.backupMode = backupMode;

            sendMessage(H.CREATE_BACKUP_AGENT, d);
        }
        
        ActivityThread.H.handleMessage(what=CREATE_BACKUP_AGENT) --> ActivityThread.handleCreateBackupAgent
        
    private void handleCreateBackupAgent(CreateBackupAgentData data) {
        ······
        String classname = data.appInfo.backupAgentName;
        // full backup operation but no app-supplied agent?  use the default implementation
        if (classname == null && (data.backupMode == IApplicationThread.BACKUP_MODE_FULL
                || data.backupMode == IApplicationThread.BACKUP_MODE_RESTORE_FULL)) {
            classname = "android.app.backup.FullBackupAgent";//默认Agent类
        }

        try {
            IBinder binder = null;
            BackupAgent agent = mBackupAgents.get(packageName);
            if (agent != null) {
                ······
                binder = agent.onBind();
            } else {
                try {

                    java.lang.ClassLoader cl = packageInfo.getClassLoader();
                    agent = (BackupAgent) cl.loadClass(classname).newInstance();

                    // set up the agent's context
                    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                    context.setOuterContext(agent);
                    agent.attach(context);

                    agent.onCreate();
                    binder = agent.onBind();//获取agent的binder对象
                    mBackupAgents.put(packageName, agent);
                } catch (Exception e) {
                    
                }
            }

            // tell the OS that we're live now
            try {
                ActivityManagerNative.getDefault().backupAgentCreated(packageName, binder);//调用AMS.backupAgentCreated
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            throw new RuntimeException("Unable to create BackupAgent "
                    + classname + ": " + e.toString(), e);
        }
    }
    
    跨进程调入app内部,再从app内部跨进程告知Ams,并带上binder对象

(6)ActivityManagerService.backupAgentCreated

    public void backupAgentCreated(String agentPackageName, IBinder agent) {
        ······
        try {
            IBackupManager bm = IBackupManager.Stub.asInterface(
                    ServiceManager.getService(Context.BACKUP_SERVICE));
            bm.agentConnected(agentPackageName, agent);//调进BackupManagerService.agentConnected
        } catch (RemoteException e) {
            
        } catch (Exception e) {
            
        } finally {
            
        }
    }

(7)Trampoline.agentConnected-->BackupManagerService.agentConnected

    public void agentConnected(String packageName, IBinder agentBinder) {
        synchronized(mAgentConnectLock) {
            if (Binder.getCallingUid() == Process.SYSTEM_UID) {
                IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
                mConnectedAgent = agent;//终于见到本尊的初始化了
                mConnecting = false;
            } else {
                Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
                        + " claiming agent connected");
            }
            mAgentConnectLock.notifyAll();//唤醒对应的线程,可见(2)
        }
    }
    
    至此,mConnectedAgent的对象已知,为BackupAgent

(c)BackupAgent.BackupServiceBinder.doFullBackup

BackupAgent.BackupServiceBinder.doFullBackup
        public void doFullBackup(ParcelFileDescriptor data,
                int token, IBackupManager callbackBinder) {
            ······
            try {
                BackupAgent.this.onFullBackup(new FullBackupDataOutput(data));
            } catch (IOException ex) {
                
            } catch (RuntimeException ex) {
                
            } finally {
                
            }
        }
        
BackupAgent.onFullBackup
            public void onFullBackup(FullBackupDataOutput data) throws IOException {
        //这里涉及app的用户数据备份,例如:sp、db
        //最关键的applyXmlFiltersAndDoFullBackupForDomain
        //fullBackupFileTree-->FullBackup.backupToTar
    }

8)重点解读:FullBackup.backupToTar

代码路径:
frameworks/base/core/java/android/app/backup/FullBackup.java
frameworks/base/core/jni/android_app_backup_FullBackup.cpp
frameworks/base/libs/androidfw/BackupHelpers.cpp

FullBackup.java
static public native int backupToTar(String packageName, String domain,
            String linkdomain, String rootpath, String path, FullBackupDataOutput output);

android_app_backup_FullBackup.cpp
static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
        jstring domainObj, jstring linkdomain,
        jstring rootpathObj, jstring pathObj, jobject dataOutputObj) {
    ······
    jint err = write_tarfile(packageName, domain, rootpath, path, &tarSize, writer);
    if (!err) {
        //ALOGI("measured [%s] at %lld", path.string(), (long long) tarSize);
        env->CallVoidMethod(dataOutputObj, sFullBackupDataOutput.addSize, (jlong) tarSize);
    }

    return err;
}

BackupHelpers.cpp
int write_tarfile(const String8& packageName, const String8& domain,
        const String8& rootpath, const String8& filepath, off_t* outSize,
        BackupDataWriter* writer)
{
    //可以自行查看代码
    ········
}

c)简化流程

1)备份业务:
BackupManagerService.fullBackup
|
|
|/
BackupRestoreConfirmation
(调用BackupManagerService.acknowledgeFullBackupOrRestore区分点FULL_BACKUP_INTENT_ACTION)
|
|
|/
BackupManagerService
    MSG_RUN_ADB_BACKUP (BackupHandler)
       PerformAdbBackupTask (FullBackupParams)
          run 调用如下1-BackupManagerService
|
|
|/
1-BackupManagerService
    FullBackupEngine
        FullBackupRunner
           writeApkToBackup//备份app
           mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);//备份app涉及的数据
关键点:
FullBackup.backupToTar

2)恢复业务:
BackupManagerService.fullRestore
|
|
|/
BackupRestoreConfirmation
(调用BackupManagerService.acknowledgeFullBackupOrRestore区分点FULL_RESTORE_INTENT_ACTION)
|
|
|/
BackupManagerService
    MSG_RUN_ADB_RESTORE  (BackupHandler)
        PerformAdbRestoreTask (FullRestoreParams)
            run
               restoreOneFile
                   installApk

3)访问的权限要求
android.permission.BACKUP --- signature|privileged

亮点解读
1.怎么实现跨进程等待?
案例1): 调用接口fullBackup,需要等待用户确认

等待过程:
    public final AtomicBoolean latch;
    
    void waitForCompletion(FullParams params) {
        synchronized (params.latch) {
            while (params.latch.get() == false) {
                try {
                    params.latch.wait();
                } catch (InterruptedException e) { /* never interrupted */ }
            }
        }
    }

确认过程(确认后,等待的wait自动退出)
方案1)
    void signalFullBackupRestoreCompletion(FullParams params) {
        synchronized (params.latch) {
            params.latch.set(true);
            params.latch.notifyAll();
        }
    }
    
方案2)
    final AtomicBoolean mLatch;

    synchronized (mLatch) {
        mLatch.set(true);
        mLatch.notifyAll();
    }

总结:
对象的wait和notifyAll方法使用

案例2):
备份app数据需要启动Agent,等待确认

等待过程:
    IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) {
       
        synchronized(mAgentConnectLock) {
            try {
                if (mActivityManager.bindBackupAgent(app.packageName, mode,
                        UserHandle.USER_OWNER)) {
                    
                    long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
                    while (mConnecting && mConnectedAgent == null
                            && (System.currentTimeMillis() < timeoutMark)) {
                        try {
                            mAgentConnectLock.wait(5000);
                        } catch (InterruptedException e) {
                            
                        }
                    }
                }
            } catch (RemoteException e) {
                // can't happen - ActivityManager is local
            }
        }
    }
    
确认过程
    public void agentConnected(String packageName, IBinder agentBinder) {
        synchronized(mAgentConnectLock) {
            ·····
            mAgentConnectLock.notifyAll();
        }
    }
    
总结
对象的wait和notifyAll方法使用

2.app的用户数据怎么被打包到指定文件?

采用管道,因为父子进程(fork)共享内存拷贝
ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();
[0] 读
[1] 写

参考学习:
https://www.jianshu.com/p/c2a8987e1c0d
https://www.jianshu.com/p/115cf0e519c2

问题记录:

aAsset path /data/cache/backup_stage/**.apk is neither a directory nor file (type=0).

参考学习

https://www.52pojie.cn/forum.php?mod=viewthread&tid=1060641
https://github.com/IzZzI/BackUpDemo
https://bbs.125.la/thread-14425656-1-1.html?goto=lastpost
https://blog.csdn.net/self_study/article/details/58587412
https://blog.csdn.net/u013334392/article/details/81392097
https://www.jianshu.com/p/c2a8987e1c0d
https://www.jianshu.com/p/115cf0e519c2
http://www.bubuko.com/infodetail-1890598.html
https://www.cnblogs.com/lipeineng/p/6237681.html

你可能感兴趣的:(Android之备份服务(Bacackupanagerervice))