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