Merge "Fix incorrect @hide usage in libcore"
diff --git a/api/system-current.txt b/api/system-current.txt
index 2b34895..e723d099 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6293,6 +6293,7 @@
method public static void dataChanged(java.lang.String);
method public long getAvailableRestoreToken(java.lang.String);
method public java.lang.String getCurrentTransport();
+ method public boolean isAppEligibleForBackup(java.lang.String);
method public boolean isBackupEnabled();
method public java.lang.String[] listAllTransports();
method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
@@ -6342,6 +6343,7 @@
method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor);
method public int getRestoreData(android.os.ParcelFileDescriptor);
method public int initializeDevice();
+ method public boolean isAppEligibleForBackup(android.content.pm.PackageInfo, boolean);
method public java.lang.String name();
method public android.app.backup.RestoreDescription nextRestorePackage();
method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int);
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 193a0b2c..c27eaa4f 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -426,6 +426,29 @@
}
/**
+ * Ask the framework whether this app is eligible for backup.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @param packageName The name of the package.
+ * @return Whether this app is eligible for backup.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isAppEligibleForBackup(String packageName) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ return sService.isAppEligibleForBackup(packageName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
+ }
+ }
+ return false;
+ }
+
+ /**
* Request an immediate backup, providing an observer to which results of the backup operation
* will be published. The Android backup system will decide for each package whether it will
* be full app data backup or key/value-pair-based backup.
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 4363604..aca115f 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -482,6 +482,18 @@
"Transport cancelFullBackup() not implemented");
}
+ /**
+ * Ask the transport whether this app is eligible for backup.
+ *
+ * @param targetPackage The identity of the application.
+ * @param isFullBackup If set, transport should check if app is eligible for full data backup,
+ * otherwise to check if eligible for key-value backup.
+ * @return Whether this app is eligible for backup.
+ */
+ public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup) {
+ return true;
+ }
+
// ------------------------------------------------------------------------------------
// Full restore interfaces
@@ -659,6 +671,12 @@
}
@Override
+ public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup)
+ throws RemoteException {
+ return BackupTransport.this.isAppEligibleForBackup(targetPackage, isFullBackup);
+ }
+
+ @Override
public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
return BackupTransport.this.getNextFullRestoreDataChunk(socket);
}
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 2a1c00f..5d4cc6f 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -329,6 +329,16 @@
long getAvailableRestoreToken(String packageName);
/**
+ * Ask the framework whether this app is eligible for backup.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @param packageName The name of the package.
+ * @return Whether this app is eligible for backup.
+ */
+ boolean isAppEligibleForBackup(String packageName);
+
+ /**
* Request an immediate backup, providing an observer to which results of the backup operation
* will be published. The Android backup system will decide for each package whether it will
* be full app data backup or key/value-pair-based backup.
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index b1fc20d..444dbfa 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -239,6 +239,16 @@
int sendBackupData(int numBytes);
void cancelFullBackup();
+ /**
+ * Ask the transport whether this app is eligible for backup.
+ *
+ * @param targetPackage The identity of the application.
+ * @param isFullBackup If set, transport should check if app is eligible for full data backup,
+ * otherwise to check if eligible for key-value backup.
+ * @return Whether this app is eligible for backup.
+ */
+ boolean isAppEligibleForBackup(in PackageInfo targetPackage, boolean isFullBackup);
+
// full restore stuff
/**
@@ -286,5 +296,4 @@
* operation will immediately be finished with no further attempts to restore app data.
*/
int abortFullRestore();
-
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 234c94e..d63dd0c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -676,8 +676,13 @@
return true;
}
+ // Checks if the app is in a stopped state, that means it won't receive broadcasts.
+ private static boolean appIsStopped(ApplicationInfo app) {
+ return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
+ }
+
/* does *not* check overall backup eligibility policy! */
- public static boolean appGetsFullBackup(PackageInfo pkg) {
+ private static boolean appGetsFullBackup(PackageInfo pkg) {
if (pkg.applicationInfo.backupAgentName != null) {
// If it has an agent, it gets full backups only if it says so
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
@@ -2758,7 +2763,7 @@
return;
}
- if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+ if (appIsStopped(mCurrentPackage.applicationInfo)) {
// The app has been force-stopped or cleared or just installed,
// and not yet launched out of that state, so just as it won't
// receive broadcasts, we won't run it for backup.
@@ -4179,28 +4184,18 @@
try {
PackageInfo info = mPackageManager.getPackageInfo(pkg,
PackageManager.GET_SIGNATURES);
- if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
- || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
+ if (!appIsEligibleForBackup(info.applicationInfo)) {
// Cull any packages that have indicated that backups are not permitted,
+ // that run as system-domain uids but do not define their own backup agents,
// as well as any explicit mention of the 'special' shared-storage agent
// package (we handle that one at the end).
if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring opted-out package " + pkg);
+ Slog.d(TAG, "Ignoring not eligible package " + pkg);
}
sendBackupOnResult(mBackupObserver, pkg,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
- } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
- && (info.applicationInfo.backupAgentName == null)) {
- // Cull any packages that run as system-domain uids but do not define their
- // own backup agents
- if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring non-agent system package " + pkg);
- }
- sendBackupOnResult(mBackupObserver, pkg,
- BackupManager.ERROR_BACKUP_NOT_ALLOWED);
- continue;
- } else if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+ } else if (appIsStopped(info.applicationInfo)) {
// Cull any packages in the 'stopped' state: they've either just been
// installed or have explicitly been force-stopped by the user. In both
// cases we do not want to launch them for backup.
@@ -9538,6 +9533,32 @@
}
}
+ public boolean isAppEligibleForBackup(String packageName) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "isAppEligibleForBackup");
+ try {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_SIGNATURES);
+ if (!appIsEligibleForBackup(packageInfo.applicationInfo) ||
+ appIsStopped(packageInfo.applicationInfo)) {
+ return false;
+ }
+ IBackupTransport transport = getTransport(mCurrentTransport);
+ if (transport != null) {
+ try {
+ return transport.isAppEligibleForBackup(packageInfo,
+ appGetsFullBackup(packageInfo));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to contact transport");
+ }
+ }
+ // If transport is not present we couldn't tell that the package is not eligible.
+ return true;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
// ----- Restore session -----
class ActiveRestoreSession extends IRestoreSession.Stub {
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 505a1a5..bbf881b 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -326,6 +326,12 @@
}
@Override
+ public boolean isAppEligibleForBackup(String packageName) {
+ BackupManagerService svc = mService;
+ return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false;
+ }
+
+ @Override
public int requestBackup(String[] packages, IBackupObserver observer) throws RemoteException {
BackupManagerService svc = mService;
return (svc != null) ? svc.requestBackup(packages, observer) : null;