diff options
38 files changed, 963 insertions, 217 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 332a51623212..492d6a923f51 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -46479,8 +46479,6 @@ package android.webkit { 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 @@ package android.webkit { 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 4cb261927ef8..f11bf742c925 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1558,6 +1558,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ class ActivityManagerProxy implements IActivityManager 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 eb8d6bc1e92a..64c69af8691d 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -259,6 +259,7 @@ public interface IActivityManager extends IInterface { 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 @@ public interface IActivityManager extends IInterface { 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/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 89610e99a718..85d9831921ac 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -128,6 +128,14 @@ public class NotificationManager = "android.app.action.INTERRUPTION_FILTER_CHANGED"; /** + * Intent that is broadcast when the state of getCurrentInterruptionFilter() changes. + * @hide + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL + = "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL"; + + /** * {@link #getCurrentInterruptionFilter() Interruption filter} constant - * Normal interruption filter. */ diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 5e8ad68957b2..b899116142c8 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -180,10 +180,17 @@ public class StatusBarManager { * Expand the settings panel. */ public void expandSettingsPanel() { + expandSettingsPanel(null); + } + + /** + * Expand the settings panel and open a subPanel, pass null to just open the settings panel. + */ + public void expandSettingsPanel(String subPanel) { try { final IStatusBarService svc = getService(); if (svc != null) { - svc.expandSettingsPanel(); + svc.expandSettingsPanel(subPanel); } } catch (RemoteException ex) { // system process is dead anyway. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 74fd8cd10de3..a1e551082799 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5749,6 +5749,13 @@ public final class Settings { "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/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 76c63b958046..232d4fe4e979 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -713,10 +713,10 @@ public abstract class NotificationListenerService extends Service { createLegacyIconExtras(sbn.getNotification()); maybePopulateRemoteViews(sbn.getNotification()); } catch (IllegalArgumentException e) { - // drop corrupt notification - sbn = null; + // warn and drop corrupt notification Log.w(TAG, "onNotificationPosted: can't rebuild notification from " + sbn.getPackageName()); + sbn = null; } // protect subclass from concurrent modifications of (@link mNotificationKeys}. diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl index a77459b09251..89d5d69de392 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 @@ interface IWebViewUpdateService { /** * 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 229011db049c..01d15664f24a 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -24,6 +24,7 @@ import android.content.Context; 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.ServiceManager; 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 final class WebViewFactory { 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 final class WebViewFactory { 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 { - 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); - } - - // TODO (gsennton) remove when committing webview xts test change - public static String getWebViewPackageName() { - String[] webViewPackageNames = getWebViewPackageNames(); - return webViewPackageNames[webViewPackageNames.length-1]; + // 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"; } /** - * 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(); + public static class MissingWebViewPackageException extends AndroidRuntimeException { + public MissingWebViewPackageException(String message) { super(message); } + public MissingWebViewPackageException(Exception e) { super(e); } + } - for (String packageName : getWebViewPackageNames()) { - try { - PackageInfo packageInfo = pm.getPackageInfo(packageName, - PackageManager.GET_META_DATA); - ApplicationInfo applicationInfo = packageInfo.applicationInfo; + 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"; - // If the correct flag is set the package contains webview. - if (getWebViewLibrary(applicationInfo) != null) { - return packageInfo; + /** + * 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 (PackageManager.NameNotFoundException e) { } + } 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(); } - throw new MissingWebViewPackageException("Could not find a loadable WebView package"); + return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]); } - // throws MissingWebViewPackageException - private static ApplicationInfo getWebViewApplicationInfo() { - if (sPackageInfo == null) - return findPreferredWebViewPackage().applicationInfo; - else - return sPackageInfo.applicationInfo; + + // TODO (gsennton) remove when committing webview xts test change + public static String getWebViewPackageName() { + WebViewProviderInfo[] providers = getWebViewPackages(); + return providers[0].packageName; } - private static String getWebViewLibrary(ApplicationInfo ai) { + /** + * @hide + */ + public static String getWebViewLibrary(ApplicationInfo ai) { if (ai.metaData != null) return ai.metaData.getString("com.android.webview.WebViewLibrary"); return null; @@ -156,16 +204,14 @@ public final class WebViewFactory { * 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 @@ public final class WebViewFactory { 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 @@ public final class WebViewFactory { } } - // 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 @@ public final class WebViewFactory { } } - /** - * 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 @@ public final class WebViewFactory { // 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 @@ public final class WebViewFactory { } // 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 final class WebViewFactory { 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 @@ public final class WebViewFactory { } 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 @@ public final class WebViewFactory { } } + 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; - } - - 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; + 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"); } + 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 000000000000..82e5a7936de8 --- /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 000000000000..d5e3a230919b --- /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 000000000000..9c884cc7ad33 --- /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 000000000000..f5e09e2be71e --- /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/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 11ef18b4d5c0..849d3145bb56 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -28,7 +28,7 @@ oneway interface IStatusBar void removeIcon(int index); void disable(int state1, int state2); void animateExpandNotificationsPanel(); - void animateExpandSettingsPanel(); + void animateExpandSettingsPanel(String subPanel); void animateCollapsePanels(); void setSystemUiVisibility(int vis, int mask); void topAppWindowChanged(boolean menuVisible); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 6c957becc5e5..0a4ad0661c64 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -39,7 +39,7 @@ interface IStatusBarService void topAppWindowChanged(boolean menuVisible); void setImeWindowStatus(in IBinder token, int vis, int backDisposition, boolean showImeSwitcher); - void expandSettingsPanel(); + void expandSettingsPanel(String subPanel); void setCurrentUser(int newUserId); // ---- Methods below are for use by the status bar policy services ---- diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index 8c4d078ecd78..406b487f643d 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -778,8 +778,11 @@ public class StateMachine { */ @Override public final void handleMessage(Message msg) { - mSm.onPreHandleMessage(msg); if (!mHasQuit) { + if (mSm != null) { + mSm.onPreHandleMessage(msg); + } + if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what); /** Save the current message */ @@ -803,8 +806,11 @@ public class StateMachine { // We need to check if mSm == null here as we could be quitting. if (mDbg && mSm != null) mSm.log("handleMessage: X"); + + if (mSm != null) { + mSm.onPostHandleMessage(msg); + } } - mSm.onPostHandleMessage(msg); } /** diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 97c0e07186e0..e2b1dbb6300e 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 6367d3728d50..bf758c225859 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 000000000000..6f9c58d2f9b7 --- /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 d7e5faabe2a3..5c846d8efd16 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/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml index 82e8dc694cde..1033bb19c10c 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 55bd08a16d8f..7e2288133ab3 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/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 5acd0ef8fae8..8d3da1172771 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 1edfd5c3b784..ae57a32629f7 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 9cccec47d7b8..35a6e1bab4e8 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 9a22b2c30afd..9a0a0c0566a4 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/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index ae8542ad9d88..16fd9ebba7fd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -154,6 +154,20 @@ public class QSPanel extends FrameLayout implements Tunable { } } + public void openDetails(String subPanel) { + QSTile<?> tile = getTile(subPanel); + showDetailAdapter(true, tile.getDetailAdapter(), new int[] {getWidth() / 2, 0}); + } + + private QSTile<?> getTile(String subPanel) { + for (int i = 0; i < mRecords.size(); i++) { + if (subPanel.equals(mRecords.get(i).tile.getTileSpec())) { + return mRecords.get(i).tile; + } + } + return mHost.createTile(subPanel); + } + protected void createCustomizePanel() { mCustomizePanel = (QSCustomizer) LayoutInflater.from(mContext) .inflate(R.layout.qs_customize_panel, null); 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 60bedaecdf2d..512effab047a 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 class Task { 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 @@ public class Task { 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 @@ public class Task { /** 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 @@ public class Task { } } + /** + * 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 7a9839365498..13ab3920065e 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.Color; 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 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; */ 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 @@ class FilteredTaskList { 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 @@ public class TaskStack { // 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 @@ public class TaskStack { 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 @@ public class TaskStack { 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/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 10d4a965852f..deedae0f6a80 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -91,7 +91,7 @@ public class CommandQueue extends IStatusBar.Stub { public void disable(int state1, int state2, boolean animate); public void animateExpandNotificationsPanel(); public void animateCollapsePanels(int flags); - public void animateExpandSettingsPanel(); + public void animateExpandSettingsPanel(String obj); public void setSystemUiVisibility(int vis, int mask); public void topAppWindowChanged(boolean visible); public void setImeWindowStatus(IBinder token, int vis, int backDisposition, @@ -157,10 +157,10 @@ public class CommandQueue extends IStatusBar.Stub { } } - public void animateExpandSettingsPanel() { + public void animateExpandSettingsPanel(String subPanel) { synchronized (mList) { mHandler.removeMessages(MSG_EXPAND_SETTINGS); - mHandler.sendEmptyMessage(MSG_EXPAND_SETTINGS); + mHandler.obtainMessage(MSG_EXPAND_SETTINGS, subPanel).sendToTarget(); } } @@ -353,7 +353,7 @@ public class CommandQueue extends IStatusBar.Stub { mCallbacks.animateCollapsePanels(0); break; case MSG_EXPAND_SETTINGS: - mCallbacks.animateExpandSettingsPanel(); + mCallbacks.animateExpandSettingsPanel((String) msg.obj); break; case MSG_SET_SYSTEMUI_VISIBILITY: mCallbacks.setSystemUiVisibility(msg.arg1, msg.arg2); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 76b8223ba778..8f7c95e1b9af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -2162,7 +2162,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, animateExpandNotificationsPanel(); break; case MSG_OPEN_SETTINGS_PANEL: - animateExpandSettingsPanel(); + animateExpandSettingsPanel((String) m.obj); break; case MSG_CLOSE_PANELS: animateCollapsePanels(); @@ -2305,7 +2305,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void animateExpandSettingsPanel() { + public void animateExpandSettingsPanel(String subPanel) { if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible); if (!panelsEnabled()) { return; @@ -2314,6 +2314,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // Settings are not available in setup if (!mUserSetup) return; + + if (subPanel != null) { + mQSPanel.openDetails(subPanel); + } mNotificationPanel.expandWithQs(); if (false) postStartTracing(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 856a774fdcce..44b41c55b4de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -135,7 +135,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void animateExpandSettingsPanel() { + public void animateExpandSettingsPanel(String subPanel) { } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 22d30dfb499f..be1fd58fce3b 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } } } + + /** + * 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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 07343a9fd2f1..e6a48a8cd87d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -880,6 +880,9 @@ public class NotificationManagerService extends SystemService { @Override void onZenModeChanged() { sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED); + getContext().sendBroadcastAsUser( + new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL), + UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS); synchronized(mNotificationList) { updateInterruptionFilterLocked(); } @@ -3683,7 +3686,7 @@ public class NotificationManagerService extends SystemService { for (int i = 0; i < tokens.length; i++) { String token = tokens[i]; if (token != null) { - token.trim(); + token = token.trim(); } if (TextUtils.isEmpty(token)) { continue; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 3c891dff5b1d..6030bab6db64 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -564,6 +564,7 @@ public class ZenModeHelper { private boolean evaluateZenMode(String reason, boolean setRingerMode) { if (DEBUG) Log.d(TAG, "evaluateZenMode"); + final int zenBefore = mZenMode; final int zen = computeZenMode(); ZenLog.traceSetZenMode(zen, reason); mZenMode = zen; @@ -573,7 +574,7 @@ public class ZenModeHelper { applyZenToRingerMode(); } applyRestrictions(); - if (zen != mZenMode) { + if (zen != zenBefore) { mHandler.postDispatchOnZenModeChanged(); } return true; diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 19b03d5e56cd..fc271704a1ec 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -216,12 +216,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void expandSettingsPanel() { + public void expandSettingsPanel(String subPanel) { enforceExpandStatusBar(); if (mBar != null) { try { - mBar.animateExpandSettingsPanel(); + mBar.animateExpandSettingsPanel(subPanel); } catch (RemoteException ex) { } } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 97713fc2407a..7be0eadf895e 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 @@ import com.android.server.SystemService; 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. + + // 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 boolean mRelroReady32Bit = false; - private boolean mRelroReady64Bit = false; + private int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE; - private String oldWebViewPackageName = null; + // 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 @@ public class WebViewUpdateService extends SystemService { 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 @@ public class WebViewUpdateService extends SystemService { publishBinderService("webviewupdate", new BinderService()); } - private void onWebViewUpdateInstalled() { - Slog.d(TAG, "WebView Package updated!"); + /** + * 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); + } + } + - synchronized (this) { - mRelroReady32Bit = false; - mRelroReady64Bit = false; + /** + * 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(); + } } - WebViewFactory.onWebViewUpdateInstalled(); } private class BinderService extends IWebViewUpdateService.Stub { @@ -108,7 +345,7 @@ public class WebViewUpdateService extends SystemService { * 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 @@ public class WebViewUpdateService extends SystemService { } 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 @@ public class WebViewUpdateService extends SystemService { 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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2f33d7cdd3fe..189ed332abef 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -150,6 +150,7 @@ public final class SystemServer { // 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 @@ public final class SystemServer { 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 @@ public final class SystemServer { 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"); |