SystemImpl.java revision ff396f2710e60a4c596e30c7dc74ad7ef24a7ecc
1/* 2 * Copyright (C) 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 17package com.android.server.webkit; 18 19import android.app.ActivityManagerNative; 20import android.app.AppGlobals; 21import android.content.Context; 22import android.content.pm.ApplicationInfo; 23import android.content.pm.IPackageDeleteObserver; 24import android.content.pm.PackageInfo; 25import android.content.pm.PackageManager; 26import android.content.pm.PackageManager.NameNotFoundException; 27import android.content.pm.UserInfo; 28import android.content.res.XmlResourceParser; 29import android.os.Build; 30import android.os.RemoteException; 31import android.os.UserHandle; 32import android.os.UserManager; 33import android.provider.Settings.Global; 34import android.provider.Settings; 35import android.util.AndroidRuntimeException; 36import android.util.Log; 37import android.webkit.WebViewFactory.MissingWebViewPackageException; 38import android.webkit.WebViewFactory; 39import android.webkit.WebViewProviderInfo; 40 41import com.android.internal.util.XmlUtils; 42 43import java.io.IOException; 44import java.util.ArrayList; 45import java.util.List; 46 47import org.xmlpull.v1.XmlPullParserException; 48 49/** 50 * Default implementation for the WebView preparation Utility interface. 51 * @hide 52 */ 53public class SystemImpl implements SystemInterface { 54 private static final String TAG = SystemImpl.class.getSimpleName(); 55 private static final String TAG_START = "webviewproviders"; 56 private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider"; 57 private static final String TAG_PACKAGE_NAME = "packageName"; 58 private static final String TAG_DESCRIPTION = "description"; 59 // Whether or not the provider must be explicitly chosen by the user to be used. 60 private static final String TAG_AVAILABILITY = "availableByDefault"; 61 private static final String TAG_SIGNATURE = "signature"; 62 private static final String TAG_FALLBACK = "isFallback"; 63 64 /** 65 * Returns all packages declared in the framework resources as potential WebView providers. 66 * @hide 67 * */ 68 @Override 69 public WebViewProviderInfo[] getWebViewPackages() { 70 int numFallbackPackages = 0; 71 XmlResourceParser parser = null; 72 List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>(); 73 try { 74 parser = AppGlobals.getInitialApplication().getResources().getXml( 75 com.android.internal.R.xml.config_webview_packages); 76 XmlUtils.beginDocument(parser, TAG_START); 77 while(true) { 78 XmlUtils.nextElement(parser); 79 String element = parser.getName(); 80 if (element == null) { 81 break; 82 } 83 if (element.equals(TAG_WEBVIEW_PROVIDER)) { 84 String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME); 85 if (packageName == null) { 86 throw new MissingWebViewPackageException( 87 "WebView provider in framework resources missing package name"); 88 } 89 String description = parser.getAttributeValue(null, TAG_DESCRIPTION); 90 if (description == null) { 91 throw new MissingWebViewPackageException( 92 "WebView provider in framework resources missing description"); 93 } 94 boolean availableByDefault = "true".equals( 95 parser.getAttributeValue(null, TAG_AVAILABILITY)); 96 boolean isFallback = "true".equals( 97 parser.getAttributeValue(null, TAG_FALLBACK)); 98 WebViewProviderInfo currentProvider = new WebViewProviderInfo( 99 packageName, description, availableByDefault, isFallback, 100 readSignatures(parser)); 101 if (currentProvider.isFallback) { 102 numFallbackPackages++; 103 if (numFallbackPackages > 1) { 104 throw new AndroidRuntimeException( 105 "There can be at most one webview fallback package."); 106 } 107 } 108 webViewProviders.add(currentProvider); 109 } 110 else { 111 Log.e(TAG, "Found an element that is not a webview provider"); 112 } 113 } 114 } catch (XmlPullParserException | IOException e) { 115 throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e); 116 } finally { 117 if (parser != null) parser.close(); 118 } 119 return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]); 120 } 121 122 public int getFactoryPackageVersion(String packageName) throws NameNotFoundException { 123 PackageManager pm = AppGlobals.getInitialApplication().getPackageManager(); 124 return pm.getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY).versionCode; 125 } 126 127 /** 128 * Reads all signatures at the current depth (within the current provider) from the XML parser. 129 */ 130 private static String[] readSignatures(XmlResourceParser parser) throws IOException, 131 XmlPullParserException { 132 List<String> signatures = new ArrayList<String>(); 133 int outerDepth = parser.getDepth(); 134 while(XmlUtils.nextElementWithin(parser, outerDepth)) { 135 if (parser.getName().equals(TAG_SIGNATURE)) { 136 // Parse the value within the signature tag 137 String signature = parser.nextText(); 138 signatures.add(signature); 139 } else { 140 Log.e(TAG, "Found an element in a webview provider that is not a signature"); 141 } 142 } 143 return signatures.toArray(new String[signatures.size()]); 144 } 145 146 @Override 147 public int onWebViewProviderChanged(PackageInfo packageInfo) { 148 return WebViewFactory.onWebViewProviderChanged(packageInfo); 149 } 150 151 @Override 152 public String getUserChosenWebViewProvider(Context context) { 153 return Settings.Global.getString(context.getContentResolver(), 154 Settings.Global.WEBVIEW_PROVIDER); 155 } 156 157 @Override 158 public void updateUserSetting(Context context, String newProviderName) { 159 Settings.Global.putString(context.getContentResolver(), 160 Settings.Global.WEBVIEW_PROVIDER, 161 newProviderName == null ? "" : newProviderName); 162 } 163 164 @Override 165 public void killPackageDependents(String packageName) { 166 try { 167 ActivityManagerNative.getDefault().killPackageDependents(packageName, 168 UserHandle.USER_ALL); 169 } catch (RemoteException e) { 170 } 171 } 172 173 @Override 174 public boolean isFallbackLogicEnabled() { 175 // Note that this is enabled by default (i.e. if the setting hasn't been set). 176 return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(), 177 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1; 178 } 179 180 @Override 181 public void enableFallbackLogic(boolean enable) { 182 Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(), 183 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0); 184 } 185 186 @Override 187 public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) { 188 enablePackageForAllUsers(context, packageName, false); 189 try { 190 PackageManager pm = AppGlobals.getInitialApplication().getPackageManager(); 191 ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0); 192 if (applicationInfo != null && applicationInfo.isUpdatedSystemApp()) { 193 pm.deletePackage(packageName, new IPackageDeleteObserver.Stub() { 194 public void packageDeleted(String packageName, int returnCode) { 195 enablePackageForAllUsers(context, packageName, false); 196 } 197 }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS); 198 } 199 } catch (NameNotFoundException e) { 200 } 201 } 202 203 @Override 204 public void enablePackageForAllUsers(Context context, String packageName, boolean enable) { 205 UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); 206 for(UserInfo userInfo : userManager.getUsers()) { 207 enablePackageForUser(packageName, enable, userInfo.id); 208 } 209 } 210 211 @Override 212 public void enablePackageForUser(String packageName, boolean enable, int userId) { 213 try { 214 AppGlobals.getPackageManager().setApplicationEnabledSetting( 215 packageName, 216 enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT : 217 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0, 218 userId, null); 219 } catch (RemoteException | IllegalArgumentException e) { 220 Log.w(TAG, "Tried to " + (enable ? "enable " : "disable ") + packageName 221 + " for user " + userId + ": " + e); 222 } 223 } 224 225 @Override 226 public boolean systemIsDebuggable() { 227 return Build.IS_DEBUGGABLE; 228 } 229 230 @Override 231 public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo) 232 throws NameNotFoundException { 233 PackageManager pm = AppGlobals.getInitialApplication().getPackageManager(); 234 return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS); 235 } 236 237 // flags declaring we want extra info from the package manager for webview providers 238 private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA 239 | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING; 240} 241