代码路径

注:Android 7.1源码frameworks/base/core/java/android/app/backupframeworks/base/core/java/com/android/internal/backupframeworks/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.Trampoline1)Trampoline extends IBackupManager.Stub2)    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 是否正常 默认falseb.android.software.backup 是否在/system/etc/**.xml定义c.a和b正常,则可通过命令检查:adb shell dumpsys backup  是否有Inactived.如果是不激活状态,可查具体原因: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.javapublic 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.runPerformAdbBackupTask        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]中读出数据,填充到指定fd2.备份的apk文件路径为:/data/app/***/base.apk3.调用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/ApplicatinThreadNativeApplicationThreadProxy    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.javaframeworks/base/core/jni/android_app_backup_FullBackup.cppframeworks/base/libs/androidfw/BackupHelpers.cppFullBackup.javastatic public native int backupToTar(String packageName, String domain,            String linkdomain, String rootpath, String path, FullBackupDataOutput output);android_app_backup_FullBackup.cppstatic 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.cppint 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.backupToTar2)恢复业务:BackupManagerService.fullRestore|||/BackupRestoreConfirmation(调用BackupManagerService.acknowledgeFullBackupOrRestore区分点FULL_RESTORE_INTENT_ACTION)|||/BackupManagerService    MSG_RUN_ADB_RESTORE  (BackupHandler)        PerformAdbRestoreTask (FullRestoreParams)            run               restoreOneFile                   installApk3)访问的权限要求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/c2a8987e1c0dhttps://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=1060641https://github.com/IzZzI/BackUpDemohttps://bbs.125.la/thread-14425656-1-1.html?goto=lastposthttps://blog.csdn.net/self_study/article/details/58587412https://blog.csdn.net/u013334392/article/details/81392097https://www.jianshu.com/p/c2a8987e1c0dhttps://www.jianshu.com/p/115cf0e519c2http://www.bubuko.com/infodetail-1890598.htmlhttps://www.cnblogs.com/lipeineng/p/6237681.html

更多相关文章

  1. OpenGL,Android注意事项初始化顺序 NullPointer
  2. Android倒计时器——CountDownTimer
  3. Android(安卓)P WMS初始化过程
  4. SystemUI9.0系统应用图标加载流程
  5. android java代码的启动:app_process
  6. Android(安卓)进程间通信(IPC)
  7. android java代码的启动:app_process
  8. Android百度地图导航的那些坑
  9. Android(安卓)Init Language(安卓初始化语言)

随机推荐

  1. Android 使用内容解析者往短信数据库里插
  2. android工程没有gen路径
  3. 移植Busybox到Android平台
  4. android 上传文件到服务器
  5. android关机充电的奥妙所在(留着以后用)
  6. 【Android】 dialog 设置maxHeight 最大
  7. Android Handler不同界面发送数据
  8. Android_Architecture_HAL--Dynamic Life
  9. Android支持多并发的异步任务框架MultiAs
  10. Android手机开发:获取GPS信息