• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.cts.backup.keyvaluerestoreapp;
18 
19 import static android.content.Context.MODE_PRIVATE;
20 
21 import static androidx.test.InstrumentationRegistry.getTargetContext;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.app.backup.BackupManager;
27 import android.app.backup.BackupObserver;
28 import android.app.backup.FileBackupHelper;
29 import android.app.backup.SharedPreferencesBackupHelper;
30 import android.content.BroadcastReceiver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.SharedPreferences;
35 import android.platform.test.annotations.AppModeFull;
36 import android.util.Log;
37 
38 import androidx.test.runner.AndroidJUnit4;
39 
40 import com.android.compatibility.common.util.SystemUtil;
41 import com.android.compatibility.common.util.TestUtils;
42 
43 import org.junit.After;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 
48 import java.io.File;
49 import java.io.FileNotFoundException;
50 import java.io.PrintWriter;
51 import java.util.Scanner;
52 import java.util.concurrent.CountDownLatch;
53 import java.util.concurrent.TimeUnit;
54 
55 /**
56  * Device side routines to be invoked by the host side KeyValueBackupRestoreHostSideTest. These
57  * are not designed to be called in any other way, as they rely on state set up by the host side
58  * test.
59  *
60  * Some tests invoked by KeyValueBackupRestoreHostSideTest#testSharedPreferencesRestore() are
61  * interacting with SharedPrefsRestoreTestActivity from another package.
62  *
63  */
64 @RunWith(AndroidJUnit4.class)
65 @AppModeFull
66 public class KeyValueBackupRestoreTest {
67     private static final String KEY_VALUE_RESTORE_APP_PACKAGE =
68             "android.cts.backup.keyvaluerestoreapp";
69     private static final String TAG = "KeyValueBackupRestore";
70 
71     // Names and values of the test files for
72     // KeyValueBackupRestoreHostSideTest#testKeyValueBackupAndRestore()
73     private static final String TEST_FILE_1 = "test-file-1";
74     private static final String TEST_FILE_1_DATA = "test-file-1-data";
75 
76     private static final String TEST_FILE_2 = "test-file-2";
77     private static final String TEST_FILE_2_DATA = "test-file-2-data";
78 
79     private static final String TEST_PREFS_1 = "test-prefs-1";
80     private static final String INT_PREF = "int-pref";
81     private static final int INT_PREF_VALUE = 111;
82     private static final String BOOL_PREF = "bool-pref";
83     private static final boolean BOOL_PREF_VALUE = true;
84 
85     private static final String TEST_PREFS_2 = "test-prefs-2";
86     private static final String FLOAT_PREF = "float-pref";
87     private static final float FLOAT_PREF_VALUE = 0.12345f;
88     private static final String LONG_PREF = "long-pref";
89     private static final long LONG_PREF_VALUE = 12345L;
90     private static final String STRING_PREF = "string-pref";
91     private static final String STRING_PREF_VALUE = "string-pref-value";
92 
93     private static final int DEFAULT_INT_VALUE = 0;
94     private static final boolean DEFAULT_BOOL_VALUE = false;
95     private static final float DEFAULT_FLOAT_VALUE = 0.0f;
96     private static final long DEFAULT_LONG_VALUE = 0L;
97     private static final String DEFAULT_STRING_VALUE = null;
98     private static final String DEFAULT_FILE_CONTENT = "";
99 
100 
101     /** Package name of the test app for
102      * KeyValueBackupRestoreHostSideTest#testSharedPreferencesRestore() */
103     private static final String SHARED_PREFERENCES_RESTORE_PACKAGE_NAME =
104             "android.cts.backup.sharedprefrestoreapp";
105 
106     /** Test activity for KeyValueBackupRestoreHostSideTest#testSharedPreferencesRestore() */
107     private static final String SHARED_PREFERENCES_RESTORE_ACTIVITY_NAME =
108             SHARED_PREFERENCES_RESTORE_PACKAGE_NAME + ".SharedPrefsRestoreTestActivity";
109 
110     // Shared prefs test activity actions
111     private static final String INIT_ACTION = "android.backup.cts.backuprestore.INIT";
112     private static final String UPDATE_ACTION = "android.backup.cts.backuprestore.UPDATE";
113     private static final String TEST_ACTION = "android.backup.cts.backuprestore.TEST";
114 
115     // Action for returning the result of shared preference activity's operations
116     private static final String RESULT_ACTION = "android.backup.cts.backuprestore.RESULT";
117     private static final String EXTRA_SUCCESS = "EXTRA_SUCCESS";
118 
119     private static final int ACTIVITY_TEST_TIMEOUT_MS = 5000;
120     private static final int REQUEST_BACKUP_TIMEOUT_SECS = 60;
121 
122     private Context mContext;
123 
124     private int mIntValue;
125     private boolean mBoolValue;
126     private float mFloatValue;
127     private long mLongValue;
128     private String mStringValue;
129     private String mFileContent1;
130     private String mFileContent2;
131 
132     private boolean mSharedPrefTestSuccess;
133     private CountDownLatch mLatch;
134     private Intent mSharedPrefActivityIntent;
135     private BackupManager mBackupManager;
136 
137     private final BroadcastReceiver mSharedPrefencesReceiver = new BroadcastReceiver() {
138         @Override
139         public void onReceive(Context context, Intent intent) {
140             Log.i(TAG, "Received shared preference activity result broadcast");
141             mSharedPrefTestSuccess = intent.getBooleanExtra(EXTRA_SUCCESS, false);
142             mLatch.countDown();
143         }
144     };
145 
146     @Before
setUp()147     public void setUp() {
148         Log.i(TAG, "set up");
149 
150         mContext = getTargetContext();
151         mLatch = new CountDownLatch(1);
152         mSharedPrefTestSuccess = false;
153         mSharedPrefActivityIntent = new Intent()
154                 .setClassName(SHARED_PREFERENCES_RESTORE_PACKAGE_NAME,
155                         SHARED_PREFERENCES_RESTORE_ACTIVITY_NAME)
156                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
157         mContext.registerReceiver(mSharedPrefencesReceiver, new IntentFilter(RESULT_ACTION),
158                 Context.RECEIVER_EXPORTED_UNAUDITED);
159         mBackupManager = new BackupManager(mContext);
160     }
161 
162     @After
tearDown()163     public void tearDown() {
164         mContext.unregisterReceiver(mSharedPrefencesReceiver);
165     }
166 
167     @Test
saveSharedPreferencesAndNotifyBackupManager()168     public void saveSharedPreferencesAndNotifyBackupManager() throws Exception {
169         saveSharedPreferencesValues();
170 
171         //Let BackupManager know that the data has changed
172         BackupManager backupManager = new BackupManager(mContext);
173         backupManager.dataChanged();
174     }
175 
176     @Test
checkSharedPrefIsEmpty()177     public void checkSharedPrefIsEmpty() throws Exception {
178         readSharedPrefValues();
179         assertEquals(DEFAULT_INT_VALUE, mIntValue);
180         assertEquals(DEFAULT_BOOL_VALUE, mBoolValue);
181         assertEquals(DEFAULT_FLOAT_VALUE, mFloatValue, 0.001f);
182         assertEquals(DEFAULT_LONG_VALUE, mLongValue);
183         assertEquals(DEFAULT_STRING_VALUE, mStringValue);
184         assertEquals(DEFAULT_FILE_CONTENT, mFileContent1);
185         assertEquals(DEFAULT_FILE_CONTENT, mFileContent2);
186     }
187 
188     @Test
checkSharedPreferencesAreRestored()189     public void checkSharedPreferencesAreRestored() throws Exception {
190         readSharedPrefValues();
191         assertEquals(INT_PREF_VALUE, mIntValue);
192         assertEquals(BOOL_PREF_VALUE, mBoolValue);
193         assertEquals(FLOAT_PREF_VALUE, mFloatValue, 0.001f);
194         assertEquals(LONG_PREF_VALUE, mLongValue);
195         assertEquals(STRING_PREF_VALUE, mStringValue);
196         assertEquals(TEST_FILE_1_DATA, mFileContent1);
197         assertEquals(TEST_FILE_2_DATA, mFileContent2);
198     }
199 
200     @Test
launchSharedPrefActivity()201     public void launchSharedPrefActivity() throws Exception {
202         mContext.startActivity(mSharedPrefActivityIntent.setAction(INIT_ACTION));
203 
204         assertTrue("Activity init timed out",
205                 mLatch.await(ACTIVITY_TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
206         assertTrue("Saving shared preferences didn't succeed", mSharedPrefTestSuccess);
207     }
208 
209     @Test
updateSharedPrefActivity()210     public void updateSharedPrefActivity() throws Exception {
211         mContext.startActivity(mSharedPrefActivityIntent.setAction(UPDATE_ACTION));
212 
213         assertTrue("Activity launch timed out",
214                 mLatch.await(ACTIVITY_TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
215         assertTrue("Saving shared preferences didn't succeed", mSharedPrefTestSuccess);
216     }
217 
218     @Test
checkSharedPrefActivity()219     public void checkSharedPrefActivity() throws Exception {
220         mContext.startActivity(mSharedPrefActivityIntent.setAction(TEST_ACTION));
221 
222         assertTrue("Activity test timed out",
223                 mLatch.await(ACTIVITY_TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
224         assertTrue("Shared preference value wasn't updated from the restore set",
225                 mSharedPrefTestSuccess);
226     }
227 
228     /** Saves predefined constant values to shared preferences and files. */
saveSharedPreferencesValues()229     private void saveSharedPreferencesValues() throws FileNotFoundException {
230         SharedPreferences prefs = mContext.getSharedPreferences(TEST_PREFS_1, MODE_PRIVATE);
231         SharedPreferences.Editor editor = prefs.edit();
232         editor.putInt(INT_PREF, INT_PREF_VALUE);
233         editor.putBoolean(BOOL_PREF, BOOL_PREF_VALUE);
234         assertTrue("Error committing shared preference 1 value", editor.commit());
235 
236         prefs = mContext.getSharedPreferences(TEST_PREFS_2, MODE_PRIVATE);
237         editor = prefs.edit();
238         editor.putFloat(FLOAT_PREF, FLOAT_PREF_VALUE);
239         editor.putLong(LONG_PREF, LONG_PREF_VALUE);
240         editor.putString(STRING_PREF, STRING_PREF_VALUE);
241         assertTrue("Error committing shared preference 2 value", editor.commit());
242 
243         File file = new File(mContext.getFilesDir(), TEST_FILE_1);
244         PrintWriter writer = new PrintWriter(file);
245         writer.write(TEST_FILE_1_DATA);
246         writer.close();
247         assertTrue("Error writing file 1 data", file.exists());
248 
249         file = new File(mContext.getFilesDir(), TEST_FILE_2);
250         writer = new PrintWriter(file);
251         writer.write(TEST_FILE_2_DATA);
252         writer.close();
253         assertTrue("Error writing file 2 data", file.exists());
254     }
255 
readSharedPrefValues()256     private void readSharedPrefValues() throws InterruptedException {
257         SharedPreferences prefs = mContext.getSharedPreferences(TEST_PREFS_1, MODE_PRIVATE);
258         mIntValue = prefs.getInt(INT_PREF, DEFAULT_INT_VALUE);
259         mBoolValue = prefs.getBoolean(BOOL_PREF, DEFAULT_BOOL_VALUE);
260 
261         prefs = mContext.getSharedPreferences(TEST_PREFS_2, MODE_PRIVATE);
262         mFloatValue = prefs.getFloat(FLOAT_PREF, DEFAULT_FLOAT_VALUE);
263         mLongValue = prefs.getLong(LONG_PREF, DEFAULT_LONG_VALUE);
264         mStringValue = prefs.getString(STRING_PREF, DEFAULT_STRING_VALUE);
265 
266         mFileContent1 = readFileContent(TEST_FILE_1);
267         mFileContent2 = readFileContent(TEST_FILE_2);
268 
269         Log.i(TAG, INT_PREF + ":" + mIntValue + "\n"
270                 + BOOL_PREF + ":" + mBoolValue + "\n"
271                 + FLOAT_PREF + ":" + mFloatValue + "\n"
272                 + LONG_PREF + ":" + mLongValue + "\n"
273                 + STRING_PREF + ":" + mStringValue + "\n"
274                 + TEST_FILE_1 + ":" + mFileContent1 + "\n"
275                 + TEST_FILE_2 + ":" + mFileContent2 + "\n");
276     }
277 
readFileContent(String fileName)278     private String readFileContent(String fileName) {
279         StringBuilder contents = new StringBuilder();
280         Scanner scanner = null;
281         try {
282             scanner = new Scanner(new File(mContext.getFilesDir(), fileName));
283             while (scanner.hasNext()) {
284                 contents.append(scanner.nextLine());
285             }
286             scanner.close();
287         } catch (FileNotFoundException e) {
288             Log.i(TAG, "Couldn't find test file but this may be fine...");
289         } finally {
290             if (scanner != null) {
291                 scanner.close();
292             }
293         }
294         return contents.toString();
295     }
296 
getSharedPreferencesBackupHelper(Context context)297     public static SharedPreferencesBackupHelper getSharedPreferencesBackupHelper(Context context) {
298         return new SharedPreferencesBackupHelper(context, TEST_PREFS_1, TEST_PREFS_2);
299     }
300 
getFileBackupHelper(Context context)301     public static FileBackupHelper getFileBackupHelper(Context context) {
302         return new FileBackupHelper(context, TEST_FILE_1, TEST_FILE_2);
303     }
304 
305     /**
306      * This is not an actual test, but a device-side routine that's called from the host-side to
307      * requestBackup.
308      */
309     @Test
requestBackup()310     public void requestBackup(){
311         SystemUtil.runWithShellPermissionIdentity(this::requestBackupInternal);
312     }
313 
requestBackupInternal()314     private void requestBackupInternal() throws Exception {
315         RequestBackupObserver observer = new RequestBackupObserver();
316         int result = mBackupManager.requestBackup(
317                 new String[] {KEY_VALUE_RESTORE_APP_PACKAGE}, observer);
318         Log.i(TAG, "requestBackup returned with:" + result);
319         if (result == 0) {
320             Log.i(TAG, "Waiting for requestBackup to finish");
321             observer.waitForCompletion();
322         }
323     }
324 
325     private static class RequestBackupObserver extends BackupObserver {
326         private volatile boolean mDone = false;
327 
328         @Override
backupFinished(int status)329         public void backupFinished(int status) {
330             Log.i(TAG, "backupFinished with status=:" + status);
331             mDone = true;
332         }
333 
waitForCompletion()334         public void waitForCompletion() throws Exception {
335             TestUtils.waitUntil(
336                     "Waiting for requestBackup to complete for " + KEY_VALUE_RESTORE_APP_PACKAGE,
337                     REQUEST_BACKUP_TIMEOUT_SECS,
338                     () -> mDone);
339         }
340     }
341 }
342