am 487529a: First baby steps towards settings backup
Merge commit '487529a70cd1479ae8d6bbfb356be7e72542c185' * commit '487529a70cd1479ae8d6bbfb356be7e72542c185': First baby steps towards settings backup
This commit is contained in:
committed by
The Android Open Source Project
commit
f8997690da
@@ -70,6 +70,8 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/ITransientNotification.aidl \
|
||||
core/java/android/app/IWallpaperService.aidl \
|
||||
core/java/android/app/IWallpaperServiceCallback.aidl \
|
||||
core/java/android/backup/IBackupManager.aidl \
|
||||
core/java/android/backup/IBackupService.aidl \
|
||||
core/java/android/bluetooth/IBluetoothA2dp.aidl \
|
||||
core/java/android/bluetooth/IBluetoothDevice.aidl \
|
||||
core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \
|
||||
@@ -105,6 +107,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/com/android/internal/app/IUsageStats.aidl \
|
||||
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
|
||||
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
|
||||
core/java/com/android/internal/backup/IBackupTransport.aidl \
|
||||
core/java/com/android/internal/os/IResultReceiver.aidl \
|
||||
core/java/com/android/internal/view/IInputContext.aidl \
|
||||
core/java/com/android/internal/view/IInputContextCallback.aidl \
|
||||
|
||||
@@ -23953,6 +23953,82 @@
|
||||
</field>
|
||||
</class>
|
||||
</package>
|
||||
<package name="android.backup"
|
||||
>
|
||||
<class name="BackupService"
|
||||
extends="android.app.Service"
|
||||
abstract="true"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<constructor name="BackupService"
|
||||
type="android.backup.BackupService"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</constructor>
|
||||
<method name="onBackup"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="oldStateFd" type="int">
|
||||
</parameter>
|
||||
<parameter name="dataFd" type="int">
|
||||
</parameter>
|
||||
<parameter name="newStateFd" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onBind"
|
||||
return="android.os.IBinder"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="intent" type="android.content.Intent">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="onRestore"
|
||||
return="void"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="dataFd" type="int">
|
||||
</parameter>
|
||||
<parameter name="newStateFd" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<field name="SERVICE_ACTION"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""android.service.action.BACKUP""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</class>
|
||||
</package>
|
||||
<package name="android.content"
|
||||
>
|
||||
<class name="ActivityNotFoundException"
|
||||
@@ -27117,6 +27193,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="BACKUP_SERVICE"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""backup""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="BIND_AUTO_CREATE"
|
||||
type="int"
|
||||
transient="false"
|
||||
|
||||
106
core/java/android/backup/BackupService.java
Normal file
106
core/java/android/backup/BackupService.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 android.backup;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.app.Service;
|
||||
import android.backup.IBackupService;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This is the central interface between an application and Android's
|
||||
* settings backup mechanism.
|
||||
*
|
||||
* <p><em>Not hidden but API subject to change and should not be published</em>
|
||||
*/
|
||||
|
||||
public abstract class BackupService extends Service {
|
||||
/**
|
||||
* Service Action: Participate in the backup infrastructure. Applications
|
||||
* that wish to use the Android backup mechanism must provide an exported
|
||||
* subclass of BackupService and give it an {@link android.content.IntentFilter
|
||||
* IntentFilter} that accepts this action.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SERVICE_ACTION = "android.service.action.BACKUP";
|
||||
|
||||
/**
|
||||
* The application is being asked to write any data changed since the
|
||||
* last time it performed a backup operation. The state data recorded
|
||||
* during the last backup pass is provided in the oldStateFd file descriptor.
|
||||
* If oldStateFd is negative, no old state is available and the application
|
||||
* should perform a full backup. In both cases, a representation of the
|
||||
* final backup state after this pass should be written to the file pointed
|
||||
* to by the newStateFd file descriptor.
|
||||
*
|
||||
* @param oldStateFd An open, read-only file descriptor pointing to the last
|
||||
* backup state provided by the application. May be negative,
|
||||
* in which case no prior state is being provided and the
|
||||
* application should perform a full backup.
|
||||
* @param dataFd An open, read/write file descriptor pointing to the backup data
|
||||
* destination. Typically the application will use backup helper
|
||||
* classes to write to this file.
|
||||
* @param newStateFd An open, read/write file descriptor pointing to an empty
|
||||
* file. The application should record the final backup state
|
||||
* here after writing the requested data to dataFd.
|
||||
*/
|
||||
public abstract void onBackup(int oldStateFd, int dataFd, int newStateFd);
|
||||
|
||||
/**
|
||||
* The application is being restored from backup, and should replace any
|
||||
* existing data with the contents of the backup. The backup data is
|
||||
* provided in the file pointed to by the dataFd file descriptor. Once
|
||||
* the restore is finished, the application should write a representation
|
||||
* of the final state to the newStateFd file descriptor,
|
||||
*
|
||||
* @param dataFd An open, read-only file descriptor pointing to a full snapshot
|
||||
* of the application's data.
|
||||
* @param newStateFd An open, read/write file descriptor pointing to an empty
|
||||
* file. The application should record the final backup state
|
||||
* here after restoring its data from dataFd.
|
||||
*/
|
||||
public abstract void onRestore(int dataFd, int newStateFd);
|
||||
|
||||
|
||||
// ----- Core implementation -----
|
||||
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new BackupServiceBinder().asBinder();
|
||||
|
||||
// ----- IBackupService binder interface -----
|
||||
private class BackupServiceBinder extends IBackupService.Stub {
|
||||
public void doBackup(int oldStateFd, int dataFd, int newStateFd)
|
||||
throws RemoteException {
|
||||
// !!! TODO - real implementation; for now just invoke the callbacks directly
|
||||
Log.v("BackupServiceBinder", "doBackup() invoked");
|
||||
BackupService.this.onBackup(oldStateFd, dataFd, newStateFd);
|
||||
}
|
||||
|
||||
public void doRestore(int dataFd, int newStateFd) throws RemoteException {
|
||||
// !!! TODO - real implementation; for now just invoke the callbacks directly
|
||||
Log.v("BackupServiceBinder", "doRestore() invoked");
|
||||
BackupService.this.onRestore(dataFd, newStateFd);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
core/java/android/backup/IBackupManager.aidl
Normal file
32
core/java/android/backup/IBackupManager.aidl
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 android.backup;
|
||||
|
||||
/**
|
||||
* Direct interface to the Backup Manager Service that applications invoke on. The only
|
||||
* operation currently needed is a simple notification that the app has made changes to
|
||||
* data it wishes to back up, so the system should run a backup pass.
|
||||
*
|
||||
* {@hide pending API solidification}
|
||||
*/
|
||||
interface IBackupManager {
|
||||
/**
|
||||
* Tell the system service that the caller has made changes to its
|
||||
* data, and therefore needs to undergo a backup pass.
|
||||
*/
|
||||
oneway void dataChanged();
|
||||
}
|
||||
53
core/java/android/backup/IBackupService.aidl
Normal file
53
core/java/android/backup/IBackupService.aidl
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 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 android.backup;
|
||||
|
||||
/**
|
||||
* Interface presented by applications being asked to participate in the
|
||||
* backup & restore mechanism. End user code does not typically implement
|
||||
* this interface; they subclass BackupService instead.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface IBackupService {
|
||||
/**
|
||||
* Request that the app perform an incremental backup.
|
||||
*
|
||||
* @param oldStateFd Read-only file containing the description blob of the
|
||||
* app's data state as of the last backup operation's completion.
|
||||
*
|
||||
* @param dataFd Read-write file, empty when onBackup() is called, that
|
||||
* is the data destination for this backup pass's incrementals.
|
||||
*
|
||||
* @param newStateFd Read-write file, empty when onBackup() is called,
|
||||
* where the new state blob is to be recorded.
|
||||
*/
|
||||
void doBackup(int oldStateFd, int dataFd, int newStateFd);
|
||||
|
||||
/**
|
||||
* Restore an entire data snapshot to the application.
|
||||
*
|
||||
* @param dataFd Read-only file containing the full data snapshot of the
|
||||
* app's backup. This is to be a <i>replacement</i> of the app's
|
||||
* current data, not to be merged into it.
|
||||
*
|
||||
* @param newStateFd Read-write file, empty when onRestore() is called,
|
||||
* that is to be written with the state description that holds after
|
||||
* the restore has been completed.
|
||||
*/
|
||||
void doRestore(int dataFd, int newStateFd);
|
||||
}
|
||||
@@ -1278,6 +1278,15 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String APPWIDGET_SERVICE = "appwidget";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve an
|
||||
* {@blink android.backup.IBackupManager IBackupManager} for communicating
|
||||
* with the backup mechanism.
|
||||
*
|
||||
* @see #getSystemService
|
||||
*/
|
||||
public static final String BACKUP_SERVICE = "backup";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
21
core/java/com/android/internal/backup/IBackupTransport.aidl
Normal file
21
core/java/com/android/internal/backup/IBackupTransport.aidl
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.internal.backup;
|
||||
|
||||
/** {@hide} */
|
||||
interface IBackupTransport {
|
||||
}
|
||||
191
services/java/com/android/server/BackupManagerService.java
Normal file
191
services/java/com/android/server/BackupManagerService.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,6 +309,13 @@ class ServerThread extends Thread {
|
||||
Log.e(TAG, "Failure starting HeadsetObserver", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Starting Backup Service");
|
||||
ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "Failure starting Backup Service", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Starting AppWidget Service");
|
||||
appWidget = new AppWidgetService(context);
|
||||
|
||||
Reference in New Issue
Block a user