diff options
| author | Christopher Tate <ctate@google.com> | 2009-04-29 14:03:25 -0700 |
|---|---|---|
| committer | Christopher Tate <ctate@google.com> | 2009-04-29 14:49:30 -0700 |
| commit | 487529a70cd1479ae8d6bbfb356be7e72542c185 (patch) | |
| tree | ca19a948a28e9d4eb7b4c9890b006e43b89d7a6d /services/java/com/android/server/BackupManagerService.java | |
| parent | dc67739af90aa31a0b546c14bf1e68e6acbb8375 (diff) | |
First baby steps towards settings backup
This change adds a sketched outline of the backup system architecture, with
all of the major pieces represented other than client-side helpers for
specific types of data. IBackupManager and BackupService are public so that
we can write test apps against SDK-domain symbols from the outset.
What code exists in this change hasn't been tested and may crash. It's the
beginnings of the real implementation but of course is barely begun.
Diffstat (limited to 'services/java/com/android/server/BackupManagerService.java')
| -rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java new file mode 100644 index 000000000000..de14c337d989 --- /dev/null +++ b/services/java/com/android/server/BackupManagerService.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.backup.BackupService; +import android.backup.IBackupService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; +import android.util.SparseArray; + +import android.backup.IBackupManager; + +import java.lang.String; +import java.util.HashSet; +import java.util.List; + +class BackupManagerService extends IBackupManager.Stub { + private static final String TAG = "BackupManagerService"; + private static final boolean DEBUG = true; + + private static final long COLLECTION_INTERVAL = 3 * 60 * 1000; + + private static final int MSG_RUN_BACKUP = 1; + + private Context mContext; + private PackageManager mPackageManager; + private final BackupHandler mBackupHandler = new BackupHandler(); + // map UIDs to the set of backup client services within that UID's app set + private SparseArray<HashSet<ServiceInfo>> mBackupParticipants + = new SparseArray<HashSet<ServiceInfo>>(); + // set of backup services that have pending changes + private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>(); + private final Object mQueueLock = new Object(); + + + // ----- Handler that runs the actual backup process asynchronously ----- + + private class BackupHandler extends Handler implements ServiceConnection { + private volatile Object mBindSignaller = new Object(); + private volatile boolean mBinding = false; + private IBackupService mTargetService = null; + + public void handleMessage(Message msg) { + + switch (msg.what) { + case MSG_RUN_BACKUP: + { + // snapshot the pending-backup set and work on that + HashSet<ServiceInfo> queue; + synchronized (mQueueLock) { + queue = mPendingBackups; + mPendingBackups = new HashSet<ServiceInfo>(); + // !!! TODO: start a new backup-queue journal file too + } + + // Walk the set of pending backups, setting up the relevant files and + // invoking the backup service in each participant + Intent backupIntent = new Intent(BackupService.SERVICE_ACTION); + for (ServiceInfo service : queue) { + mBinding = true; + mTargetService = null; + + backupIntent.setClassName(service.packageName, service.name); + Log.d(TAG, "binding to " + backupIntent); + if (mContext.bindService(backupIntent, this, 0)) { + synchronized (mBindSignaller) { + while (mTargetService == null && mBinding == true) { + try { + mBindSignaller.wait(); + } catch (InterruptedException e) { + } + } + } + if (mTargetService != null) { + try { + Log.d(TAG, "invoking doBackup() on " + backupIntent); + // !!! TODO: set up files + mTargetService.doBackup(-1, -1, -1); + } catch (RemoteException e) { + Log.d(TAG, "Remote target " + backupIntent + + " threw during backup:"); + e.printStackTrace(); + } + mContext.unbindService(this); + } + } else { + Log.d(TAG, "Unable to bind to " + backupIntent); + } + } + } + break; + } + } + + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mBindSignaller) { + mTargetService = IBackupService.Stub.asInterface(service); + mBinding = false; + mBindSignaller.notifyAll(); + } + } + + public void onServiceDisconnected(ComponentName name) { + synchronized (mBindSignaller) { + mTargetService = null; + mBinding = false; + mBindSignaller.notifyAll(); + } + } + } + + public BackupManagerService(Context context) { + mContext = context; + mPackageManager = context.getPackageManager(); + + // Identify the backup participants + // !!! TODO: also watch package-install to keep this up to date + List<ResolveInfo> services = mPackageManager.queryIntentServices( + new Intent(BackupService.SERVICE_ACTION), 0); + if (DEBUG) { + Log.v(TAG, "Backup participants: " + services.size()); + for (ResolveInfo ri : services) { + Log.v(TAG, " " + ri + " : " + ri.filter); + } + } + + // Build our mapping of uid to backup client services + for (ResolveInfo ri : services) { + int uid = ri.serviceInfo.applicationInfo.uid; + HashSet<ServiceInfo> set = mBackupParticipants.get(uid); + if (set == null) { + set = new HashSet<ServiceInfo>(); + mBackupParticipants.put(uid, set); + } + set.add(ri.serviceInfo); + } + } + + + // ----- IBackupManager binder interface ----- + + public void dataChanged() throws RemoteException { + // Record that we need a backup pass for the caller. Since multiple callers + // may share a uid, we need to note all candidates within that uid and schedule + // a backup pass for each of them. + + HashSet<ServiceInfo> targets = mBackupParticipants.get(Binder.getCallingUid()); + if (targets != null) { + synchronized (mQueueLock) { + // Note that this client has made data changes that need to be backed up + // !!! add them to the set of pending packages + for (ServiceInfo service : targets) { + if (mPendingBackups.add(service)) { + // !!! TODO: write to the pending-backup journal file in case of crash + } + } + + // Schedule a backup pass in a few minutes. As backup-eligible data + // keeps changing, continue to defer the backup pass until things + // settle down, to avoid extra overhead. + mBackupHandler.removeMessages(MSG_RUN_BACKUP); + mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL); + } + } + } +} |
