Merge change 1110 into donut

* changes:
  Track install/removal/update of packages that provide backup services
This commit is contained in:
Android (Google) Code Review
2009-05-06 16:15:21 -07:00
2 changed files with 120 additions and 19 deletions

View File

@@ -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">
* &lt;!-- Use the class "MyBackupService" to perform backups for my app --&gt; * &lt;!-- Use the class "MyBackupService" to perform backups for my app --&gt;

View File

@@ -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 -----