1893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz/* 2893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Copyright 2016, The Android Open Source Project 3893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * 4893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Licensed under the Apache License, Version 2.0 (the "License"); 5893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * you may not use this file except in compliance with the License. 6893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * You may obtain a copy of the License at 7893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * 8893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * http://www.apache.org/licenses/LICENSE-2.0 9893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * 10893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Unless required by applicable law or agreed to in writing, software 11893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * distributed under the License is distributed on an "AS IS" BASIS, 12893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * See the License for the specific language governing permissions and 14893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * limitations under the License. 15893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz */ 16893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 17893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzpackage com.android.managedprovisioning.task.nonrequiredapps; 18893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 19893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport static com.android.internal.util.Preconditions.checkNotNull; 20893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 21893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport android.annotation.Nullable; 22893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport android.app.AppGlobals; 23893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport android.content.Context; 24893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport android.content.pm.IPackageManager; 25893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport android.util.Xml; 26893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 27893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport com.android.internal.annotations.VisibleForTesting; 28893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport com.android.internal.util.FastXmlSerializer; 29893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport com.android.managedprovisioning.common.ProvisionLogger; 30893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport com.android.managedprovisioning.common.Utils; 31893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 32893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.io.File; 33893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.io.FileInputStream; 34893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.io.FileOutputStream; 35893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.io.IOException; 36893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.util.Collections; 37893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.util.HashSet; 38893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport java.util.Set; 39893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 40893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport org.xmlpull.v1.XmlPullParser; 41893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport org.xmlpull.v1.XmlPullParserException; 42893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzimport org.xmlpull.v1.XmlSerializer; 43893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 44893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz/** 45893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Stores and retrieves the system apps that were on the device during provisioning and on 46893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * subsequent OTAs. 47893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz */ 48893e62e1faddce062d66810f078edf417c724ae4Benjamin Franzpublic class SystemAppsSnapshot { 49893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private static final String TAG_SYSTEM_APPS = "system-apps"; 50893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private static final String TAG_PACKAGE_LIST_ITEM = "item"; 51893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private static final String ATTR_VALUE = "value"; 52893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 53893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private final Context mContext; 54893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private final IPackageManager mIPackageManager; 55893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private final Utils mUtils; 56893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 57893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz public SystemAppsSnapshot(Context context) { 58893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz this(context, AppGlobals.getPackageManager(), new Utils()); 59893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 60893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 61893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz @VisibleForTesting 62893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz SystemAppsSnapshot( 63893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz Context context, 64893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz IPackageManager iPackageManager, 65893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz Utils utils) { 66893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz mContext = checkNotNull(context); 67893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz mIPackageManager = checkNotNull(iPackageManager); 68893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz mUtils = checkNotNull(utils); 69893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 70893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 71893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz /** 72893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Returns whether currently a snapshot exists for the given user. 73893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * 74893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * @param userId the user id for which the snapshot is requested. 75893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz */ 76893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz public boolean hasSnapshot(int userId) { 77893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz return getSystemAppsFile(mContext, userId).exists(); 78893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 79893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 80893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz /** 81893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Returns the last stored snapshot for the given user. 82893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * 83893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * @param userId the user id for which the snapshot is requested. 84893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz */ 85893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz public Set<String> getSnapshot(int userId) { 86893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz return readSystemApps(getSystemAppsFile(mContext, userId)); 87893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 88893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 89893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz /** 90893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * Call this method to take a snapshot of the current set of system apps. 91893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * 92893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz * @param userId the user id for which the snapshot should be taken. 93893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz */ 94893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz public void takeNewSnapshot(int userId) { 95893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz final File systemAppsFile = getSystemAppsFile(mContext, userId); 96893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz systemAppsFile.getParentFile().mkdirs(); // Creating the folder if it does not exist 97893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz writeSystemApps(mUtils.getCurrentSystemApps(mIPackageManager, userId), systemAppsFile); 98893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 99893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 100893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private void writeSystemApps(Set<String> packageNames, File systemAppsFile) { 101893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz try { 102893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz FileOutputStream stream = new FileOutputStream(systemAppsFile, false); 103893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz XmlSerializer serializer = new FastXmlSerializer(); 104893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.setOutput(stream, "utf-8"); 105893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.startDocument(null, true); 106893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.startTag(null, TAG_SYSTEM_APPS); 107893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz for (String packageName : packageNames) { 108893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.startTag(null, TAG_PACKAGE_LIST_ITEM); 109893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.attribute(null, ATTR_VALUE, packageName); 110893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.endTag(null, TAG_PACKAGE_LIST_ITEM); 111893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 112893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.endTag(null, TAG_SYSTEM_APPS); 113893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz serializer.endDocument(); 114893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz stream.close(); 115893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } catch (IOException e) { 116893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz ProvisionLogger.loge("IOException trying to write the system apps", e); 117893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 118893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 119893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 120893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz private Set<String> readSystemApps(File systemAppsFile) { 121893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz Set<String> result = new HashSet<>(); 122893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz if (!systemAppsFile.exists()) { 123893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz return result; 124893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 125893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz try { 126893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz FileInputStream stream = new FileInputStream(systemAppsFile); 127893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 128893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz XmlPullParser parser = Xml.newPullParser(); 129893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz parser.setInput(stream, null); 130893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz parser.next(); 131893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 132893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz int type; 133893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz int outerDepth = parser.getDepth(); 134893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 135893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 136893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 137893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz continue; 138893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 139893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz String tag = parser.getName(); 140893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz if (tag.equals(TAG_PACKAGE_LIST_ITEM)) { 141893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz result.add(parser.getAttributeValue(null, ATTR_VALUE)); 142893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } else { 143893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz ProvisionLogger.loge("Unknown tag: " + tag); 144893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 145893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 146893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz stream.close(); 147893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } catch (IOException e) { 148893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz ProvisionLogger.loge("IOException trying to read the system apps", e); 149893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } catch (XmlPullParserException e) { 150893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz ProvisionLogger.loge("XmlPullParserException trying to read the system apps", e); 151893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 152893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz return result; 153893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 154893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz 155893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz @VisibleForTesting 156893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz static File getSystemAppsFile(Context context, int userId) { 157893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz return new File(context.getFilesDir() + File.separator + "system_apps" 158893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz + File.separator + "user" + userId + ".xml"); 159893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz } 160893e62e1faddce062d66810f078edf417c724ae4Benjamin Franz} 161