1 /*
2  * Copyright (C) 2018 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 com.android.cts.install.lib.testapp;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.res.Resources;
23 import android.os.Process;
24 
25 import java.io.File;
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.io.PrintWriter;
29 import java.util.Scanner;
30 
31 /**
32  * A broadcast receiver to check for and update user app data version
33  * and user handle compatibility.
34  */
35 public class ProcessUserData extends BroadcastReceiver {
36 
37     /**
38      * Exception thrown in case of issue with user data.
39      */
40     public static class UserDataException extends Exception {
UserDataException(String message)41         public UserDataException(String message) {
42             super(message);
43         }
44 
UserDataException(String message, Throwable cause)45         public UserDataException(String message, Throwable cause) {
46            super(message, cause);
47         }
48     }
49 
50     @Override
onReceive(Context context, Intent intent)51     public void onReceive(Context context, Intent intent) {
52         if (intent.getAction().equals("PROCESS_USER_DATA")) {
53             try {
54                 processUserData(context);
55                 setResultCode(1);
56             } catch (UserDataException e) {
57                 setResultCode(0);
58                 setResultData(e.getMessage());
59             }
60         } else if (intent.getAction().equals("GET_USER_DATA_VERSION")) {
61             setResultCode(getUserDataVersion(context));
62         }
63     }
64 
65     /**
66      * Update the app's user data version to match the app version, and confirm
67      * the user data is for the correct user.
68      *
69      * @param context The application context.
70      * @throws UserDataException in case of problems with app user data.
71      */
processUserData(Context context)72     public void processUserData(Context context) throws UserDataException {
73         Resources res = context.getResources();
74         String packageName = context.getPackageName();
75 
76         String userHandle = Process.myUserHandle().toString();
77 
78         int appVersionId = res.getIdentifier("app_version", "integer", packageName);
79         int appVersion = res.getInteger(appVersionId);
80 
81         int splitVersionId = res.getIdentifier("split_version", "integer", packageName);
82         int splitVersion = res.getInteger(splitVersionId);
83 
84         // Make sure the app version and split versions are compatible.
85         if (appVersion != splitVersion) {
86             throw new UserDataException("Split version " + splitVersion
87                     + " does not match app version " + appVersion);
88         }
89 
90         // Read the version of the app's user data and ensure it is compatible
91         // with our version of the application. Also ensure that the user data is
92         // for the correct user.
93         File versionFile = new File(context.getFilesDir(), "userdata.txt");
94         try {
95             Scanner s = new Scanner(versionFile);
96             int userDataVersion = s.nextInt();
97             s.nextLine();
98 
99             if (userDataVersion > appVersion) {
100                 throw new UserDataException("User data is from version " + userDataVersion
101                         + ", which is not compatible with this version " + appVersion
102                         + " of the RollbackTestApp");
103             }
104 
105             String readUserHandle = s.nextLine();
106             s.close();
107 
108             if (!readUserHandle.equals(userHandle)) {
109                 throw new UserDataException("User handle expected to be: " + userHandle
110                         + ", but was actually " + readUserHandle);
111             }
112         } catch (FileNotFoundException e) {
113             // No problem. This is a fresh install of the app or the user data
114             // has been wiped.
115         }
116 
117         // Record the current version of the app in the user data.
118         try {
119             PrintWriter pw = new PrintWriter(versionFile);
120             pw.println(appVersion);
121             pw.println(userHandle);
122             pw.close();
123         } catch (IOException e) {
124             throw new UserDataException("Unable to write user data.", e);
125         }
126     }
127 
128     /**
129      * Return the app's user data version or -1 if userdata.txt doesn't exist.
130      */
getUserDataVersion(Context context)131     private int getUserDataVersion(Context context) {
132         File versionFile = new File(context.getFilesDir(), "userdata.txt");
133         try (Scanner s = new Scanner(versionFile);) {
134             int dataVersion = s.nextInt();
135             return dataVersion;
136         } catch (FileNotFoundException e) {
137             // No problem. This is a fresh install of the app or the user data
138             // has been wiped.
139             return -1;
140         }
141     }
142 }
143