1 /* 2 * Copyright 2016, 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.managedprovisioning.task.nonrequiredapps; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 21 import android.app.AppGlobals; 22 import android.content.Context; 23 import android.content.pm.IPackageManager; 24 import android.os.UserManager; 25 import android.util.Xml; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.internal.util.FastXmlSerializer; 29 import com.android.managedprovisioning.common.ProvisionLogger; 30 import com.android.managedprovisioning.common.Utils; 31 32 import org.xmlpull.v1.XmlPullParser; 33 import org.xmlpull.v1.XmlPullParserException; 34 import org.xmlpull.v1.XmlSerializer; 35 36 import java.io.File; 37 import java.io.FileInputStream; 38 import java.io.FileOutputStream; 39 import java.io.IOException; 40 import java.util.HashSet; 41 import java.util.Set; 42 43 /** 44 * Stores and retrieves the system apps that were on the device during provisioning and on 45 * subsequent OTAs. 46 */ 47 public class SystemAppsSnapshot { 48 private static final String TAG_SYSTEM_APPS = "system-apps"; 49 private static final String TAG_PACKAGE_LIST_ITEM = "item"; 50 private static final String ATTR_VALUE = "value"; 51 private static final String LEGACY_FOLDER_NAME = "system_apps"; 52 private static final String FOLDER_NAME = "system_apps_v2"; 53 54 private final Context mContext; 55 private final IPackageManager mIPackageManager; 56 private final Utils mUtils; 57 SystemAppsSnapshot(Context context)58 public SystemAppsSnapshot(Context context) { 59 this(context, AppGlobals.getPackageManager(), new Utils()); 60 } 61 62 @VisibleForTesting SystemAppsSnapshot( Context context, IPackageManager iPackageManager, Utils utils)63 SystemAppsSnapshot( 64 Context context, IPackageManager iPackageManager, Utils utils) { 65 mContext = checkNotNull(context); 66 mIPackageManager = checkNotNull(iPackageManager); 67 mUtils = checkNotNull(utils); 68 } 69 70 /** 71 * Returns whether currently a snapshot exists for the given user. 72 * 73 * @param userId the user id for which the snapshot is requested. 74 */ hasSnapshot(int userId)75 public boolean hasSnapshot(int userId) { 76 return getSystemAppsFile(mContext, userId).exists(); 77 } 78 79 /** 80 * Returns the last stored snapshot for the given user. 81 * 82 * @param userId the user id for which the snapshot is requested. 83 */ getSnapshot(int userId)84 public Set<String> getSnapshot(int userId) { 85 return readSystemApps(getSystemAppsFile(mContext, userId)); 86 } 87 88 /** 89 * Call this method to take a snapshot of the current set of system apps. 90 * 91 * @param userId the user id for which the snapshot should be taken. 92 */ takeNewSnapshot(int userId)93 public void takeNewSnapshot(int userId) { 94 final File systemAppsFile = getSystemAppsFile(mContext, userId); 95 systemAppsFile.getParentFile().mkdirs(); // Creating the folder if it does not exist 96 writeSystemApps(mUtils.getCurrentSystemApps(mIPackageManager, userId), systemAppsFile); 97 } 98 writeSystemApps(Set<String> packageNames, File systemAppsFile)99 private void writeSystemApps(Set<String> packageNames, File systemAppsFile) { 100 try { 101 FileOutputStream stream = new FileOutputStream(systemAppsFile, false); 102 XmlSerializer serializer = new FastXmlSerializer(); 103 serializer.setOutput(stream, "utf-8"); 104 serializer.startDocument(null, true); 105 serializer.startTag(null, TAG_SYSTEM_APPS); 106 for (String packageName : packageNames) { 107 serializer.startTag(null, TAG_PACKAGE_LIST_ITEM); 108 serializer.attribute(null, ATTR_VALUE, packageName); 109 serializer.endTag(null, TAG_PACKAGE_LIST_ITEM); 110 } 111 serializer.endTag(null, TAG_SYSTEM_APPS); 112 serializer.endDocument(); 113 stream.close(); 114 } catch (IOException e) { 115 ProvisionLogger.loge("IOException trying to write the system apps", e); 116 } 117 } 118 readSystemApps(File systemAppsFile)119 private Set<String> readSystemApps(File systemAppsFile) { 120 Set<String> result = new HashSet<>(); 121 if (!systemAppsFile.exists()) { 122 return result; 123 } 124 try { 125 FileInputStream stream = new FileInputStream(systemAppsFile); 126 127 XmlPullParser parser = Xml.newPullParser(); 128 parser.setInput(stream, null); 129 parser.next(); 130 131 int type; 132 int outerDepth = parser.getDepth(); 133 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 134 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 135 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 136 continue; 137 } 138 String tag = parser.getName(); 139 if (tag.equals(TAG_PACKAGE_LIST_ITEM)) { 140 result.add(parser.getAttributeValue(null, ATTR_VALUE)); 141 } else { 142 ProvisionLogger.loge("Unknown tag: " + tag); 143 } 144 } 145 stream.close(); 146 } catch (IOException e) { 147 ProvisionLogger.loge("IOException trying to read the system apps", e); 148 } catch (XmlPullParserException e) { 149 ProvisionLogger.loge("XmlPullParserException trying to read the system apps", e); 150 } 151 return result; 152 } 153 getSystemAppsFile(Context context, int userId)154 public static File getSystemAppsFile(Context context, int userId) { 155 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 156 int userSerialNumber = userManager.getUserSerialNumber(userId); 157 if (userSerialNumber == -1 ) { 158 throw new IllegalArgumentException("Invalid userId : " + userId); 159 } 160 return new File(getFolder(context), userSerialNumber + ".xml"); 161 } 162 getFolder(Context context)163 public static File getFolder(Context context) { 164 return new File(context.getFilesDir(), FOLDER_NAME); 165 } 166 getLegacyFolder(Context context)167 public static File getLegacyFolder(Context context) { 168 return new File(context.getFilesDir(), LEGACY_FOLDER_NAME); 169 } 170 } 171