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