Merge change 1110 into donut
* changes: Track install/removal/update of packages that provide backup services
This commit is contained in:
@@ -33,7 +33,7 @@ import android.util.Log;
|
|||||||
* In order to use the backup service, your application must implement a
|
* In order to use the backup service, your application must implement a
|
||||||
* subclass of BackupService, and declare an intent filter
|
* subclass of BackupService, and declare an intent filter
|
||||||
* in the application manifest specifying that your BackupService subclass
|
* in the application manifest specifying that your BackupService subclass
|
||||||
* handles the {link #SERVICE_ACTION} intent action. For example:
|
* handles the {@link BackupService#SERVICE_ACTION} intent action. For example:
|
||||||
*
|
*
|
||||||
* <pre class="prettyprint">
|
* <pre class="prettyprint">
|
||||||
* <!-- Use the class "MyBackupService" to perform backups for my app -->
|
* <!-- Use the class "MyBackupService" to perform backups for my app -->
|
||||||
|
|||||||
@@ -18,14 +18,18 @@ package com.android.server;
|
|||||||
|
|
||||||
import android.backup.BackupService;
|
import android.backup.BackupService;
|
||||||
import android.backup.IBackupService;
|
import android.backup.IBackupService;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -207,29 +211,126 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
mStateDir.mkdirs();
|
mStateDir.mkdirs();
|
||||||
mDataDir = Environment.getDownloadCacheDirectory();
|
mDataDir = Environment.getDownloadCacheDirectory();
|
||||||
|
|
||||||
// Identify the backup participants
|
// Build our mapping of uid to backup client services
|
||||||
// !!! TODO: also watch package-install to keep this up to date
|
synchronized (mBackupParticipants) {
|
||||||
List<ResolveInfo> services = mPackageManager.queryIntentServices(
|
addPackageParticipantsLocked(null);
|
||||||
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
|
// Register for broadcasts about package install, etc., so we can
|
||||||
for (ResolveInfo ri : services) {
|
// update the provider list.
|
||||||
int uid = ri.serviceInfo.applicationInfo.uid;
|
IntentFilter filter = new IntentFilter();
|
||||||
HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
|
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||||
if (set == null) {
|
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||||
set = new HashSet<ServiceInfo>();
|
filter.addDataScheme("package");
|
||||||
mBackupParticipants.put(uid, set);
|
mContext.registerReceiver(mBroadcastReceiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Track installation/removal of packages -----
|
||||||
|
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (DEBUG) Log.d(TAG, "Received broadcast " + intent);
|
||||||
|
|
||||||
|
Uri uri = intent.getData();
|
||||||
|
if (uri == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String pkgName = uri.getSchemeSpecificPart();
|
||||||
|
if (pkgName == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
|
||||||
|
synchronized (mBackupParticipants) {
|
||||||
|
Bundle extras = intent.getExtras();
|
||||||
|
if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
|
||||||
|
// The package was just upgraded
|
||||||
|
updatePackageParticipantsLocked(pkgName);
|
||||||
|
} else {
|
||||||
|
// The package was just added
|
||||||
|
addPackageParticipantsLocked(pkgName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
|
||||||
|
Bundle extras = intent.getExtras();
|
||||||
|
if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
|
||||||
|
// The package is being updated. We'll receive a PACKAGE_ADDED shortly.
|
||||||
|
} else {
|
||||||
|
synchronized (mBackupParticipants) {
|
||||||
|
removePackageParticipantsLocked(pkgName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the backup services in the given package to our set of known backup participants.
|
||||||
|
// If 'packageName' is null, adds all backup services in the system.
|
||||||
|
void addPackageParticipantsLocked(String packageName) {
|
||||||
|
List<ResolveInfo> services = mPackageManager.queryIntentServices(
|
||||||
|
new Intent(BackupService.SERVICE_ACTION), 0);
|
||||||
|
addPackageParticipantsLockedInner(packageName, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPackageParticipantsLockedInner(String packageName, List<ResolveInfo> services) {
|
||||||
|
for (ResolveInfo ri : services) {
|
||||||
|
if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
|
||||||
|
int uid = ri.serviceInfo.applicationInfo.uid;
|
||||||
|
HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
|
||||||
|
if (set == null) {
|
||||||
|
set = new HashSet<ServiceInfo>();
|
||||||
|
mBackupParticipants.put(uid, set);
|
||||||
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.v(TAG, "Adding " + services.size() + " backup participants:");
|
||||||
|
for (ResolveInfo svc : services) {
|
||||||
|
Log.v(TAG, " " + svc + " : " + svc.filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set.add(ri.serviceInfo);
|
||||||
}
|
}
|
||||||
set.add(ri.serviceInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the given package's backup services from our known active set. If
|
||||||
|
// 'packageName' is null, *all* backup services will be removed.
|
||||||
|
void removePackageParticipantsLocked(String packageName) {
|
||||||
|
List<ResolveInfo> services = mPackageManager.queryIntentServices(
|
||||||
|
new Intent(BackupService.SERVICE_ACTION), 0);
|
||||||
|
removePackageParticipantsLockedInner(packageName, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removePackageParticipantsLockedInner(String packageName, List<ResolveInfo> services) {
|
||||||
|
for (ResolveInfo ri : services) {
|
||||||
|
if (packageName == null || ri.serviceInfo.packageName.equals(packageName)) {
|
||||||
|
int uid = ri.serviceInfo.applicationInfo.uid;
|
||||||
|
HashSet<ServiceInfo> set = mBackupParticipants.get(uid);
|
||||||
|
if (set != null) {
|
||||||
|
set.remove(ri.serviceInfo);
|
||||||
|
if (set.size() == 0) {
|
||||||
|
mBackupParticipants.put(uid, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the given package's known backup participants. Unlike add/remove, the update
|
||||||
|
// action cannot be passed a null package name.
|
||||||
|
void updatePackageParticipantsLocked(String packageName) {
|
||||||
|
if (packageName == null) {
|
||||||
|
Log.e(TAG, "updatePackageParticipants called with null package name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force but small code size
|
||||||
|
List<ResolveInfo> services = mPackageManager.queryIntentServices(
|
||||||
|
new Intent(BackupService.SERVICE_ACTION), 0);
|
||||||
|
removePackageParticipantsLockedInner(packageName, services);
|
||||||
|
addPackageParticipantsLockedInner(packageName, services);
|
||||||
|
}
|
||||||
|
|
||||||
// ----- IBackupManager binder interface -----
|
// ----- IBackupManager binder interface -----
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user