Merge "Support dnd condition in Settings"
diff --git a/api/system-current.txt b/api/system-current.txt
index 332a516..492d6a9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -46479,8 +46479,6 @@
method public static android.content.pm.PackageInfo getLoadedPackageInfo();
method public static java.lang.String getWebViewPackageName();
method public static int loadWebViewNativeLibraryFromPackage(java.lang.String);
- method public static void onWebViewUpdateInstalled();
- method public static void prepareWebViewInSystemServer();
method public static void prepareWebViewInZygote();
field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
@@ -46489,7 +46487,9 @@
field public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; // 0x6
field public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; // 0x5
field public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; // 0x3
+ field public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9; // 0x9
field public static final int LIBLOAD_SUCCESS = 0; // 0x0
+ field public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8; // 0x8
field public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; // 0x1
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4cb2619..f11bf742 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1558,6 +1558,15 @@
return true;
}
+ case KILL_PACKAGE_DEPENDENTS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String packageName = data.readString();
+ int userId = data.readInt();
+ killPackageDependents(packageName, userId);
+ reply.writeNoException();
+ return true;
+ }
+
case FORCE_STOP_PACKAGE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String packageName = data.readString();
@@ -4736,6 +4745,18 @@
reply.recycle();
}
+ public void killPackageDependents(String packageName, int userId) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(packageName);
+ data.writeInt(userId);
+ mRemote.transact(KILL_PACKAGE_DEPENDENTS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
public void forceStopPackage(String packageName, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index eb8d6bc..64c69af 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -259,6 +259,7 @@
public void killBackgroundProcesses(final String packageName, int userId)
throws RemoteException;
public void killAllBackgroundProcesses() throws RemoteException;
+ public void killPackageDependents(final String packageName, int userId) throws RemoteException;
public void forceStopPackage(final String packageName, int userId) throws RemoteException;
// Note: probably don't want to allow applications access to these.
@@ -912,4 +913,5 @@
int UNLOCK_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 351;
int IN_MULTI_WINDOW_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 352;
int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
+ int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 74fd8cd..a1e5510 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5749,6 +5749,13 @@
"camera_double_tap_power_gesture_disabled";
/**
+ * Name of the package used as WebView provider (if unset the provider is instead determined
+ * by the system).
+ * @hide
+ */
+ public static final String WEBVIEW_PROVIDER = "webview_provider";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index a77459b..89d5d69 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -16,6 +16,10 @@
package android.webkit;
+import android.content.pm.PackageInfo;
+import android.webkit.WebViewProviderInfo;
+import android.webkit.WebViewProviderResponse;
+
/**
* Private service to wait for the updatable WebView to be ready for use.
* @hide
@@ -25,12 +29,28 @@
/**
* Used by the relro file creator to notify the service that it's done.
*/
- void notifyRelroCreationCompleted(boolean is64Bit, boolean success);
+ void notifyRelroCreationCompleted();
/**
* Used by WebViewFactory to block loading of WebView code until
- * preparations are complete.
+ * preparations are complete. Returns the package used as WebView provider.
*/
- void waitForRelroCreationCompleted(boolean is64Bit);
+ WebViewProviderResponse waitForAndGetProvider();
+ /**
+ * DevelopmentSettings uses this to notify WebViewUpdateService that a
+ * new provider has been selected by the user.
+ */
+ void changeProviderAndSetting(String newProvider);
+
+ /**
+ * DevelopmentSettings uses this to get the current available WebView
+ * providers (to display as choices to the user).
+ */
+ WebViewProviderInfo[] getValidWebViewPackages();
+
+ /**
+ * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
+ */
+ String getCurrentWebViewPackageName();
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 229011d..01d1566 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -24,6 +24,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
@@ -31,20 +32,27 @@
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import dalvik.system.VMRuntime;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import org.xmlpull.v1.XmlPullParserException;
+
/**
* Top level factory, used creating all the main WebView implementation classes.
*
@@ -83,6 +91,8 @@
public static final int LIBLOAD_SUCCESS = 0;
public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1;
public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2;
+
+ // error codes for waiting for WebView preparation
public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3;
public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4;
@@ -91,57 +101,95 @@
public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6;
public static final int LIBLOAD_FAILED_JNI_CALL = 7;
- private static class MissingWebViewPackageException extends AndroidRuntimeException {
+ // more error codes for waiting for WebView preparation
+ public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8;
+ public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9;
+
+ private static String getWebViewPreparationErrorReason(int error) {
+ switch (error) {
+ case LIBLOAD_FAILED_WAITING_FOR_RELRO:
+ return "Time out waiting for Relro files being created";
+ case LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES:
+ return "No WebView installed";
+ case LIBLOAD_WEBVIEW_BEING_REPLACED:
+ return "Time out waiting for WebView to be replaced";
+ case LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN:
+ return "Crashed for unknown reason";
+ }
+ return "Unknown";
+ }
+
+ /**
+ * @hide
+ */
+ public static class MissingWebViewPackageException extends AndroidRuntimeException {
public MissingWebViewPackageException(String message) { super(message); }
public MissingWebViewPackageException(Exception e) { super(e); }
}
- /** @hide */
- public static String[] getWebViewPackageNames() {
- return AppGlobals.getInitialApplication().getResources().getStringArray(
- com.android.internal.R.array.config_webViewPackageNames);
+ private static String TAG_START = "webviewproviders";
+ private static String TAG_WEBVIEW_PROVIDER = "webviewprovider";
+ private static String TAG_PACKAGE_NAME = "packageName";
+ private static String TAG_DESCRIPTION = "description";
+ private static String TAG_SIGNATURE = "signature";
+
+ /**
+ * Returns all packages declared in the framework resources as potential WebView providers.
+ * @hide
+ * */
+ public static WebViewProviderInfo[] getWebViewPackages() {
+ XmlResourceParser parser = null;
+ List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
+ try {
+ parser = AppGlobals.getInitialApplication().getResources().getXml(
+ com.android.internal.R.xml.config_webview_packages);
+ XmlUtils.beginDocument(parser, TAG_START);
+ while(true) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals(TAG_WEBVIEW_PROVIDER)) {
+ String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
+ if (packageName == null) {
+ throw new MissingWebViewPackageException(
+ "WebView provider in framework resources missing package name");
+ }
+ String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
+ if (description == null) {
+ throw new MissingWebViewPackageException(
+ "WebView provider in framework resources missing description");
+ }
+ String signature = parser.getAttributeValue(null, TAG_SIGNATURE);
+ webViewProviders.add(
+ new WebViewProviderInfo(packageName, description, signature));
+ }
+ else {
+ Log.e(LOGTAG, "Found an element that is not a webview provider");
+ }
+ }
+ } catch(XmlPullParserException e) {
+ throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+ } catch(IOException e) {
+ throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
}
+
// TODO (gsennton) remove when committing webview xts test change
public static String getWebViewPackageName() {
- String[] webViewPackageNames = getWebViewPackageNames();
- return webViewPackageNames[webViewPackageNames.length-1];
+ WebViewProviderInfo[] providers = getWebViewPackages();
+ return providers[0].packageName;
}
/**
- * Return the package info of the first package in the webview priority list that contains
- * webview.
- *
* @hide
*/
- public static PackageInfo findPreferredWebViewPackage() {
- PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
-
- for (String packageName : getWebViewPackageNames()) {
- try {
- PackageInfo packageInfo = pm.getPackageInfo(packageName,
- PackageManager.GET_META_DATA);
- ApplicationInfo applicationInfo = packageInfo.applicationInfo;
-
- // If the correct flag is set the package contains webview.
- if (getWebViewLibrary(applicationInfo) != null) {
- return packageInfo;
- }
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
- throw new MissingWebViewPackageException("Could not find a loadable WebView package");
- }
-
- // throws MissingWebViewPackageException
- private static ApplicationInfo getWebViewApplicationInfo() {
- if (sPackageInfo == null)
- return findPreferredWebViewPackage().applicationInfo;
- else
- return sPackageInfo.applicationInfo;
- }
-
- private static String getWebViewLibrary(ApplicationInfo ai) {
+ public static String getWebViewLibrary(ApplicationInfo ai) {
if (ai.metaData != null)
return ai.metaData.getString("com.android.webview.WebViewLibrary");
return null;
@@ -156,16 +204,14 @@
* name is the same as the one providing the webview.
*/
public static int loadWebViewNativeLibraryFromPackage(String packageName) {
- try {
- sPackageInfo = findPreferredWebViewPackage();
- } catch (MissingWebViewPackageException e) {
- return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
+ int ret = waitForProviderAndSetPackageInfo();
+ if (ret != LIBLOAD_SUCCESS) {
+ return ret;
}
+ if (!sPackageInfo.packageName.equals(packageName))
+ return LIBLOAD_WRONG_PACKAGE_NAME;
- if (packageName != null && packageName.equals(sPackageInfo.packageName)) {
- return loadNativeLibrary();
- }
- return LIBLOAD_WRONG_PACKAGE_NAME;
+ return loadNativeLibrary();
}
static WebViewFactoryProvider getProvider() {
@@ -207,17 +253,45 @@
private static Class<WebViewFactoryProvider> getProviderClass() {
try {
// First fetch the package info so we can log the webview package version.
- sPackageInfo = findPreferredWebViewPackage();
+ int res = waitForProviderAndSetPackageInfo();
+ if (res != LIBLOAD_SUCCESS) {
+ throw new MissingWebViewPackageException(
+ "Failed to load WebView provider, error: "
+ + getWebViewPreparationErrorReason(res));
+ }
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
+ Application initialApplication = AppGlobals.getInitialApplication();
+ Context webViewContext = null;
+ try {
+ // Construct a package context to load the Java code into the current app.
+ // This is done as early as possible since by constructing a package context we
+ // register the WebView package as a dependency for the current application so that
+ // when the WebView package is updated this application will be killed.
+ webViewContext = initialApplication.createPackageContext(
+ sPackageInfo.packageName,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new MissingWebViewPackageException(e);
+ }
+
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
loadNativeLibrary();
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
- return getChromiumProviderClass();
+ initialApplication.getAssets().addAssetPathAsSharedLibrary(
+ webViewContext.getApplicationInfo().sourceDir);
+ ClassLoader clazzLoader = webViewContext.getClassLoader();
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
+ try {
+ return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
+ true, clazzLoader);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading provider", e);
throw new AndroidRuntimeException(e);
@@ -239,30 +313,6 @@
}
}
- // throws MissingWebViewPackageException
- private static Class<WebViewFactoryProvider> getChromiumProviderClass()
- throws ClassNotFoundException {
- Application initialApplication = AppGlobals.getInitialApplication();
- try {
- // Construct a package context to load the Java code into the current app.
- Context webViewContext = initialApplication.createPackageContext(
- sPackageInfo.packageName,
- Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
- initialApplication.getAssets().addAssetPathAsSharedLibrary(
- webViewContext.getApplicationInfo().sourceDir);
- ClassLoader clazzLoader = webViewContext.getClassLoader();
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
- try {
- return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
- clazzLoader);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new MissingWebViewPackageException(e);
- }
- }
-
/**
* Perform any WebView loading preparations that must happen in the zygote.
* Currently, this means allocating address space to load the real JNI library later.
@@ -289,44 +339,34 @@
}
}
- /**
- * Perform any WebView loading preparations that must happen at boot from the system server,
- * after the package manager has started or after an update to the webview is installed.
- * This must be called in the system server.
- * Currently, this means spawning the child processes which will create the relro files.
- */
- public static void prepareWebViewInSystemServer() {
- String[] nativePaths = null;
- try {
- nativePaths = getWebViewNativeLibraryPaths();
- } catch (Throwable t) {
- // Log and discard errors at this stage as we must not crash the system server.
- Log.e(LOGTAG, "error preparing webview native library", t);
- }
- prepareWebViewInSystemServer(nativePaths);
- }
-
- private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
+ private static int prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
if (DEBUG) Log.v(LOGTAG, "creating relro files");
+ int numRelros = 0;
// We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
// unexpected values will be handled there to ensure that we trigger notifying any process
- // waiting on relreo creation.
+ // waiting on relro creation.
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
createRelroFile(false /* is64Bit */, nativeLibraryPaths);
+ numRelros++;
}
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
createRelroFile(true /* is64Bit */, nativeLibraryPaths);
+ numRelros++;
}
+ return numRelros;
}
- public static void onWebViewUpdateInstalled() {
+ /**
+ * @hide
+ */
+ public static int onWebViewProviderChanged(PackageInfo packageInfo) {
String[] nativeLibs = null;
try {
- nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
+ nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo);
if (nativeLibs != null) {
long newVmSize = 0L;
@@ -373,7 +413,7 @@
// Log and discard errors at this stage as we must not crash the system server.
Log.e(LOGTAG, "error preparing webview native library", t);
}
- prepareWebViewInSystemServer(nativeLibs);
+ return prepareWebViewInSystemServer(nativeLibs);
}
// throws MissingWebViewPackageException
@@ -397,8 +437,8 @@
}
// throws MissingWebViewPackageException
- private static String[] getWebViewNativeLibraryPaths() {
- ApplicationInfo ai = getWebViewApplicationInfo();
+ private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo) {
+ ApplicationInfo ai = packageInfo.applicationInfo;
final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
String path32;
@@ -460,7 +500,7 @@
public void run() {
try {
Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
- getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
+ getUpdateService().notifyRelroCreationCompleted();
} catch (RemoteException e) {
Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
}
@@ -508,7 +548,7 @@
} finally {
// We must do our best to always notify the update service, even if something fails.
try {
- getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
+ getUpdateService().notifyRelroCreationCompleted();
} catch (RemoteException e) {
Log.e(LOGTAG, "error notifying update service", e);
}
@@ -521,35 +561,38 @@
}
}
+ private static int waitForProviderAndSetPackageInfo() {
+ WebViewProviderResponse response = null;
+ try {
+ response =
+ getUpdateService().waitForAndGetProvider();
+ if (response.status == WebViewFactory.LIBLOAD_SUCCESS)
+ sPackageInfo = response.packageInfo;
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "error waiting for relro creation", e);
+ return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
+ }
+ return response.status;
+ }
+
+ // Assumes that we have waited for relro creation and set sPackageInfo
private static int loadNativeLibrary() {
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
}
- try {
- getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
- } catch (RemoteException e) {
- Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
- return LIBLOAD_FAILED_WAITING_FOR_RELRO;
+ String[] args = getWebViewNativeLibraryPaths(sPackageInfo);
+ int result = nativeLoadWithRelroFile(args[0] /* path32 */,
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ if (result != LIBLOAD_SUCCESS) {
+ Log.w(LOGTAG, "failed to load with relro file, proceeding without");
+ } else if (DEBUG) {
+ Log.v(LOGTAG, "loaded with relro file");
}
-
- try {
- String[] args = getWebViewNativeLibraryPaths();
- int result = nativeLoadWithRelroFile(args[0] /* path32 */,
- args[1] /* path64 */,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (result != LIBLOAD_SUCCESS) {
- Log.w(LOGTAG, "failed to load with relro file, proceeding without");
- } else if (DEBUG) {
- Log.v(LOGTAG, "loaded with relro file");
- }
- return result;
- } catch (MissingWebViewPackageException e) {
- Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
- return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
- }
+ return result;
}
private static IWebViewUpdateService getUpdateService() {
diff --git a/core/java/android/webkit/WebViewProviderInfo.aidl b/core/java/android/webkit/WebViewProviderInfo.aidl
new file mode 100644
index 0000000..82e5a79
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+parcelable WebViewProviderInfo;
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
new file mode 100644
index 0000000..d5e3a230
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.app.AppGlobals;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AndroidRuntimeException;
+import android.util.Base64;
+
+import java.util.Arrays;
+
+/** @hide */
+public class WebViewProviderInfo implements Parcelable {
+
+ /**
+ * @hide
+ */
+ public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
+ public WebViewPackageNotFoundException(String message) { super(message); }
+ public WebViewPackageNotFoundException(Exception e) { super(e); }
+ }
+
+ public WebViewProviderInfo(String packageName, String description, String signature) {
+ this.packageName = packageName;
+ this.description = description;
+ this.signature = signature;
+ }
+
+ private boolean hasValidSignature() {
+ if (Build.IS_DEBUGGABLE)
+ return true;
+ Signature[] packageSignatures;
+ try {
+ // If no signature is declared, instead check whether the package is included in the
+ // system.
+ if (signature == null)
+ return getPackageInfo().applicationInfo.isSystemApp();
+
+ packageSignatures = getPackageInfo().signatures;
+ } catch (WebViewPackageNotFoundException e) {
+ return false;
+ }
+ if (packageSignatures.length != 1)
+ return false;
+ final byte[] releaseSignature = Base64.decode(signature, Base64.DEFAULT);
+ return Arrays.equals(releaseSignature, packageSignatures[0].toByteArray());
+ }
+
+ /**
+ * Returns whether this provider is valid for use as a WebView provider.
+ */
+ public boolean isValidProvider() {
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = getPackageInfo().applicationInfo;
+ } catch (WebViewPackageNotFoundException e) {
+ return false;
+ }
+ if (hasValidSignature() && WebViewFactory.getWebViewLibrary(applicationInfo) != null) {
+ return true;
+ }
+ return false;
+ }
+
+ public PackageInfo getPackageInfo() {
+ if (packageInfo == null) {
+ try {
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new WebViewPackageNotFoundException(e);
+ }
+ }
+ return packageInfo;
+ }
+
+ // aidl stuff
+ public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
+ new Parcelable.Creator<WebViewProviderInfo>() {
+ public WebViewProviderInfo createFromParcel(Parcel in) {
+ return new WebViewProviderInfo(in);
+ }
+
+ public WebViewProviderInfo[] newArray(int size) {
+ return new WebViewProviderInfo[size];
+ }
+ };
+
+ private WebViewProviderInfo(Parcel in) {
+ packageName = in.readString();
+ description = in.readString();
+ signature = in.readString();
+ packageInfo = null;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(packageName);
+ out.writeString(description);
+ out.writeString(signature);
+ }
+
+ // fields read from framework resource
+ public String packageName;
+ public String description;
+
+ private String signature;
+
+ private PackageInfo packageInfo;
+ // flags declaring we want extra info from the package manager
+ private final static int PACKAGE_FLAGS =
+ PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNATURES;
+}
+
diff --git a/core/java/android/webkit/WebViewProviderResponse.aidl b/core/java/android/webkit/WebViewProviderResponse.aidl
new file mode 100644
index 0000000..9c884cc
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+parcelable WebViewProviderResponse;
diff --git a/core/java/android/webkit/WebViewProviderResponse.java b/core/java/android/webkit/WebViewProviderResponse.java
new file mode 100644
index 0000000..f5e09e2
--- /dev/null
+++ b/core/java/android/webkit/WebViewProviderResponse.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.content.pm.PackageInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class WebViewProviderResponse implements Parcelable {
+
+ public WebViewProviderResponse(PackageInfo packageInfo, int status) {
+ this.packageInfo = packageInfo;
+ this.status = status;
+ }
+
+ // aidl stuff
+ public static final Parcelable.Creator<WebViewProviderResponse> CREATOR =
+ new Parcelable.Creator<WebViewProviderResponse>() {
+ public WebViewProviderResponse createFromParcel(Parcel in) {
+ return new WebViewProviderResponse(in);
+ }
+
+ public WebViewProviderResponse[] newArray(int size) {
+ return new WebViewProviderResponse[size];
+ }
+ };
+
+ private WebViewProviderResponse(Parcel in) {
+ packageInfo = in.readTypedObject(PackageInfo.CREATOR);
+ status = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeTypedObject(packageInfo, flags);
+ out.writeInt(status);
+ }
+
+ PackageInfo packageInfo;
+ int status;
+}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 8186378..d23f26d 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -145,8 +145,9 @@
native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
- private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
- VM_HOOKS.postForkChild(debugFlags, instructionSet);
+ private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
+ String instructionSet) {
+ VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 73c7487..96d150b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -581,7 +581,7 @@
UnsetSigChldHandler();
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
- is_system_server ? NULL : instructionSet);
+ is_system_server, instructionSet);
if (env->ExceptionCheck()) {
RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
}
@@ -652,7 +652,7 @@
int register_com_android_internal_os_Zygote(JNIEnv* env) {
gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName));
gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
- "(ILjava/lang/String;)V");
+ "(IZLjava/lang/String;)V");
return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 97c0e07..e2b1dbb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2154,11 +2154,6 @@
string that's stored in 8-bit unpacked format) characters.-->
<bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
- <!-- List of package names (ordered by preference) providing WebView implementations. -->
- <string-array name="config_webViewPackageNames" translatable="false">
- <item>com.android.webview</item>
- </string-array>
-
<!-- If EMS is not supported, framework breaks down EMS into single segment SMS
and adds page info " x/y". This config is used to set which carrier doesn't
support EMS and whether page info should be added at the beginning or the end.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6367d37..bf758c2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2018,7 +2018,7 @@
<java-symbol type="attr" name="actionModeWebSearchDrawable" />
<java-symbol type="string" name="websearch" />
<java-symbol type="drawable" name="ic_media_video_poster" />
- <java-symbol type="array" name="config_webViewPackageNames" />
+ <java-symbol type="xml" name="config_webview_packages" />
<!-- From SubtitleView -->
<java-symbol type="dimen" name="subtitle_corner_radius" />
diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
new file mode 100644
index 0000000..6f9c58d
--- /dev/null
+++ b/core/res/res/xml/config_webview_packages.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<webviewproviders>
+ <!-- The default WebView implementation -->
+ <webviewprovider description="Android WebView" packageName="com.android.webview" />
+</webviewproviders>
diff --git a/packages/FusedLocation/res/values-de/strings.xml b/packages/FusedLocation/res/values-de/strings.xml
index d7e5faa..5c846d8 100644
--- a/packages/FusedLocation/res/values-de/strings.xml
+++ b/packages/FusedLocation/res/values-de/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbestimmung"</string>
+ <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbest."</string>
</resources>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 51c0281..0e91fdd 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
@@ -35,9 +34,10 @@
import com.android.internal.annotations.VisibleForTesting;
-import java.io.File;
import java.io.FileNotFoundException;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
/**
* Database for MTP objects.
@@ -397,6 +397,7 @@
values.putNull(COLUMN_OBJECT_HANDLE);
values.putNull(COLUMN_PARENT_DOCUMENT_ID);
values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
+ values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_STORAGE);
values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources));
values.putNull(Document.COLUMN_SUMMARY);
@@ -436,6 +437,7 @@
values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
values.put(COLUMN_PARENT_DOCUMENT_ID, parentId);
values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
+ values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_OBJECT);
values.put(Document.COLUMN_MIME_TYPE, mimeType);
values.put(Document.COLUMN_DISPLAY_NAME, info.getName());
values.putNull(Document.COLUMN_SUMMARY);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index 0ead2d5..72bd6ee 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -49,6 +49,7 @@
static final String COLUMN_STORAGE_ID = "storage_id";
static final String COLUMN_OBJECT_HANDLE = "object_handle";
static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
+ static final String COLUMN_DOCUMENT_TYPE = "document_type";
static final String COLUMN_ROW_STATE = "row_state";
/**
@@ -83,6 +84,23 @@
*/
static final int MAP_BY_NAME = 1;
+ /**
+ * Document that represents a MTP device.
+ * Note we have "device" document only when the device has multiple storage volumes. Otherwise
+ * we regard the single "storage" document as root.
+ */
+ static final int DOCUMENT_TYPE_DEVICE = 0;
+
+ /**
+ * Document that represents a MTP storage.
+ */
+ static final int DOCUMENT_TYPE_STORAGE = 1;
+
+ /**
+ * Document that represents a MTP object.
+ */
+ static final int DOCUMENT_TYPE_OBJECT = 2;
+
static final String SELECTION_DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID + " = ?";
static final String SELECTION_ROOT_ID = Root.COLUMN_ROOT_ID + " = ?";
static final String SELECTION_ROOT_DOCUMENTS =
@@ -98,6 +116,7 @@
COLUMN_OBJECT_HANDLE + " INTEGER," +
COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
COLUMN_ROW_STATE + " INTEGER NOT NULL," +
+ COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," +
Document.COLUMN_MIME_TYPE + " TEXT," +
Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
Document.COLUMN_SUMMARY + " TEXT," +
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 67b0672..8166de1 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -42,7 +42,8 @@
DocumentsContract.Document.COLUMN_LAST_MODIFIED,
DocumentsContract.Document.COLUMN_ICON,
DocumentsContract.Document.COLUMN_FLAGS,
- DocumentsContract.Document.COLUMN_SIZE
+ DocumentsContract.Document.COLUMN_SIZE,
+ MtpDatabaseConstants.COLUMN_DOCUMENT_TYPE
};
private final TestResources resources = new TestResources();
@@ -83,6 +84,8 @@
assertEquals("icon", R.drawable.ic_root_mtp, cursor.getInt(8));
assertEquals("flag", 0, cursor.getInt(9));
assertEquals("size", 1000, cursor.getInt(10));
+ assertEquals(
+ "documentType", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, cursor.getInt(11));
cursor.moveToNext();
assertEquals("documentId", 2, cursor.getInt(0));
@@ -178,6 +181,8 @@
DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
cursor.getInt(9));
assertEquals("size", 1024, cursor.getInt(10));
+ assertEquals(
+ "documentType", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, cursor.getInt(11));
cursor.moveToNext();
assertEquals("documentId", 2, cursor.getInt(0));
@@ -195,6 +200,8 @@
DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
cursor.getInt(9));
assertEquals("size", 2 * 1024 * 1024, cursor.getInt(10));
+ assertEquals(
+ "documentType", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, cursor.getInt(11));
cursor.moveToNext();
assertEquals("documentId", 3, cursor.getInt(0));
@@ -212,6 +219,8 @@
DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
cursor.getInt(9));
assertEquals("size", 3 * 1024 * 1024, cursor.getInt(10));
+ assertEquals(
+ "documentType", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, cursor.getInt(11));
cursor.close();
}
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 82e8dc6..1033bb19 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -141,7 +141,7 @@
<string name="development_settings_not_available" msgid="4308569041701535607">"Bu foydalanuvchiga dasturchi imkoniyatlari taqdim etilmagan"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"Ushbu foydalanuvchi uchun VPN sozlamalari mavjud emas"</string>
<string name="tethering_settings_not_available" msgid="6765770438438291012">"Ushbu foydalanuvchi uchun Modem rejimi sozlamalari mavjud emas"</string>
- <string name="apn_settings_not_available" msgid="7873729032165324000">"Ushbu foydalanuvchi uchun Ulanish nuqtasi nomi (APN) sozlamalari mavjud emas"</string>
+ <string name="apn_settings_not_available" msgid="7873729032165324000">"Ushbu foydalanuvchi uchun Internetga kirish nuqtasi (APN) sozlamalari mavjud emas"</string>
<string name="enable_adb" msgid="7982306934419797485">"USB orqali nosozliklarni tuzatish"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"USB orqali kompyuterga ulanganda tuzatish rejimi yoqilsin"</string>
<string name="clear_adb_keys" msgid="4038889221503122743">"USB orqali nosozliklarni tuzatishni taqiqlash"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 55bd08a..7e22881 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -675,6 +675,11 @@
<!-- Sound & display settings screen, theme setting value to automatically switch between a light- or dark-colored user interface [CHAR LIMIT=30] -->
<string name="night_mode_auto">Automatic</string>
+ <!-- Developer settings: select WebView provider title -->
+ <string name="select_webview_provider_title">WebView implementation</string>
+ <!-- Developer settings: select WebView provider dialog title -->
+ <string name="select_webview_provider_dialog_title">Set WebView implementation</string>
+
<!-- Developer settings screen, convert userdata to file encryption option name -->
<string name="convert_to_file_encryption">Convert to file encryption</string>
<!-- Developer settings screen, convert userdata to file encryption summary when option is available -->
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index 7d37137..c871727 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -124,6 +124,16 @@
if (gotIt) {
Log.v(TAG, "Found activity " + name + ", it's the default action");
+ // Clicks the "Just Once" button.
+ gotIt = mDevice
+ .wait(Until.hasObject(By.res("android", "button_once")), mTimeout);
+ assertTrue("'Just Once' button not visible yet", gotIt);
+
+ UiObject justOnce = mDevice
+ .findObject(new UiSelector().resourceId("android:id/button_once"));
+ assertTrue("'Just Once' button not found", justOnce.exists());
+
+ click(justOnce, "Just Once");
} else {
// Since it's not, need to find it in the scrollable list...
Log.v(TAG, "Activity " + name + " is not default action");
@@ -140,16 +150,5 @@
// ... then select it.
click(activity, name);
}
-
- // Then clicks the "Just Once" button.
- gotIt = mDevice
- .wait(Until.hasObject(By.res("android", "button_once")), mTimeout);
- assertTrue("'Just Once' button not visible yet", gotIt);
-
- UiObject justOnce = mDevice
- .findObject(new UiSelector().resourceId("android:id/button_once"));
- assertTrue("'Just Once' button not found", justOnce.exists());
-
- click(justOnce, "Just Once");
}
}
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 5acd0ef..8d3da117 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -217,7 +217,7 @@
<string name="accessibility_casting_turned_off" msgid="1430668982271976172">"העברת המסך הופסקה."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"מצב עבודה כבוי."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"מצב עבודה מופעל."</string>
- <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"מצב עבודה כובה."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"מצב עבודה הושבת."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"מצב עבודה הופעל."</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"בהירות תצוגה"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"השימוש בנתוני 2G-3G מושהה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1edfd5c..ae57a32 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -161,7 +161,7 @@
<string name="accessibility_ringer_silent" msgid="9061243307939135383">"マナーモード着信。"</string>
<!-- no translation found for accessibility_casting (6887382141726543668) -->
<skip />
- <string name="accessibility_work_mode" msgid="2478631941714607225">"職場モード"</string>
+ <string name="accessibility_work_mode" msgid="2478631941714607225">"Work モード"</string>
<string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>を削除します。"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>は削除されました。"</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
@@ -213,10 +213,10 @@
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"モバイルアクセスポイントをOFFにしました。"</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"モバイルアクセスポイントをONにしました。"</string>
<string name="accessibility_casting_turned_off" msgid="1430668982271976172">"画面のキャストが停止しました。"</string>
- <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"職場モードがオフです。"</string>
- <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"職場モードがオンです。"</string>
- <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"職場モードをオフにしました。"</string>
- <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"職場モードをオンにしました。"</string>
+ <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Work モードがオフです。"</string>
+ <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Work モードがオンです。"</string>
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Work モードをオフにしました。"</string>
+ <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Work モードをオンにしました。"</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"ディスプレイの明るさ"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G~3Gデータは一時停止中です"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
@@ -294,7 +294,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g>使用中"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
- <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"職場モード"</string>
+ <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work モード"</string>
<string name="recents_empty_message" msgid="8682129509540827999">"ここに最近の画面が表示されます"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"画面固定"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 9cccec4..35a6e1b 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -270,7 +270,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ບໍ່ມີເຄືອຂ່າຍ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ປິດ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"ບໍ່ມີເຄືອຂ່າຍ Wi-Fi ຢູ່"</string>
- <string name="quick_settings_cast_title" msgid="7709016546426454729">"ຄາສທ໌"</string>
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ການສົ່ງສັນຍານ"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"ກຳລັງສົ່ງສັນຍານ"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ອຸປະກອນບໍ່ມີຊື່"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ພ້ອມສົ່ງສັນຍານແລ້ວ"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 9a22b2c..9a0a0c0 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -213,8 +213,8 @@
<string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Tempat liputan mudah alih bergerak dimatikan."</string>
<string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Tempat liputan mudah alih bergerak dihidupkan."</string>
<string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Penghantaran skrin dihentikan."</string>
- <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Mod kerja dimatikan."</string>
- <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mod kerja dihidupkan."</string>
+ <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Mod kerja mati."</string>
+ <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Mod kerja hidup."</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Mod kerja dimatikan."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Mod kerja dihidupkan."</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan paparan"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 60bedae..512effa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -93,7 +93,8 @@
public TaskKey key;
public TaskGrouping group;
- public int taskAffiliation;
+ // The taskAffiliationId is the task id of the parent task or itself if it is not affiliated with any task
+ public int taskAffiliationId;
public int taskAffiliationColor;
public boolean isLaunchTarget;
public Drawable applicationIcon;
@@ -123,7 +124,7 @@
boolean isInAffiliationGroup = (taskAffiliation != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
this.key = key;
- this.taskAffiliation = taskAffiliation;
+ this.taskAffiliationId = taskAffiliation;
this.taskAffiliationColor = taskAffiliationColor;
this.activityLabel = activityTitle;
this.contentDescription = contentDescription;
@@ -142,7 +143,7 @@
/** Copies the other task. */
public void copyFrom(Task o) {
this.key = o.key;
- this.taskAffiliation = o.taskAffiliation;
+ this.taskAffiliationId = o.taskAffiliationId;
this.taskAffiliationColor = o.taskAffiliationColor;
this.activityLabel = o.activityLabel;
this.contentDescription = o.contentDescription;
@@ -206,6 +207,13 @@
}
}
+ /**
+ * Returns whether this task is affiliated with another task.
+ */
+ public boolean isAffiliatedTask() {
+ return key.id != taskAffiliationId;
+ }
+
@Override
public boolean equals(Object o) {
// Check that the id matches
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 7a98393..13ab392 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -23,6 +23,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
+import android.util.SparseArray;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
@@ -50,7 +51,7 @@
*/
interface TaskFilter {
/** Returns whether the filter accepts the specified task */
- public boolean acceptTask(Task t, int index);
+ public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
}
/**
@@ -157,10 +158,17 @@
private void updateFilteredTasks() {
mFilteredTasks.clear();
if (mFilter != null) {
+ // Create a sparse array from task id to Task
+ SparseArray<Task> taskIdMap = new SparseArray<>();
int taskCount = mTasks.size();
for (int i = 0; i < taskCount; i++) {
Task t = mTasks.get(i);
- if (mFilter.acceptTask(t, i)) {
+ taskIdMap.put(t.key.id, t);
+ }
+
+ for (int i = 0; i < taskCount; i++) {
+ Task t = mTasks.get(i);
+ if (mFilter.acceptTask(taskIdMap, t, i)) {
mFilteredTasks.add(t);
}
}
@@ -318,13 +326,29 @@
// Ensure that we only show non-docked tasks
mStackTaskList.setFilter(new TaskFilter() {
@Override
- public boolean acceptTask(Task t, int index) {
+ public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
+ if (t.isAffiliatedTask()) {
+ // If this task is affiliated with another parent in the stack, then the historical state of this
+ // task depends on the state of the parent task
+ Task parentTask = taskIdMap.get(t.taskAffiliationId);
+ if (parentTask != null) {
+ t = parentTask;
+ }
+ }
return !t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
}
});
mHistoryTaskList.setFilter(new TaskFilter() {
@Override
- public boolean acceptTask(Task t, int index) {
+ public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
+ if (t.isAffiliatedTask()) {
+ // If this task is affiliated with another parent in the stack, then the historical state of this
+ // task depends on the state of the parent task
+ Task parentTask = taskIdMap.get(t.taskAffiliationId);
+ if (parentTask != null) {
+ t = parentTask;
+ }
+ }
return t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
}
});
@@ -585,8 +609,8 @@
taskGrouping2.latestActiveTimeInGroup);
}
});
- // Sort group tasks by increasing firstActiveTime of the task, and also build a new list of
- // tasks
+ // Sort group tasks by increasing firstActiveTime of the task, and also build a new list
+ // of tasks
int taskIndex = 0;
int groupCount = mGroups.size();
for (int i = 0; i < groupCount; i++) {
@@ -607,13 +631,13 @@
mStackTaskList.set(tasks);
} else {
// Create the task groups
- HashMap<Task.TaskKey, Task> tasksMap = new HashMap<Task.TaskKey, Task>();
+ HashMap<Task.TaskKey, Task> tasksMap = new HashMap<>();
ArrayList<Task> tasks = mStackTaskList.getTasks();
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task t = tasks.get(i);
TaskGrouping group;
- int affiliation = t.taskAffiliation > 0 ? t.taskAffiliation :
+ int affiliation = t.taskAffiliationId > 0 ? t.taskAffiliationId :
IndividualTaskIdOffset + t.key.id;
if (mAffinitiesGroups.containsKey(affiliation)) {
group = getGroupWithAffiliation(affiliation);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 22d30df..be1fd58 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5390,7 +5390,7 @@
return;
}
killPackageProcessesLocked(packageName, appId, userId,
- ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+ ProcessList.SERVICE_ADJ, false, true, true, false, true, "kill background");
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -5691,7 +5691,7 @@
private final boolean killPackageProcessesLocked(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
- boolean doit, boolean evenPersistent, String reason) {
+ boolean doit, boolean evenPersistent, boolean killPackageApp, String reason) {
ArrayList<ProcessRecord> procs = new ArrayList<>();
// Remove all processes this package may have touched: all with the
@@ -5740,7 +5740,7 @@
if (userId != UserHandle.USER_ALL && app.userId != userId) {
continue;
}
- if (!app.pkgList.containsKey(packageName) && !isDep) {
+ if ((!killPackageApp || !app.pkgList.containsKey(packageName)) && !isDep) {
continue;
}
}
@@ -5906,7 +5906,7 @@
}
boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
- ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
+ ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent, true,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
@@ -11819,7 +11819,7 @@
final long identity = Binder.clearCallingIdentity();
try {
killPackageProcessesLocked(null, appId, userId,
- ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true,
+ ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true, true,
reason != null ? reason : "kill uid");
} finally {
Binder.restoreCallingIdentity(identity);
@@ -20777,4 +20777,35 @@
}
}
}
+
+ /**
+ * Kill processes for the user with id userId and that depend on the package named packageName
+ */
+ @Override
+ public void killPackageDependents(String packageName, int userId) {
+ enforceCallingPermission(android.Manifest.permission.KILL_UID, "killPackageDependents()");
+ if (packageName == null) {
+ throw new NullPointerException("Cannot kill the dependents of a package without its name.");
+ }
+
+ long callingId = Binder.clearCallingIdentity();
+ IPackageManager pm = AppGlobals.getPackageManager();
+ int pkgUid = -1;
+ try {
+ pkgUid = pm.getPackageUid(packageName, userId);
+ } catch (RemoteException e) {
+ }
+ if (pkgUid == -1) {
+ throw new IllegalArgumentException("Cannot kill dependents of non-existing package " + packageName);
+ }
+ try {
+ synchronized(this) {
+ killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), userId,
+ ProcessList.FOREGROUND_APP_ADJ, false, true, true, false, false,
+ "dep: " + packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 11fdb92..459c47f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -523,7 +523,9 @@
case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
for (int type : mLocalDevices) {
HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
- localDevice.setAutoDeviceOff(enabled);
+ if (localDevice != null) {
+ localDevice.setAutoDeviceOff(enabled);
+ }
}
// No need to propagate to HAL.
break;
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 97713fc..7be0ead 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -16,18 +16,35 @@
package com.android.server.webkit;
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
import android.os.Binder;
import android.os.Process;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.util.AndroidRuntimeException;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
+import android.webkit.WebViewProviderInfo;
+import android.webkit.WebViewProviderResponse;
import android.webkit.WebViewFactory;
import com.android.server.SystemService;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
/**
* Private service to wait for the updatable WebView to be ready for use.
* @hide
@@ -35,12 +52,23 @@
public class WebViewUpdateService extends SystemService {
private static final String TAG = "WebViewUpdateService";
- private static final int WAIT_TIMEOUT_MS = 5000; // Same as KEY_DISPATCHING_TIMEOUT.
+ private static final int WAIT_TIMEOUT_MS = 4500; // KEY_DISPATCHING_TIMEOUT is 5000.
- private boolean mRelroReady32Bit = false;
- private boolean mRelroReady64Bit = false;
+ // Keeps track of the number of running relro creations
+ private int mNumRelroCreationsStarted = 0;
+ private int mNumRelroCreationsFinished = 0;
+ // Implies that we need to rerun relro creation because we are using an out-of-date package
+ private boolean mWebViewPackageDirty = false;
+ // Set to true when the current provider is being replaced
+ private boolean mCurrentProviderBeingReplaced = false;
+ private boolean mAnyWebViewInstalled = false;
- private String oldWebViewPackageName = null;
+ private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
+
+ // The WebView package currently in use (or the one we are preparing).
+ private PackageInfo mCurrentWebViewPackage = null;
+ // The WebView providers that are currently available.
+ private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
private BroadcastReceiver mWebViewUpdatedReceiver;
@@ -53,28 +81,69 @@
mWebViewUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
-
- // When a package is replaced we will receive two intents, one representing the
- // removal of the old package and one representing the addition of the new
- // package. We here ignore the intent representing the removed package to make
- // sure we don't change WebView provider twice.
+ // When a package is replaced we will receive two intents, one representing
+ // the removal of the old package and one representing the addition of the
+ // new package.
+ // In the case where we receive an intent to remove the old version of the
+ // package that is being replaced we set a flag here and early-out so that we
+ // don't change provider while replacing the current package (we will instead
+ // change provider when the new version of the package is being installed).
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
- && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
+ && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
+ synchronized(this) {
+ if (mCurrentWebViewPackage == null) return;
+
+ String webViewPackage = "package:" + mCurrentWebViewPackage.packageName;
+ if (webViewPackage.equals(intent.getDataString()))
+ mCurrentProviderBeingReplaced = true;
+ }
+
return;
}
- for (String packageName : WebViewFactory.getWebViewPackageNames()) {
- String webviewPackage = "package:" + packageName;
+ for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+ String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
- String usedPackageName =
- WebViewFactory.findPreferredWebViewPackage().packageName;
- // Only trigger update actions if the updated package is the one that
- // will be used, or the one that was in use before the update.
- if (packageName.equals(usedPackageName) ||
- packageName.equals(oldWebViewPackageName)) {
- onWebViewUpdateInstalled();
- oldWebViewPackageName = usedPackageName;
+ boolean updateWebView = false;
+ boolean removedOldPackage = false;
+ String oldProviderName = null;
+ PackageInfo newPackage = null;
+ synchronized(WebViewUpdateService.this) {
+ try {
+ updateValidWebViewPackages();
+ newPackage = findPreferredWebViewPackage();
+ if (mCurrentWebViewPackage != null)
+ oldProviderName = mCurrentWebViewPackage.packageName;
+ // Only trigger update actions if the updated package is the one
+ // that will be used, or the one that was in use before the
+ // update, or if we haven't seen a valid WebView package before.
+ updateWebView =
+ provider.packageName.equals(newPackage.packageName)
+ || provider.packageName.equals(oldProviderName)
+ || mCurrentWebViewPackage == null;
+ // We removed the old package if we received an intent to remove
+ // or replace the old package.
+ removedOldPackage =
+ provider.packageName.equals(oldProviderName);
+ if (updateWebView) {
+ onWebViewProviderChanged(newPackage);
+ }
+ } catch (WebViewFactory.MissingWebViewPackageException e) {
+ Slog.e(TAG, "Could not find valid WebView package to create " +
+ "relro with " + e);
+ }
+ }
+ if(updateWebView && !removedOldPackage && oldProviderName != null) {
+ // If the provider change is the result of adding or replacing a
+ // package that was not the previous provider then we must kill
+ // packages dependent on the old package ourselves. The framework
+ // only kills dependents of packages that are being removed.
+ try {
+ ActivityManagerNative.getDefault().killPackageDependents(
+ oldProviderName, getContext().getUserId());
+ } catch (RemoteException e) {
+ }
}
return;
}
@@ -90,14 +159,182 @@
publishBinderService("webviewupdate", new BinderService());
}
- private void onWebViewUpdateInstalled() {
- Slog.d(TAG, "WebView Package updated!");
-
- synchronized (this) {
- mRelroReady32Bit = false;
- mRelroReady64Bit = false;
+ /**
+ * Perform any WebView loading preparations that must happen at boot from the system server,
+ * after the package manager has started or after an update to the webview is installed.
+ * This must be called in the system server.
+ * Currently, this means spawning the child processes which will create the relro files.
+ */
+ public void prepareWebViewInSystemServer() {
+ try {
+ synchronized(this) {
+ updateValidWebViewPackages();
+ mCurrentWebViewPackage = findPreferredWebViewPackage();
+ onWebViewProviderChanged(mCurrentWebViewPackage);
+ }
+ } catch (Throwable t) {
+ // Log and discard errors at this stage as we must not crash the system server.
+ Slog.e(TAG, "error preparing webview provider from system server", t);
}
- WebViewFactory.onWebViewUpdateInstalled();
+ }
+
+
+ /**
+ * Change WebView provider and provider setting and kill packages using the old provider.
+ */
+ private void changeProviderAndSetting(String newProviderName) {
+ PackageInfo oldPackage = null;
+ PackageInfo newPackage = null;
+ synchronized(this) {
+ oldPackage = mCurrentWebViewPackage;
+ updateUserSetting(newProviderName);
+
+ try {
+ newPackage = findPreferredWebViewPackage();
+ if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
+ // If we don't perform the user change, revert the settings change.
+ updateUserSetting(newPackage.packageName);
+ return;
+ }
+ } catch (WebViewFactory.MissingWebViewPackageException e) {
+ Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView package "
+ + e);
+ // If we don't perform the user change but don't have an installed WebView package,
+ // we will have changed the setting and it will be used when a package is available.
+ return;
+ }
+ onWebViewProviderChanged(newPackage);
+ }
+ // Kill apps using the old provider
+ try {
+ if (oldPackage != null) {
+ ActivityManagerNative.getDefault().killPackageDependents(
+ oldPackage.packageName, getContext().getUserId());
+ }
+ } catch (RemoteException e) {
+ }
+ return;
+ }
+
+ /**
+ * This is called when we change WebView provider, either when the current provider is updated
+ * or a new provider is chosen / takes precedence.
+ */
+ private void onWebViewProviderChanged(PackageInfo newPackage) {
+ synchronized(this) {
+ mAnyWebViewInstalled = true;
+ // If we have changed provider then the replacement of the old provider is
+ // irrelevant - we can only have chosen a new provider if its package is available.
+ mCurrentProviderBeingReplaced = false;
+ if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
+ mCurrentWebViewPackage = newPackage;
+ updateUserSetting(newPackage.packageName);
+
+ // The relro creations might 'finish' (not start at all) before
+ // WebViewFactory.onWebViewProviderChanged which means we might not know the number
+ // of started creations before they finish.
+ mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
+ mNumRelroCreationsFinished = 0;
+ mNumRelroCreationsStarted = WebViewFactory.onWebViewProviderChanged(newPackage);
+ // If the relro creations finish before we know the number of started creations we
+ // will have to do any cleanup/notifying here.
+ checkIfRelrosDoneLocked();
+ } else {
+ mWebViewPackageDirty = true;
+ }
+ }
+ }
+
+ /**
+ * Updates the currently valid WebView provider packages.
+ * Should be used when a provider has been installed or removed.
+ * @hide
+ * */
+ private void updateValidWebViewPackages() {
+ List<WebViewProviderInfo> webViewProviders =
+ new ArrayList<WebViewProviderInfo>(Arrays.asList(WebViewFactory.getWebViewPackages()));
+ Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
+ // remove non-valid packages
+ while(it.hasNext()) {
+ WebViewProviderInfo current = it.next();
+ if (!current.isValidProvider())
+ it.remove();
+ }
+ synchronized(this) {
+ mCurrentValidWebViewPackages =
+ webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ }
+ }
+
+ private static String getUserChosenWebViewProvider() {
+ return Settings.Secure.getString(AppGlobals.getInitialApplication().getContentResolver(),
+ Settings.Secure.WEBVIEW_PROVIDER);
+ }
+
+ private void updateUserSetting(String newProviderName) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.WEBVIEW_PROVIDER,
+ newProviderName == null ? "" : newProviderName);
+ }
+
+ /**
+ * Returns either the package info of the WebView provider determined in the following way:
+ * If the user has chosen a provider then use that if it is valid,
+ * otherwise use the first package in the webview priority list that is valid.
+ *
+ * @hide
+ */
+ private PackageInfo findPreferredWebViewPackage() {
+ WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
+
+ String userChosenProvider = getUserChosenWebViewProvider();
+
+ // If the user has chosen provider, use that
+ for (WebViewProviderInfo provider : providers) {
+ if (provider.packageName.equals(userChosenProvider)) {
+ return provider.getPackageInfo();
+ }
+ }
+
+ // User did not choose, or the choice failed, use the most stable provider available
+ for (WebViewProviderInfo provider : providers) {
+ return provider.getPackageInfo();
+ }
+ mAnyWebViewInstalled = false;
+ throw new WebViewFactory.MissingWebViewPackageException(
+ "Could not find a loadable WebView package");
+ }
+
+ /**
+ * Returns whether WebView is ready and is not going to go through its preparation phase again
+ * directly.
+ */
+ private boolean webViewIsReadyLocked() {
+ return !mWebViewPackageDirty
+ && (mNumRelroCreationsStarted == mNumRelroCreationsFinished)
+ && !mCurrentProviderBeingReplaced
+ // The current package might be replaced though we haven't received an intent declaring
+ // this yet, the following flag makes anyone loading WebView to wait in this case.
+ && mAnyWebViewInstalled;
+ }
+
+ private void checkIfRelrosDoneLocked() {
+ if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
+ if (mWebViewPackageDirty) {
+ mWebViewPackageDirty = false;
+ // If we have changed provider since we started the relro creation we need to
+ // redo the whole process using the new package instead.
+ // Though, if the current provider package is being replaced we don't want to change
+ // provider here since we will perform the change either when the package is added
+ // again or when we switch to another provider (whichever comes first).
+ if (!mCurrentProviderBeingReplaced) {
+ PackageInfo newPackage = findPreferredWebViewPackage();
+ onWebViewProviderChanged(newPackage);
+ }
+ } else {
+ this.notifyAll();
+ }
+ }
}
private class BinderService extends IWebViewUpdateService.Stub {
@@ -108,7 +345,7 @@
* crashed.
*/
@Override // Binder call
- public void notifyRelroCreationCompleted(boolean is64Bit, boolean success) {
+ public void notifyRelroCreationCompleted() {
// Verify that the caller is either the shared relro process (nominal case) or the
// system server (only in the case the relro process crashes and we get here via the
// crashHandler).
@@ -118,20 +355,17 @@
}
synchronized (WebViewUpdateService.this) {
- if (is64Bit) {
- mRelroReady64Bit = true;
- } else {
- mRelroReady32Bit = true;
- }
- WebViewUpdateService.this.notifyAll();
+ mNumRelroCreationsFinished++;
+ checkIfRelrosDoneLocked();
}
}
/**
* WebViewFactory calls this to block WebView loading until the relro file is created.
+ * Returns the WebView provider for which we create relro files.
*/
@Override // Binder call
- public void waitForRelroCreationCompleted(boolean is64Bit) {
+ public WebViewProviderResponse waitForAndGetProvider() {
// The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
// happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
// another service there tries to bring up a WebView in the between, the wait below
@@ -140,21 +374,74 @@
throw new IllegalStateException("Cannot create a WebView from the SystemServer");
}
+ PackageInfo webViewPackage = null;
final long NS_PER_MS = 1000000;
final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
- boolean relroReady = (is64Bit ? mRelroReady64Bit : mRelroReady32Bit);
+ boolean webViewReady = false;
+ int webViewStatus = WebViewFactory.LIBLOAD_SUCCESS;
synchronized (WebViewUpdateService.this) {
- while (!relroReady) {
+ webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
+ while (!webViewReady) {
final long timeNowMs = System.nanoTime() / NS_PER_MS;
if (timeNowMs >= timeoutTimeMs) break;
try {
WebViewUpdateService.this.wait(timeoutTimeMs - timeNowMs);
} catch (InterruptedException e) {}
- relroReady = (is64Bit ? mRelroReady64Bit : mRelroReady32Bit);
+ webViewReady = WebViewUpdateService.this.webViewIsReadyLocked();
+ }
+ // Make sure we return the provider that was used to create the relro file
+ webViewPackage = WebViewUpdateService.this.mCurrentWebViewPackage;
+ if (webViewReady) {
+ } else if (mCurrentProviderBeingReplaced) {
+ // It is important that we check this flag before the one representing WebView
+ // being installed, otherwise we might think there is no WebView though the
+ // current one is just being replaced.
+ webViewStatus = WebViewFactory.LIBLOAD_WEBVIEW_BEING_REPLACED;
+ } else if (!mAnyWebViewInstalled) {
+ webViewStatus = WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
+ } else {
+ // Either the current relro creation isn't done yet, or the new relro creatioin
+ // hasn't kicked off yet (the last relro creation used an out-of-date WebView).
+ webViewStatus = WebViewFactory.LIBLOAD_FAILED_WAITING_FOR_RELRO;
}
}
- if (!relroReady) Slog.w(TAG, "creating relro file timed out");
+ if (!webViewReady) Slog.w(TAG, "creating relro file timed out");
+ return new WebViewProviderResponse(webViewPackage, webViewStatus);
+ }
+
+ /**
+ * This is called from DeveloperSettings when the user changes WebView provider.
+ */
+ @Override // Binder call
+ public void changeProviderAndSetting(String newProvider) {
+ if (getContext().checkCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: changeProviderAndSetting() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ WebViewUpdateService.this.changeProviderAndSetting(newProvider);
+ }
+
+ @Override // Binder call
+ public WebViewProviderInfo[] getValidWebViewPackages() {
+ synchronized(WebViewUpdateService.this) {
+ return mCurrentValidWebViewPackages;
+ }
+ }
+
+ @Override // Binder call
+ public String getCurrentWebViewPackageName() {
+ synchronized(WebViewUpdateService.this) {
+ if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
+ return null;
+ return WebViewUpdateService.this.mCurrentWebViewPackage.packageName;
+ }
}
}
-
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9b64481..5942198 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -110,6 +110,8 @@
final DimLayerController mDimLayerController;
+ final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
+
/**
* @param display May not be null.
* @param service You know.
@@ -412,6 +414,11 @@
inputMethod.getTouchableRegion(mTmpRegion);
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
+ for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
+ WindowState win = mTapExcludedWindows.get(i);
+ win.getTouchableRegion(mTmpRegion);
+ mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
+ }
if (mTapDetector != null) {
mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion, mNonResizeableRegion);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c606fe..816cab7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -42,6 +42,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
@@ -1966,6 +1967,10 @@
res = WindowManagerGlobal.ADD_OKAY;
+ if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+ displayContent.mTapExcludedWindows.add(win);
+ }
+
origId = Binder.clearCallingIdentity();
if (addToken) {
@@ -2309,6 +2314,11 @@
Slog.w(TAG_WM, "Removing window " + win, e);
}
+ final int type = win.mAttrs.type;
+ if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+ final DisplayContent displaycontent = win.getDisplayContent();
+ displaycontent.mTapExcludedWindows.remove(win);
+ }
mPolicy.removeWindowLw(win);
win.removeLocked();
@@ -2364,7 +2374,7 @@
}
}
- if (win.mAttrs.type == TYPE_WALLPAPER) {
+ if (type == TYPE_WALLPAPER) {
mWallpaperControllerLocked.clearLastWallpaperTimeoutTime();
getDefaultDisplayContentLocked().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 539810d..cd82a5f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -710,11 +710,13 @@
// Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
if (mTmpSize.width() < 1) {
- Slog.w(TAG, "Width of " + w + " is not positive " + mTmpSize.width());
+ if (!mWin.mLayoutNeeded) Slog.w(TAG,
+ "Width of " + w + " is not positive " + mTmpSize.width());
mTmpSize.right = mTmpSize.left + 1;
}
if (mTmpSize.height() < 1) {
- Slog.w(TAG, "Height of " + w + " is not positive " + mTmpSize.height());
+ if (!mWin.mLayoutNeeded) Slog.w(TAG,
+ "Height of " + w + " is not positive " + mTmpSize.height());
mTmpSize.bottom = mTmpSize.top + 1;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2f33d7c..189ed33 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -150,6 +150,7 @@
// TODO: remove all of these references by improving dependency resolution and boot phases
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
+ private WebViewUpdateService mWebViewUpdateService;
private DisplayManagerService mDisplayManagerService;
private PackageManagerService mPackageManagerService;
private PackageManager mPackageManager;
@@ -409,7 +410,7 @@
LocalServices.getService(UsageStatsManagerInternal.class));
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
- mSystemServiceManager.startService(WebViewUpdateService.class);
+ mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
}
/**
@@ -1180,7 +1181,7 @@
Slog.i(TAG, "WebViewFactory preparation");
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
- WebViewFactory.prepareWebViewInSystemServer();
+ mWebViewUpdateService.prepareWebViewInSystemServer();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");