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