Add backup logging to WallpaperBackupAgent
Bug: 268471749
Test: atest WallpaperEventLoggerTest WallpaperBackupAgentTest
Change-Id: I9e040383e64adc76cc308450c9c112c8dd5dbe32
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index d142f25..8acc508 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -42,7 +42,7 @@
srcs: [
// Include the app source code because the app runs as the system user on-device.
"src/**/*.java",
- "test/src/**/*.java"
+ "test/src/**/*.java",
],
libs: [
"android.test.base",
@@ -54,7 +54,8 @@
"mockito-target-minus-junit4",
"truth-prebuilt",
],
+ resource_dirs: ["test/res"],
certificate: "platform",
platform_apis: true,
- test_suites: ["device-tests"]
+ test_suites: ["device-tests"],
}
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index e549b61..6aca2fd 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -19,11 +19,18 @@
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_INELIGIBLE;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_NO_METADATA;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_NO_WALLPAPER;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_QUOTA_EXCEEDED;
+
import android.app.AppGlobals;
import android.app.WallpaperManager;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupRestoreEventLogger.BackupRestoreError;
import android.app.backup.FullBackupDataOutput;
import android.content.ComponentName;
import android.content.Context;
@@ -103,6 +110,10 @@
private boolean mQuotaExceeded;
private WallpaperManager mWallpaperManager;
+ private WallpaperEventLogger mEventLogger;
+
+ private boolean mSystemHasLiveComponent;
+ private boolean mLockHasLiveComponent;
@Override
public void onCreate() {
@@ -117,6 +128,9 @@
if (DEBUG) {
Slog.v(TAG, "quota file " + mQuotaFile.getPath() + " exists=" + mQuotaExceeded);
}
+
+ BackupManager backupManager = new BackupManager(getApplicationContext());
+ mEventLogger = new WallpaperEventLogger(backupManager, /* wallpaperAgent */ this);
}
@Override
@@ -149,11 +163,18 @@
Slog.v(TAG, "lockGen=" + lockGeneration + " : lockChanged=" + lockChanged);
}
+ // Due to the way image vs live wallpaper backup logic is intermingled, for logging
+ // purposes first check if we have live components for each wallpaper to avoid
+ // over-reporting errors.
+ mSystemHasLiveComponent = mWallpaperManager.getWallpaperInfo(FLAG_SYSTEM) != null;
+ mLockHasLiveComponent = mWallpaperManager.getWallpaperInfo(FLAG_LOCK) != null;
+
backupWallpaperInfoFile(/* sysOrLockChanged= */ sysChanged || lockChanged, data);
backupSystemWallpaperFile(sharedPrefs, sysChanged, sysGeneration, data);
backupLockWallpaperFileIfItExists(sharedPrefs, lockChanged, lockGeneration, data);
} catch (Exception e) {
Slog.e(TAG, "Unable to back up wallpaper", e);
+ mEventLogger.onBackupException(e);
} finally {
// Even if this time we had to back off on attempting to store the lock image
// due to exceeding the data quota, try again next time. This will alternate
@@ -170,6 +191,14 @@
if (wallpaperInfoFd == null) {
Slog.w(TAG, "Wallpaper metadata file doesn't exist");
+ // If we have live components, getting the file to back up somehow failed, so log it
+ // as an error.
+ if (mSystemHasLiveComponent) {
+ mEventLogger.onSystemLiveWallpaperBackupFailed(ERROR_NO_METADATA);
+ }
+ if (mLockHasLiveComponent) {
+ mEventLogger.onLockLiveWallpaperBackupFailed(ERROR_NO_METADATA);
+ }
return;
}
@@ -182,12 +211,22 @@
if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
backupFile(infoStage, data);
+
+ // We've backed up the info file which contains the live component, so log it as success
+ if (mSystemHasLiveComponent) {
+ mEventLogger.onSystemLiveWallpaperBackedUp(
+ mWallpaperManager.getWallpaperInfo(FLAG_SYSTEM));
+ }
+ if (mLockHasLiveComponent) {
+ mEventLogger.onLockLiveWallpaperBackedUp(mWallpaperManager.getWallpaperInfo(FLAG_LOCK));
+ }
}
private void backupSystemWallpaperFile(SharedPreferences sharedPrefs,
boolean sysChanged, int sysGeneration, FullBackupDataOutput data) throws IOException {
if (!mWallpaperManager.isWallpaperBackupEligible(FLAG_SYSTEM)) {
Slog.d(TAG, "System wallpaper ineligible for backup");
+ logSystemImageErrorIfNoLiveComponent(ERROR_INELIGIBLE);
return;
}
@@ -197,6 +236,7 @@
if (systemWallpaperImageFd == null) {
Slog.w(TAG, "System wallpaper doesn't exist");
+ logSystemImageErrorIfNoLiveComponent(ERROR_NO_WALLPAPER);
return;
}
@@ -210,8 +250,17 @@
if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
backupFile(imageStage, data);
sharedPrefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
+ mEventLogger.onSystemImageWallpaperBackedUp();
}
+ private void logSystemImageErrorIfNoLiveComponent(@BackupRestoreError String error) {
+ if (mSystemHasLiveComponent) {
+ return;
+ }
+ mEventLogger.onSystemImageWallpaperBackupFailed(error);
+ }
+
+
private void backupLockWallpaperFileIfItExists(SharedPreferences sharedPrefs,
boolean lockChanged, int lockGeneration, FullBackupDataOutput data) throws IOException {
final File lockImageStage = new File(getFilesDir(), LOCK_WALLPAPER_STAGE);
@@ -224,11 +273,13 @@
}
Slog.d(TAG, "No lockscreen wallpaper set, add nothing to backup");
sharedPrefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
+ logLockImageErrorIfNoLiveComponent(ERROR_NO_WALLPAPER);
return;
}
if (!mWallpaperManager.isWallpaperBackupEligible(FLAG_LOCK)) {
Slog.d(TAG, "Lock screen wallpaper ineligible for backup");
+ logLockImageErrorIfNoLiveComponent(ERROR_INELIGIBLE);
return;
}
@@ -239,11 +290,13 @@
// set, but we can't find it.
if (lockWallpaperFd == null) {
Slog.w(TAG, "Lock wallpaper doesn't exist");
+ logLockImageErrorIfNoLiveComponent(ERROR_NO_WALLPAPER);
return;
}
if (mQuotaExceeded) {
Slog.w(TAG, "Not backing up lock screen wallpaper. Quota was exceeded last time");
+ logLockImageErrorIfNoLiveComponent(ERROR_QUOTA_EXCEEDED);
return;
}
@@ -255,6 +308,14 @@
if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
backupFile(lockImageStage, data);
sharedPrefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
+ mEventLogger.onLockImageWallpaperBackedUp();
+ }
+
+ private void logLockImageErrorIfNoLiveComponent(@BackupRestoreError String error) {
+ if (mLockHasLiveComponent) {
+ return;
+ }
+ mEventLogger.onLockImageWallpaperBackupFailed(error);
}
/**
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperEventLogger.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperEventLogger.java
new file mode 100644
index 0000000..64944b3
--- /dev/null
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperEventLogger.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2023 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.wallpaperbackup;
+
+import android.annotation.Nullable;
+import android.app.WallpaperInfo;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupRestoreEventLogger;
+import android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType;
+import android.app.backup.BackupRestoreEventLogger.BackupRestoreError;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Log backup / restore related events using {@link BackupRestoreEventLogger}.
+ */
+public class WallpaperEventLogger {
+ /* Static image used as system (or home) screen wallpaper */
+ @BackupRestoreDataType
+ @VisibleForTesting
+ static final String WALLPAPER_IMG_SYSTEM = "wlp_img_system";
+
+ /* Static image used as lock screen wallpaper */
+ @BackupRestoreDataType
+ @VisibleForTesting
+ static final String WALLPAPER_IMG_LOCK = "wlp_img_lock";
+
+ /* Live component used as system (or home) screen wallpaper */
+ @BackupRestoreDataType
+ @VisibleForTesting
+ static final String WALLPAPER_LIVE_SYSTEM = "wlp_live_system";
+
+ /* Live component used as lock screen wallpaper */
+ @BackupRestoreDataType
+ @VisibleForTesting
+ static final String WALLPAPER_LIVE_LOCK = "wlp_live_lock";
+
+ @BackupRestoreError
+ static final String ERROR_INELIGIBLE = "ineligible";
+ @BackupRestoreError
+ static final String ERROR_NO_METADATA = "no_metadata";
+ @BackupRestoreError
+ static final String ERROR_NO_WALLPAPER = "no_wallpaper";
+ @BackupRestoreError
+ static final String ERROR_QUOTA_EXCEEDED = "quota_exceeded";
+
+ private final BackupRestoreEventLogger mLogger;
+
+ private final Set<String> mProcessedDataTypes = new HashSet<>();
+
+ WallpaperEventLogger(BackupManager backupManager, WallpaperBackupAgent wallpaperAgent) {
+ mLogger = backupManager.getBackupRestoreEventLogger(/* backupAgent */ wallpaperAgent);
+ }
+
+ void onSystemImageWallpaperBackedUp() {
+ logBackupSuccessInternal(WALLPAPER_IMG_SYSTEM, /* liveComponentWallpaperInfo */ null);
+ }
+
+ void onLockImageWallpaperBackedUp() {
+ logBackupSuccessInternal(WALLPAPER_IMG_LOCK, /* liveComponentWallpaperInfo */ null);
+ }
+
+ void onSystemLiveWallpaperBackedUp(WallpaperInfo wallpaperInfo) {
+ logBackupSuccessInternal(WALLPAPER_LIVE_SYSTEM, wallpaperInfo);
+ }
+
+ void onLockLiveWallpaperBackedUp(WallpaperInfo wallpaperInfo) {
+ logBackupSuccessInternal(WALLPAPER_LIVE_LOCK, wallpaperInfo);
+ }
+
+ void onSystemImageWallpaperBackupFailed(@BackupRestoreError String error) {
+ logBackupFailureInternal(WALLPAPER_IMG_SYSTEM, error);
+ }
+
+ void onLockImageWallpaperBackupFailed(@BackupRestoreError String error) {
+ logBackupFailureInternal(WALLPAPER_IMG_LOCK, error);
+ }
+
+ void onSystemLiveWallpaperBackupFailed(@BackupRestoreError String error) {
+ logBackupFailureInternal(WALLPAPER_LIVE_SYSTEM, error);
+ }
+
+ void onLockLiveWallpaperBackupFailed(@BackupRestoreError String error) {
+ logBackupFailureInternal(WALLPAPER_LIVE_LOCK, error);
+ }
+
+
+ /**
+ * Called when the whole backup flow is interrupted by an exception.
+ */
+ void onBackupException(Exception exception) {
+ String error = exception.getClass().getName();
+ if (!mProcessedDataTypes.contains(WALLPAPER_IMG_SYSTEM) && !mProcessedDataTypes.contains(
+ WALLPAPER_LIVE_SYSTEM)) {
+ mLogger.logItemsBackupFailed(WALLPAPER_IMG_SYSTEM, /* count */ 1, error);
+ }
+ if (!mProcessedDataTypes.contains(WALLPAPER_IMG_LOCK) && !mProcessedDataTypes.contains(
+ WALLPAPER_LIVE_LOCK)) {
+ mLogger.logItemsBackupFailed(WALLPAPER_IMG_LOCK, /* count */ 1, error);
+ }
+ }
+
+ private void logBackupSuccessInternal(@BackupRestoreDataType String which,
+ @Nullable WallpaperInfo liveComponentWallpaperInfo) {
+ mLogger.logItemsBackedUp(which, /* count */ 1);
+ logLiveWallpaperNameIfPresent(which, liveComponentWallpaperInfo);
+ mProcessedDataTypes.add(which);
+ }
+
+ private void logBackupFailureInternal(@BackupRestoreDataType String which,
+ @BackupRestoreError String error) {
+ mLogger.logItemsBackupFailed(which, /* count */ 1, error);
+ mProcessedDataTypes.add(which);
+ }
+
+ private void logLiveWallpaperNameIfPresent(@BackupRestoreDataType String wallpaperType,
+ WallpaperInfo wallpaperInfo) {
+ if (wallpaperInfo != null) {
+ mLogger.logBackupMetadata(wallpaperType, wallpaperInfo.getComponent().getClassName());
+ }
+ }
+}
diff --git a/packages/WallpaperBackup/test/AndroidManifest.xml b/packages/WallpaperBackup/test/AndroidManifest.xml
index 44ab1b6..eb1e98b 100644
--- a/packages/WallpaperBackup/test/AndroidManifest.xml
+++ b/packages/WallpaperBackup/test/AndroidManifest.xml
@@ -4,6 +4,21 @@
<application android:label="WallpaperBackup Tests">
<uses-library android:name="android.test.runner" />
+ <service android:name="com.android.wallpaperbackup.utils.TestWallpaperService"
+ android:enabled="true"
+ android:directBootAware="true"
+ android:label="Test wallpaper"
+ android:permission="android.permission.BIND_WALLPAPER"
+ android:exported="true">
+
+ <intent-filter>
+ <action android:name="android.service.wallpaper.WallpaperService"/>
+ </intent-filter>
+
+ <!-- Link to XML that defines the wallpaper info. -->
+ <meta-data android:name="android.service.wallpaper"
+ android:resource="@xml/livewallpaper"/>
+ </service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/packages/WallpaperBackup/test/res/xml/livewallpaper.xml b/packages/WallpaperBackup/test/res/xml/livewallpaper.xml
new file mode 100644
index 0000000..c6fbe2bda
--- /dev/null
+++ b/packages/WallpaperBackup/test/res/xml/livewallpaper.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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
+ -->
+<wallpaper/>
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index 20dd5165..89459f6 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -23,22 +23,40 @@
import static com.android.wallpaperbackup.WallpaperBackupAgent.LOCK_WALLPAPER_STAGE;
import static com.android.wallpaperbackup.WallpaperBackupAgent.SYSTEM_WALLPAPER_STAGE;
import static com.android.wallpaperbackup.WallpaperBackupAgent.WALLPAPER_INFO_STAGE;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_INELIGIBLE;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_NO_WALLPAPER;
+import static com.android.wallpaperbackup.WallpaperEventLogger.ERROR_QUOTA_EXCEEDED;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_LOCK;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_SYSTEM;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_LOCK;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_SYSTEM;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.WallpaperInfo;
import android.app.WallpaperManager;
+import android.app.backup.BackupAnnotations;
+import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.app.backup.FullBackupDataOutput;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.service.wallpaper.WallpaperService;
+import androidx.test.InstrumentationRegistry;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
@@ -69,12 +87,18 @@
private static final int TEST_SYSTEM_WALLPAPER_ID = 1;
private static final int TEST_LOCK_WALLPAPER_ID = 2;
private static final int NO_LOCK_WALLPAPER_ID = -1;
+ // An arbitrary user.
+ private static final UserHandle USER_HANDLE = new UserHandle(15);
- @Mock private FullBackupDataOutput mOutput;
- @Mock private WallpaperManager mWallpaperManager;
- @Mock private Context mMockContext;
+ @Mock
+ private FullBackupDataOutput mOutput;
+ @Mock
+ private WallpaperManager mWallpaperManager;
+ @Mock
+ private Context mMockContext;
- @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private ContextWithServiceOverrides mContext;
private IsolatedWallpaperBackupAgent mWallpaperBackupAgent;
@@ -90,9 +114,10 @@
mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext());
mContext.injectSystemService(WallpaperManager.class, mWallpaperManager);
- mWallpaperBackupAgent = new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
+ mWallpaperBackupAgent = new IsolatedWallpaperBackupAgent();
mWallpaperBackupAgent.attach(mContext);
- mWallpaperBackupAgent.onCreate();
+ mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
+ BackupAnnotations.OperationType.BACKUP);
mWallpaperComponent = new ComponentName(TEST_WALLPAPER_PACKAGE, "");
}
@@ -388,6 +413,185 @@
verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK));
}
+ @Test
+ public void testOnFullBackup_systemWallpaperImgSuccess_logsSuccess() throws Exception {
+ mockSystemWallpaperFileWithContents("system wallpaper");
+ mockCurrentWallpaperIds(TEST_SYSTEM_WALLPAPER_ID, NO_LOCK_WALLPAPER_ID);
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_SYSTEM,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testOnFullBackup_systemWallpaperImgIneligible_logsFailure() throws Exception {
+ when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(false);
+ mockSystemWallpaperFileWithContents("system wallpaper");
+ mockCurrentWallpaperIds(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_SYSTEM,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(ERROR_INELIGIBLE);
+ }
+
+ @Test
+ public void testOnFullBackup_systemWallpaperImgMissing_logsFailure() throws Exception {
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_SYSTEM,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(ERROR_NO_WALLPAPER);
+ }
+
+ @Test
+ public void testOnFullBackup_systemWallpaperImgMissingButHasLiveComponent_logsLiveSuccess()
+ throws Exception {
+ mockWallpaperInfoFileWithContents("info file");
+ when(mWallpaperManager.getWallpaperInfo(anyInt())).thenReturn(getFakeWallpaperInfo());
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_LIVE_SYSTEM,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
+ assertThat(result.getMetadataHash()).isNotNull();
+ }
+
+ @Test
+ public void testOnFullBackup_systemWallpaperImgMissingButHasLiveComponent_logsNothingForImg()
+ throws Exception {
+ mockWallpaperInfoFileWithContents("info file");
+ when(mWallpaperManager.getWallpaperInfo(anyInt())).thenReturn(getFakeWallpaperInfo());
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_SYSTEM,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void testOnFullBackup_lockWallpaperImgSuccess_logsSuccess() throws Exception {
+ mockLockWallpaperFileWithContents("lock wallpaper");
+ mockCurrentWallpaperIds(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testOnFullBackup_lockWallpaperImgIneligible_logsFailure() throws Exception {
+ when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(false);
+ mockLockWallpaperFileWithContents("lock wallpaper");
+ mockCurrentWallpaperIds(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(ERROR_INELIGIBLE);
+ }
+
+ @Test
+ public void testOnFullBackup_lockWallpaperImgMissing_logsFailure() throws Exception {
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(ERROR_NO_WALLPAPER);
+ }
+
+ @Test
+ public void testOnFullBackup_lockWallpaperImgMissingButHasLiveComponent_logsLiveSuccess()
+ throws Exception {
+ mockWallpaperInfoFileWithContents("info file");
+ when(mWallpaperManager.getWallpaperInfo(anyInt())).thenReturn(getFakeWallpaperInfo());
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_LIVE_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
+ assertThat(result.getMetadataHash()).isNotNull();
+ }
+
+ @Test
+ public void testOnFullBackup_lockWallpaperImgMissingButHasLiveComponent_logsNothingForImg()
+ throws Exception {
+ mockWallpaperInfoFileWithContents("info file");
+ when(mWallpaperManager.getWallpaperInfo(anyInt())).thenReturn(getFakeWallpaperInfo());
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNull();
+ }
+
+
+ @Test
+ public void testOnFullBackup_exceptionThrown_logsException() throws Exception {
+ when(mWallpaperManager.isWallpaperBackupEligible(anyInt())).thenThrow(
+ new RuntimeException());
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(RuntimeException.class.getName());
+ }
+
+ @Test
+ public void testOnFullBackup_lastBackupOverQuota_logsLockFailure() throws Exception {
+ mockSystemWallpaperFileWithContents("system wallpaper");
+ mockLockWallpaperFileWithContents("lock wallpaper");
+ mockCurrentWallpaperIds(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+ markAgentAsOverQuota();
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_LOCK,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getFailCount()).isEqualTo(1);
+ assertThat(result.getErrors()).containsKey(ERROR_QUOTA_EXCEEDED);
+ }
+
+ @Test
+ public void testOnFullBackup_lastBackupOverQuota_logsSystemSuccess() throws Exception {
+ mockSystemWallpaperFileWithContents("system wallpaper");
+ mockLockWallpaperFileWithContents("lock wallpaper");
+ mockCurrentWallpaperIds(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+ markAgentAsOverQuota();
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ DataTypeResult result = getLoggingResult(WALLPAPER_IMG_SYSTEM,
+ mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
+ assertThat(result).isNotNull();
+ assertThat(result.getSuccessCount()).isEqualTo(1);
+ }
+
private void mockCurrentWallpaperIds(int systemWallpaperId, int lockWallpaperId) {
when(mWallpaperManager.getWallpaperId(eq(FLAG_SYSTEM))).thenReturn(systemWallpaperId);
when(mWallpaperManager.getWallpaperId(eq(FLAG_LOCK))).thenReturn(lockWallpaperId);
@@ -432,16 +636,41 @@
ParcelFileDescriptor.open(fakeLockWallpaperFile, MODE_READ_ONLY));
}
+ private WallpaperInfo getFakeWallpaperInfo() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+ Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
+ intent.setPackage("com.android.wallpaperbackup.tests");
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> result = pm.queryIntentServices(intent, PackageManager.GET_META_DATA);
+ assertEquals(1, result.size());
+ ResolveInfo info = result.get(0);
+ return new WallpaperInfo(context, info);
+ }
+
+ private void markAgentAsOverQuota() throws Exception {
+ // Create over quota file to indicate the last backup was over quota
+ File quotaFile = new File(mContext.getFilesDir(), WallpaperBackupAgent.QUOTA_SENTINEL);
+ quotaFile.createNewFile();
+
+ // Now redo the setup of the agent to pick up the over quota
+ mWallpaperBackupAgent.onCreate(USER_HANDLE, BackupAnnotations.BackupDestination.CLOUD,
+ BackupAnnotations.OperationType.BACKUP);
+ }
+
+ private static DataTypeResult getLoggingResult(String dataType, List<DataTypeResult> results) {
+ for (DataTypeResult result : results) {
+ if ((result.getDataType()).equals(dataType)) {
+ return result;
+ }
+ }
+ return null;
+ }
+
private class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
- File mWallpaperBaseDirectory;
List<File> mBackedUpFiles = new ArrayList<>();
PackageMonitor mWallpaperPackageMonitor;
boolean mIsDeviceInRestore = false;
- IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) {
- mWallpaperBaseDirectory = wallpaperBaseDirectory;
- }
-
@Override
protected void backupFile(File file, FullBackupDataOutput data) {
mBackedUpFiles.add(file);
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperEventLoggerTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperEventLoggerTest.java
new file mode 100644
index 0000000..3816a3c
--- /dev/null
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperEventLoggerTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2023 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.wallpaperbackup;
+
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_LOCK;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_IMG_SYSTEM;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_LOCK;
+import static com.android.wallpaperbackup.WallpaperEventLogger.WALLPAPER_LIVE_SYSTEM;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.WallpaperInfo;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupRestoreEventLogger;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.service.wallpaper.WallpaperService;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.wallpaperbackup.utils.TestWallpaperService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class WallpaperEventLoggerTest {
+
+ @Mock
+ private BackupRestoreEventLogger mMockLogger;
+
+ @Mock
+ private BackupManager mMockBackupManager;
+
+ @Mock
+ private WallpaperBackupAgent mMockBackupAgent;
+
+ private static final String WALLPAPER_ERROR = "some_error";
+
+ private WallpaperEventLogger mWallpaperEventLogger;
+ private WallpaperInfo mWallpaperInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mMockBackupAgent.getBackupRestoreEventLogger()).thenReturn(mMockLogger);
+ when(mMockBackupManager.getBackupRestoreEventLogger(any())).thenReturn(mMockLogger);
+
+ mWallpaperInfo = getWallpaperInfo();
+ mWallpaperEventLogger = new WallpaperEventLogger(mMockBackupManager, mMockBackupAgent);
+ }
+
+ @Test
+ public void onSystemImgWallpaperBackedUp_logsSuccess() {
+ mWallpaperEventLogger.onSystemImageWallpaperBackedUp();
+
+ verify(mMockLogger).logItemsBackedUp(eq(WALLPAPER_IMG_SYSTEM), eq(1));
+ }
+
+ @Test
+ public void onLockImgWallpaperBackedUp_logsSuccess() {
+ mWallpaperEventLogger.onLockImageWallpaperBackedUp();
+
+ verify(mMockLogger).logItemsBackedUp(eq(WALLPAPER_IMG_LOCK), eq(1));
+ }
+
+ @Test
+ public void onSystemLiveWallpaperBackedUp_logsSuccess() {
+ mWallpaperEventLogger.onSystemLiveWallpaperBackedUp(mWallpaperInfo);
+
+ verify(mMockLogger).logItemsBackedUp(eq(WALLPAPER_LIVE_SYSTEM), eq(1));
+ }
+
+ @Test
+ public void onLockLiveWallpaperBackedUp_logsSuccess() {
+ mWallpaperEventLogger.onLockLiveWallpaperBackedUp(mWallpaperInfo);
+
+ verify(mMockLogger).logItemsBackedUp(eq(WALLPAPER_LIVE_LOCK), eq(1));
+ }
+
+ @Test
+ public void onImgWallpaperBackedUp_nullInfo_doesNotLogMetadata() {
+ mWallpaperEventLogger.onSystemImageWallpaperBackedUp();
+
+ verify(mMockLogger, never()).logBackupMetadata(eq(WALLPAPER_IMG_SYSTEM), anyString());
+ }
+
+
+ @Test
+ public void onLiveWallpaperBackedUp_logsMetadata() {
+ mWallpaperEventLogger.onSystemLiveWallpaperBackedUp(mWallpaperInfo);
+
+ verify(mMockLogger).logBackupMetadata(eq(WALLPAPER_LIVE_SYSTEM),
+ eq(TestWallpaperService.class.getName()));
+ }
+
+
+ @Test
+ public void onSystemImgWallpaperBackupFailed_logsFail() {
+ mWallpaperEventLogger.onSystemImageWallpaperBackupFailed(WALLPAPER_ERROR);
+
+ verify(mMockLogger).logItemsBackupFailed(eq(WALLPAPER_IMG_SYSTEM), eq(1),
+ eq(WALLPAPER_ERROR));
+ }
+
+ @Test
+ public void onLockImgWallpaperBackupFailed_logsFail() {
+ mWallpaperEventLogger.onLockImageWallpaperBackupFailed(WALLPAPER_ERROR);
+
+ verify(mMockLogger).logItemsBackupFailed(eq(WALLPAPER_IMG_LOCK), eq(1),
+ eq(WALLPAPER_ERROR));
+ }
+
+
+ @Test
+ public void onSystemLiveWallpaperBackupFailed_logsFail() {
+ mWallpaperEventLogger.onSystemLiveWallpaperBackupFailed(WALLPAPER_ERROR);
+
+ verify(mMockLogger).logItemsBackupFailed(eq(WALLPAPER_LIVE_SYSTEM), eq(1),
+ eq(WALLPAPER_ERROR));
+ }
+
+ @Test
+ public void onLockLiveWallpaperBackupFailed_logsFail() {
+ mWallpaperEventLogger.onLockLiveWallpaperBackupFailed(WALLPAPER_ERROR);
+
+ verify(mMockLogger).logItemsBackupFailed(eq(WALLPAPER_LIVE_LOCK), eq(1),
+ eq(WALLPAPER_ERROR));
+ }
+
+
+ @Test
+ public void onWallpaperBackupException_someProcessed_doesNotLogErrorForProcessedType() {
+ mWallpaperEventLogger.onSystemImageWallpaperBackedUp();
+
+ mWallpaperEventLogger.onBackupException(new Exception());
+
+ verify(mMockLogger, never()).logItemsBackupFailed(eq(WALLPAPER_IMG_SYSTEM), anyInt(),
+ anyString());
+ }
+
+
+ @Test
+ public void onWallpaperBackupException_someProcessed_logsErrorForUnprocessedType() {
+ mWallpaperEventLogger.onSystemImageWallpaperBackedUp();
+
+ mWallpaperEventLogger.onBackupException(new Exception());
+
+ verify(mMockLogger).logItemsBackupFailed(eq(WALLPAPER_IMG_LOCK), eq(1),
+ eq(Exception.class.getName()));
+
+ }
+
+ @Test
+ public void onWallpaperBackupException_liveTypeProcessed_doesNotLogErrorForSameImgType() {
+ mWallpaperEventLogger.onSystemLiveWallpaperBackedUp(mWallpaperInfo);
+
+ mWallpaperEventLogger.onBackupException(new Exception());
+
+ verify(mMockLogger, never()).logItemsBackupFailed(eq(WALLPAPER_IMG_SYSTEM), anyInt(),
+ anyString());
+ }
+
+ private WallpaperInfo getWallpaperInfo() throws Exception {
+ Context context = InstrumentationRegistry.getTargetContext();
+ Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
+ intent.setPackage("com.android.wallpaperbackup.tests");
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> result = pm.queryIntentServices(intent, PackageManager.GET_META_DATA);
+ assertEquals(1, result.size());
+ ResolveInfo info = result.get(0);
+ return new WallpaperInfo(context, info);
+ }
+}
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/TestWallpaperService.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/TestWallpaperService.java
new file mode 100644
index 0000000..cb85041
--- /dev/null
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/utils/TestWallpaperService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 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.wallpaperbackup.utils;
+
+import android.service.wallpaper.WallpaperService;
+
+/**
+ * Empty wallpaper service used for wallpaper backup tests
+ */
+public class TestWallpaperService extends WallpaperService {
+ @Override
+ public Engine onCreateEngine() {
+ return new Engine();
+ }
+}