美文网首页Android进化
Android之备份服务(Bacackupanagerervic

Android之备份服务(Bacackupanagerervic

作者: 锄禾豆 | 来源:发表于2021-05-13 21:37 被阅读0次

    代码路径

    注:
    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.
         *
         * <p>This method is <i>synchronous</i> -- it does not return until the backup has
         * completed.
         *
         * <p>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 <code>true</code>, the resulting tar stream will include the
         *     application .apk files themselves as well as their data.
         * @param includeObbs If <code>true</code>, the resulting tar stream will include any
         *     application expansion (OBB) files themselves belonging to each application.
         * @param includeShared If <code>true</code>, the resulting tar stream will include
         *     the contents of the device's shared storage (SD card or equivalent).
         * @param allApps If <code>true</code>, the resulting tar stream will include all
         *     installed applications' data, not just those named in the <code>packageNames</code>
         *     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 <code>allApps</code> 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<PackageInfo> backupQueue =
                        new ArrayList<PackageInfo>(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之备份服务(Bacackupanagerervic

        本文链接:https://www.haomeiwen.com/subject/tfaxjltx.html