blob: 6052a6e037c756168884721ab2f947780462ebd6 [file] [log] [blame]
Gustav Sennton8b179262016-03-14 11:31:14 +00001/*
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;
Gustav Sennton065b7e62016-04-01 15:11:43 +010022import android.content.pm.IPackageDeleteObserver;
Gustav Sennton8b179262016-03-14 11:31:14 +000023import android.content.pm.PackageInfo;
Gustav Sennton065b7e62016-04-01 15:11:43 +010024import android.content.pm.PackageManager;
25import android.content.pm.PackageManager.NameNotFoundException;
26import android.content.pm.UserInfo;
Gustav Sennton8b179262016-03-14 11:31:14 +000027import android.content.res.XmlResourceParser;
Gustav Sennton065b7e62016-04-01 15:11:43 +010028import android.os.Build;
Gustav Sennton8b179262016-03-14 11:31:14 +000029import android.os.RemoteException;
30import android.os.UserHandle;
Gustav Sennton065b7e62016-04-01 15:11:43 +010031import android.os.UserManager;
32import android.provider.Settings.Global;
Gustav Sennton8b179262016-03-14 11:31:14 +000033import android.provider.Settings;
34import android.util.AndroidRuntimeException;
35import android.util.Log;
Gustav Sennton8b179262016-03-14 11:31:14 +000036import android.webkit.WebViewFactory.MissingWebViewPackageException;
Gustav Sennton065b7e62016-04-01 15:11:43 +010037import android.webkit.WebViewFactory;
Gustav Sennton8b179262016-03-14 11:31:14 +000038import 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 */
Gustav Sennton065b7e62016-04-01 15:11:43 +010052public class SystemImpl implements SystemInterface {
53 private static final String TAG = SystemImpl.class.getSimpleName();
Gustav Sennton8b179262016-03-14 11:31:14 +000054 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
63 /**
64 * Returns all packages declared in the framework resources as potential WebView providers.
65 * @hide
66 * */
67 @Override
68 public WebViewProviderInfo[] getWebViewPackages() {
69 int numFallbackPackages = 0;
70 XmlResourceParser parser = null;
71 List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
72 try {
73 parser = AppGlobals.getInitialApplication().getResources().getXml(
74 com.android.internal.R.xml.config_webview_packages);
75 XmlUtils.beginDocument(parser, TAG_START);
76 while(true) {
77 XmlUtils.nextElement(parser);
78 String element = parser.getName();
79 if (element == null) {
80 break;
81 }
82 if (element.equals(TAG_WEBVIEW_PROVIDER)) {
83 String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
84 if (packageName == null) {
85 throw new MissingWebViewPackageException(
86 "WebView provider in framework resources missing package name");
87 }
88 String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
89 if (description == null) {
90 throw new MissingWebViewPackageException(
91 "WebView provider in framework resources missing description");
92 }
93 boolean availableByDefault = "true".equals(
94 parser.getAttributeValue(null, TAG_AVAILABILITY));
95 boolean isFallback = "true".equals(
96 parser.getAttributeValue(null, TAG_FALLBACK));
Gustav Senntondbf5eb02016-03-30 14:53:03 +010097 WebViewProviderInfo currentProvider = new WebViewProviderInfo(
98 packageName, description, availableByDefault, isFallback,
99 readSignatures(parser));
100 if (currentProvider.isFallback) {
Gustav Sennton8b179262016-03-14 11:31:14 +0000101 numFallbackPackages++;
102 if (numFallbackPackages > 1) {
103 throw new AndroidRuntimeException(
104 "There can be at most one webview fallback package.");
105 }
106 }
107 webViewProviders.add(currentProvider);
108 }
109 else {
110 Log.e(TAG, "Found an element that is not a webview provider");
111 }
112 }
113 } catch(XmlPullParserException e) {
114 throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
115 } catch(IOException e) {
116 throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
117 } finally {
118 if (parser != null) parser.close();
119 }
120 return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
121 }
122
123 /**
124 * Reads all signatures at the current depth (within the current provider) from the XML parser.
125 */
126 private static String[] readSignatures(XmlResourceParser parser) throws IOException,
127 XmlPullParserException {
128 List<String> signatures = new ArrayList<String>();
129 int outerDepth = parser.getDepth();
130 while(XmlUtils.nextElementWithin(parser, outerDepth)) {
131 if (parser.getName().equals(TAG_SIGNATURE)) {
132 // Parse the value within the signature tag
133 String signature = parser.nextText();
134 signatures.add(signature);
135 } else {
136 Log.e(TAG, "Found an element in a webview provider that is not a signature");
137 }
138 }
139 return signatures.toArray(new String[signatures.size()]);
140 }
141
142 @Override
143 public int onWebViewProviderChanged(PackageInfo packageInfo) {
144 return WebViewFactory.onWebViewProviderChanged(packageInfo);
145 }
146
147 @Override
148 public String getUserChosenWebViewProvider(Context context) {
149 return Settings.Global.getString(context.getContentResolver(),
150 Settings.Global.WEBVIEW_PROVIDER);
151 }
152
153 @Override
154 public void updateUserSetting(Context context, String newProviderName) {
155 Settings.Global.putString(context.getContentResolver(),
156 Settings.Global.WEBVIEW_PROVIDER,
157 newProviderName == null ? "" : newProviderName);
158 }
159
160 @Override
161 public void killPackageDependents(String packageName) {
162 try {
163 ActivityManagerNative.getDefault().killPackageDependents(packageName,
164 UserHandle.USER_ALL);
165 } catch (RemoteException e) {
166 }
167 }
Gustav Sennton065b7e62016-04-01 15:11:43 +0100168
169 @Override
170 public boolean isFallbackLogicEnabled() {
171 // Note that this is enabled by default (i.e. if the setting hasn't been set).
172 return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(),
173 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1;
174 }
175
176 @Override
177 public void enableFallbackLogic(boolean enable) {
178 Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(),
179 Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
180 }
181
182 @Override
183 public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
184 context.getPackageManager().deletePackage(packageName,
185 new IPackageDeleteObserver.Stub() {
186 public void packageDeleted(String packageName, int returnCode) {
187 // Ignore returnCode since the deletion could fail, e.g. we might be trying
188 // to delete a non-updated system-package (and we should still disable the
189 // package)
190 enablePackageForAllUsers(context, packageName, false);
191 }
192 }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
193 }
194
195 @Override
196 public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
197 UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
198 for(UserInfo userInfo : userManager.getUsers()) {
199 enablePackageForUser(packageName, enable, userInfo.id);
200 }
201 }
202
203 @Override
204 public void enablePackageForUser(String packageName, boolean enable, int userId) {
205 try {
206 AppGlobals.getPackageManager().setApplicationEnabledSetting(
207 packageName,
208 enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT :
209 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0,
210 userId, null);
211 } catch (RemoteException e) {
212 Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e);
213 }
214 }
215
216 @Override
217 public boolean systemIsDebuggable() {
218 return Build.IS_DEBUGGABLE;
219 }
220
221 @Override
222 public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
223 throws NameNotFoundException {
224 PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
225 return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
226 }
227
228 // flags declaring we want extra info from the package manager for webview providers
229 private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
230 | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
Gustav Sennton8b179262016-03-14 11:31:14 +0000231}