diff options
46 files changed, 861 insertions, 140 deletions
diff --git a/Android.mk b/Android.mk index 71720a1740a5..95c3340cd530 100644 --- a/Android.mk +++ b/Android.mk @@ -694,6 +694,8 @@ LOCAL_SOURCE_FILES_ALL_GENERATED := true LOCAL_SRC_FILES := \ $(call all-proto-files-under, core/proto) \ $(call all-proto-files-under, libs/incident/proto) +# b/72714520 +LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2e701329dbfc..472ac575107c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2662,7 +2662,7 @@ public class ConnectivityManager { * A {@code NetworkCallback} is registered by calling * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)}, - * or {@link #registerDefaultNetworkCallback(NetworkCallback). A {@code NetworkCallback} is + * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is * unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}. * A {@code NetworkCallback} should be registered at most once at any time. * A {@code NetworkCallback} that has been unregistered can be registered again. diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index bc4d9555c9e7..c94ae93a6f3b 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,7 +21,6 @@ import android.net.ConnectivityManager.NetworkCallback; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; -import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.BitUtils; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index d5377c717366..1bb4adcebc82 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.Nullable; import android.content.Intent; import android.os.Environment; import android.os.Parcel; @@ -23,6 +24,8 @@ import android.os.Parcelable; import android.os.StrictMode; import android.util.Log; +import libcore.net.UriCodec; + import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -38,8 +41,6 @@ import java.util.Objects; import java.util.RandomAccess; import java.util.Set; -import libcore.net.UriCodec; - /** * Immutable URI reference. A URI reference includes a URI and a fragment, the * component of the URI following a '#'. Builds and parses URI references @@ -174,6 +175,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the scheme or null if this is a relative URI */ + @Nullable public abstract String getScheme(); /** @@ -208,6 +210,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the authority for this URI or null if not present */ + @Nullable public abstract String getAuthority(); /** @@ -219,6 +222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the authority for this URI or null if not present */ + @Nullable public abstract String getEncodedAuthority(); /** @@ -228,6 +232,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the user info for this URI or null if not present */ + @Nullable public abstract String getUserInfo(); /** @@ -237,6 +242,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the user info for this URI or null if not present */ + @Nullable public abstract String getEncodedUserInfo(); /** @@ -246,6 +252,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the host for this URI or null if not present */ + @Nullable public abstract String getHost(); /** @@ -262,6 +269,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * @return the decoded path, or null if this is not a hierarchical URI * (like "mailto:nobody@google.com") or the URI is invalid */ + @Nullable public abstract String getPath(); /** @@ -270,6 +278,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * @return the encoded path, or null if this is not a hierarchical URI * (like "mailto:nobody@google.com") or the URI is invalid */ + @Nullable public abstract String getEncodedPath(); /** @@ -280,6 +289,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the decoded query or null if there isn't one */ + @Nullable public abstract String getQuery(); /** @@ -290,6 +300,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the encoded query or null if there isn't one */ + @Nullable public abstract String getEncodedQuery(); /** @@ -297,6 +308,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the decoded fragment or null if there isn't one */ + @Nullable public abstract String getFragment(); /** @@ -304,6 +316,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the encoded fragment or null if there isn't one */ + @Nullable public abstract String getEncodedFragment(); /** @@ -318,6 +331,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * @return the decoded last segment or null if the path is empty */ + @Nullable public abstract String getLastPathSegment(); /** @@ -1666,6 +1680,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * @throws NullPointerException if key is null * @return the decoded value or null if no parameter is found */ + @Nullable public String getQueryParameter(String key) { if (isOpaque()) { throw new UnsupportedOperationException(NOT_HIERARCHICAL); diff --git a/core/java/android/os/ChildZygoteProcess.java b/core/java/android/os/ChildZygoteProcess.java new file mode 100644 index 000000000000..337a3e279a1a --- /dev/null +++ b/core/java/android/os/ChildZygoteProcess.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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.os; + +import android.net.LocalSocketAddress; + +/** + * Represents a connection to a child-zygote process. A child-zygote is spawend from another + * zygote process using {@link startChildZygote()}. + * + * {@hide} + */ +public class ChildZygoteProcess extends ZygoteProcess { + /** + * The PID of the child zygote process. + */ + private final int mPid; + + ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) { + super(socketAddress, null); + mPid = pid; + } + + /** + * Returns the PID of the child-zygote process. + */ + public int getPid() { + return mPid; + } +} diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 4a976403e7a8..57418c8b9879 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.UUID; /*package*/ class ZygoteStartFailedEx extends Exception { ZygoteStartFailedEx(String s) { @@ -217,7 +218,8 @@ public class ZygoteProcess { try { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, - abi, instructionSet, appDataDir, invokeWith, zygoteArgs); + abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, + zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -333,6 +335,8 @@ public class ZygoteProcess { * @param abi the ABI the process should use. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. + * @param startChildZygote Start a sub-zygote. This creates a new zygote process + * that has its state cloned from this zygote process. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason @@ -348,6 +352,7 @@ public class ZygoteProcess { String instructionSet, String appDataDir, String invokeWith, + boolean startChildZygote, String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<String>(); @@ -404,6 +409,10 @@ public class ZygoteProcess { argsForZygote.add(invokeWith); } + if (startChildZygote) { + argsForZygote.add("--start-child-zygote"); + } + argsForZygote.add(processClass); if (extraArgs != null) { @@ -418,6 +427,18 @@ public class ZygoteProcess { } /** + * Closes the connections to the zygote, if they exist. + */ + public void close() { + if (primaryZygoteState != null) { + primaryZygoteState.close(); + } + if (secondaryZygoteState != null) { + secondaryZygoteState.close(); + } + } + + /** * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block * and retry if the zygote is unresponsive. This method is a no-op if a connection is * already open. @@ -549,4 +570,36 @@ public class ZygoteProcess { } Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName()); } + + /** + * Starts a new zygote process as a child of this zygote. This is used to create + * secondary zygotes that inherit data from the zygote that this object + * communicates with. This returns a new ZygoteProcess representing a connection + * to the newly created zygote. Throws an exception if the zygote cannot be started. + */ + public ChildZygoteProcess startChildZygote(final String processClass, + final String niceName, + int uid, int gid, int[] gids, + int runtimeFlags, + String seInfo, + String abi, + String instructionSet) { + // Create an unguessable address in the global abstract namespace. + final LocalSocketAddress serverAddress = new LocalSocketAddress( + processClass + "/" + UUID.randomUUID().toString()); + + final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()}; + + Process.ProcessStartResult result; + try { + result = startViaZygote(processClass, niceName, uid, gid, + gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, + abi, instructionSet, null /* appDataDir */, null /* invokeWith */, + true /* startChildZygote */, extraArgs); + } catch (ZygoteStartFailedEx ex) { + throw new RuntimeException("Starting child-zygote through Zygote failed", ex); + } + + return new ChildZygoteProcess(serverAddress, result.pid); + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 86f48214db00..f4842c6ca6c5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10387,6 +10387,14 @@ public final class Settings { "storage_settings_clobber_threshold"; /** + * Exemptions to the hidden API blacklist. + * + * @hide + */ + public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = + "hidden_api_blacklist_exemptions"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 91e2f7d4ddd0..6c7455d35397 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3866,6 +3866,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private void onTouchDown(MotionEvent ev) { mHasPerformedLongPress = false; mActivePointerId = ev.getPointerId(0); + hideSelector(); if (mTouchMode == TOUCH_MODE_OVERFLING) { // Stopped the fling. It is a scroll. @@ -5226,17 +5227,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } mRecycler.fullyDetachScrapViews(); + boolean selectorOnScreen = false; if (!inTouchMode && mSelectedPosition != INVALID_POSITION) { final int childIndex = mSelectedPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { positionSelector(mSelectedPosition, getChildAt(childIndex)); + selectorOnScreen = true; } } else if (mSelectorPosition != INVALID_POSITION) { final int childIndex = mSelectorPosition - mFirstPosition; if (childIndex >= 0 && childIndex < getChildCount()) { - positionSelector(INVALID_POSITION, getChildAt(childIndex)); + positionSelector(mSelectorPosition, getChildAt(childIndex)); + selectorOnScreen = true; } - } else { + } + if (!selectorOnScreen) { mSelectorRect.setEmpty(); } diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 895be082c679..bb5a0ad86dd4 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -230,7 +230,7 @@ public class RuntimeInit { * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ - private static Runnable findStaticMain(String className, String[] argv, + protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl; diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index cadb66ae6e08..b38c851e5101 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -129,7 +129,7 @@ class WebViewZygoteInit { final Runnable caller; try { - sServer.registerServerSocket("webview_zygote"); + sServer.registerServerSocketFromEnv("webview_zygote"); // The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 89d63f60ebdd..e23cbf815b87 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -71,6 +71,13 @@ public final class Zygote { private static final ZygoteHooks VM_HOOKS = new ZygoteHooks(); + /** + * An extraArg passed when a zygote process is forking a child-zygote, specifying a name + * in the abstract socket namespace. This socket name is what the new child zygote + * should listen for connections on. + */ + public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket="; + private Zygote() {} /** Called for some security initialization before any fork. */ @@ -102,6 +109,8 @@ public final class Zygote { * @param fdsToIgnore null-ok an array of ints, either null or holding * one or more POSIX file descriptor numbers that are to be ignored * in the file descriptor table check. + * @param startChildZygote if true, the new child process will itself be a + * new zygote process. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. * @@ -110,13 +119,13 @@ public final class Zygote { */ public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, String instructionSet, String appDataDir) { + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) { VM_HOOKS.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, - fdsToIgnore, instructionSet, appDataDir); + fdsToIgnore, startChildZygote, instructionSet, appDataDir); // Enable tracing as soon as possible for the child process. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); @@ -130,7 +139,7 @@ public final class Zygote { native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, String instructionSet, String appDataDir); + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir); /** * Called to do any initialization before starting an application. @@ -190,8 +199,8 @@ public final class Zygote { native protected static void nativeUnmountStorageOnInit(); private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, - String instructionSet) { - VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, instructionSet); + boolean isZygote, String instructionSet) { + VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); } /** diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 6a87b1f4d3fd..a32fb4316d12 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -221,8 +221,8 @@ class ZygoteConnection { pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, - parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet, - parsedArgs.appDataDir); + parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, + parsedArgs.instructionSet, parsedArgs.appDataDir); try { if (pid == 0) { @@ -233,7 +233,8 @@ class ZygoteConnection { IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; - return handleChildProc(parsedArgs, descriptors, childPipeFd); + return handleChildProc(parsedArgs, descriptors, childPipeFd, + parsedArgs.startChildZygote); } else { // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. @@ -415,6 +416,14 @@ class ZygoteConnection { boolean preloadDefault; /** + * Whether this is a request to start a zygote process as a child of this zygote. + * Set with --start-child-zygote. The remaining arguments must include the + * CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that + * should be used for communication. + */ + boolean startChildZygote; + + /** * Constructs instance and parses args * @param args zygote command-line args * @throws IllegalArgumentException @@ -565,6 +574,8 @@ class ZygoteConnection { preloadPackageCacheKey = args[++curArg]; } else if (arg.equals("--preload-default")) { preloadDefault = true; + } else if (arg.equals("--start-child-zygote")) { + startChildZygote = true; } else { break; } @@ -587,6 +598,20 @@ class ZygoteConnection { remainingArgs = new String[args.length - curArg]; System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length); } + + if (startChildZygote) { + boolean seenChildSocketArg = false; + for (String arg : remainingArgs) { + if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) { + seenChildSocketArg = true; + break; + } + } + if (!seenChildSocketArg) { + throw new IllegalArgumentException("--start-child-zygote specified " + + "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG); + } + } } } @@ -739,9 +764,10 @@ class ZygoteConnection { * @param parsedArgs non-null; zygote args * @param descriptors null-ok; new file descriptors for stdio if available. * @param pipeFd null-ok; pipe for communication back to Zygote. + * @param isZygote whether this new child process is itself a new Zygote. */ private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, - FileDescriptor pipeFd) { + FileDescriptor pipeFd, boolean isZygote) { /** * By the time we get here, the native code has closed the two actual Zygote * socket connections, and substituted /dev/null in their place. The LocalSocket @@ -778,8 +804,13 @@ class ZygoteConnection { // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { - return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, - null /* classLoader */); + if (!isZygote) { + return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, + null /* classLoader */); + } else { + return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion, + parsedArgs.remainingArgs, null /* classLoader */); + } } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 4a3bb3cca1fc..a05454f53bf8 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -576,7 +576,8 @@ public class ZygoteInit { installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName, instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter, uuid, classLoaderContext, seInfo, false /* downgrade */, - targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null); + targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null, + "server-dexopt"); } catch (RemoteException | ServiceSpecificException e) { // Ignore (but log), we need this on the classpath for fallback mode. Log.w(TAG, "Failed compiling classpath element for system server: " @@ -755,7 +756,7 @@ public class ZygoteInit { throw new RuntimeException("No ABI list supplied."); } - zygoteServer.registerServerSocket(socketName); + zygoteServer.registerServerSocketFromEnv(socketName); // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { @@ -870,5 +871,16 @@ public class ZygoteInit { return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); } + /** + * The main function called when starting a child zygote process. This is used as an + * alternative to zygoteInit(), which skips calling into initialization routines that + * start the Binder threadpool. + */ + static final Runnable childZygoteInit( + int targetSdkVersion, String[] argv, ClassLoader classLoader) { + RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv); + return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader); + } + private static final native void nativeZygoteInit(); } diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java index 8baa15a058de..fecf9b9da5dd 100644 --- a/core/java/com/android/internal/os/ZygoteServer.java +++ b/core/java/com/android/internal/os/ZygoteServer.java @@ -44,9 +44,21 @@ class ZygoteServer { private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; + /** + * Listening socket that accepts new server connections. + */ private LocalServerSocket mServerSocket; /** + * Whether or not mServerSocket's underlying FD should be closed directly. + * If mServerSocket is created with an existing FD, closing the socket does + * not close the FD and it must be closed explicitly. If the socket is created + * with a name instead, then closing the socket will close the underlying FD + * and it should not be double-closed. + */ + private boolean mCloseSocketFd; + + /** * Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}. */ private boolean mIsForkChild; @@ -59,11 +71,12 @@ class ZygoteServer { } /** - * Registers a server socket for zygote command connections + * Registers a server socket for zygote command connections. This locates the server socket + * file descriptor through an ANDROID_SOCKET_ environment variable. * * @throws RuntimeException when open fails */ - void registerServerSocket(String socketName) { + void registerServerSocketFromEnv(String socketName) { if (mServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; @@ -78,6 +91,7 @@ class ZygoteServer { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); mServerSocket = new LocalServerSocket(fd); + mCloseSocketFd = true; } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); @@ -86,6 +100,22 @@ class ZygoteServer { } /** + * Registers a server socket for zygote command connections. This opens the server socket + * at the specified name in the abstract socket namespace. + */ + void registerServerSocketAtAbstractName(String socketName) { + if (mServerSocket == null) { + try { + mServerSocket = new LocalServerSocket(socketName); + mCloseSocketFd = false; + } catch (IOException ex) { + throw new RuntimeException( + "Error binding to abstract socket '" + socketName + "'", ex); + } + } + } + + /** * Waits for and accepts a single command connection. Throws * RuntimeException on failure. */ @@ -112,7 +142,7 @@ class ZygoteServer { if (mServerSocket != null) { FileDescriptor fd = mServerSocket.getFileDescriptor(); mServerSocket.close(); - if (fd != null) { + if (fd != null && mCloseSocketFd) { Os.close(fd); } } @@ -219,6 +249,11 @@ class ZygoteServer { Log.e(TAG, "Caught post-fork exception in child process.", e); throw e; } + } finally { + // Reset the child flag, in the event that the child process is a child- + // zygote. The flag will not be consulted this loop pass after the Runnable + // is returned. + mIsForkChild = false; } } } diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 6af41a51f0dd..324f923674eb 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -256,7 +256,7 @@ public class MenuPopupHelper implements MenuHelper { final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity, mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; if (hgrav == Gravity.RIGHT) { - xOffset += mAnchorView.getWidth(); + xOffset -= mAnchorView.getWidth(); } popup.setHorizontalOffset(xOffset); diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java index d9ca5be0502e..445379b1d9f4 100644 --- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java +++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java @@ -263,7 +263,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes); subPopup.setPresenterCallback(mPresenterCallback); subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu)); - subPopup.setGravity(mDropDownGravity); // Pass responsibility for handling onDismiss to the submenu. subPopup.setOnDismissListener(mOnDismissListener); @@ -273,8 +272,17 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mMenu.close(false /* closeAllMenus */); // Show the new sub-menu popup at the same location as this popup. - final int horizontalOffset = mPopup.getHorizontalOffset(); + int horizontalOffset = mPopup.getHorizontalOffset(); final int verticalOffset = mPopup.getVerticalOffset(); + + // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT, + // So, again to display sub-menu popup in same xOffset, add the Anchor width. + final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity, + mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK; + if (hgrav == Gravity.RIGHT) { + horizontalOffset += mAnchorView.getWidth(); + } + if (subPopup.tryShow(horizontalOffset, verticalOffset)) { if (mPresenterCallback != null) { mPresenterCallback.onOpenSubMenu(subMenu); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index fa86c7537d16..3f95cf460748 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -516,7 +516,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose, - jintArray fdsToIgnore, + jintArray fdsToIgnore, bool is_child_zygote, jstring instructionSet, jstring dataDir) { SetSignalHandlers(); @@ -699,7 +699,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra UnsetChldSignalHandler(); env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, - is_system_server, instructionSet); + is_system_server, is_child_zygote, instructionSet); if (env->ExceptionCheck()) { RuntimeAbort(env, __LINE__, "Error calling post fork hooks."); } @@ -748,8 +748,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name, - jintArray fdsToClose, - jintArray fdsToIgnore, + jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote, jstring instructionSet, jstring appDataDir) { jlong capabilities = 0; @@ -786,13 +785,22 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( capabilities |= (1LL << CAP_BLOCK_SUSPEND); } + // If forking a child zygote process, that zygote will need to be able to change + // the UID and GID of processes it forks, as well as drop those capabilities. + if (is_child_zygote) { + capabilities |= (1LL << CAP_SETUID); + capabilities |= (1LL << CAP_SETGID); + capabilities |= (1LL << CAP_SETPCAP); + } + // Containers run without some capabilities, so drop any caps that are not // available. capabilities &= GetEffectiveCapabilityMask(env); return ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, - se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir); + se_name, false, fdsToClose, fdsToIgnore, is_child_zygote == JNI_TRUE, + instructionSet, appDataDir); } static jint com_android_internal_os_Zygote_nativeForkSystemServer( @@ -803,7 +811,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( runtime_flags, rlimits, permittedCapabilities, effectiveCapabilities, MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL, - NULL, NULL, NULL); + NULL, false, NULL, NULL); if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -877,7 +885,7 @@ static const JNINativeMethod gMethods[] = { { "nativeSecurityInit", "()V", (void *) com_android_internal_os_Zygote_nativeSecurityInit }, { "nativeForkAndSpecialize", - "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[ILjava/lang/String;Ljava/lang/String;)I", + "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, { "nativeForkSystemServer", "(II[II[[IJJ)I", (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, @@ -892,7 +900,7 @@ static const JNINativeMethod gMethods[] = { int register_com_android_internal_os_Zygote(JNIEnv* env) { gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName)); gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks", - "(IZLjava/lang/String;)V"); + "(IZZLjava/lang/String;)V"); return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods)); } diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 956b7249660f..1383bbd77b73 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -313,10 +313,12 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { return false; } - // This is a local socket with an abstract address, we do not accept it. + // This is a local socket with an abstract address. Remove the leading NUL byte and + // add a human-readable "ABSTRACT/" prefix. if (unix_addr->sun_path[0] == '\0') { - LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with abstract address."; - return false; + *result = "ABSTRACT/"; + result->append(&unix_addr->sun_path[1], path_len - 1); + return true; } // If we're here, sun_path must refer to a null terminated filesystem diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto index ef6eb0913da4..f78ebcaa1f79 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -335,6 +335,7 @@ message GlobalSettingsProto { SettingProto uninstalled_instant_app_min_cache_period = 290; SettingProto uninstalled_instant_app_max_cache_period = 291; SettingProto unused_static_shared_lib_min_cache_period = 292; + SettingProto hidden_api_blacklist_exemptions = 293; } message SecureSettingsProto { diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index ab9912a438d4..c0a8acda628e 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1041,6 +1041,13 @@ </intent-filter> </activity> + <activity android:name="android.view.menu.ContextMenuActivity" android:label="ContextMenu" android:theme="@android:style/Theme.Material"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> + </intent-filter> + </activity> + <activity android:name="android.view.menu.MenuWith1Item" android:label="MenuWith1Item"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/core/tests/coretests/res/layout/context_menu.xml b/core/tests/coretests/res/layout/context_menu.xml new file mode 100644 index 000000000000..3b9e2bdb3130 --- /dev/null +++ b/core/tests/coretests/res/layout/context_menu.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2018, 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. +*/ +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/context_menu_target_ltr" + android:orientation="horizontal" + android:layoutDirection="ltr" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="50px" + android:layout_marginEnd="50px"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="LTR"/> + </LinearLayout> + + <LinearLayout + android:id="@+id/context_menu_target_rtl" + android:orientation="horizontal" + android:layoutDirection="rtl" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="50px" + android:layout_marginEnd="50px"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="RTL"/> + </LinearLayout> + +</LinearLayout> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index ee276ef11957..757a70ca834e 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -413,7 +413,8 @@ public class SettingsBackupTest { Settings.Global.WTF_IS_FATAL, Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_CONFIG_ETAG, - Settings.Global.ZEN_MODE_RINGER_LEVEL); + Settings.Global.ZEN_MODE_RINGER_LEVEL, + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS); private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( diff --git a/core/tests/coretests/src/android/util/PollingCheck.java b/core/tests/coretests/src/android/util/PollingCheck.java new file mode 100644 index 000000000000..468b9b2a4864 --- /dev/null +++ b/core/tests/coretests/src/android/util/PollingCheck.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2017 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.util; + +import org.junit.Assert; + +/** + * Utility used for testing that allows to poll for a certain condition to happen within a timeout. + * + * Code copied from com.android.compatibility.common.util.PollingCheck + */ +public abstract class PollingCheck { + + private static final long DEFAULT_TIMEOUT = 3000; + private static final long TIME_SLICE = 50; + private final long mTimeout; + + /** + * The condition that the PollingCheck should use to proceed successfully. + */ + public interface PollingCheckCondition { + + /** + * @return Whether the polling condition has been met. + */ + boolean canProceed(); + } + + public PollingCheck(long timeout) { + mTimeout = timeout; + } + + protected abstract boolean check(); + + /** + * Start running the polling check. + */ + public void run() { + if (check()) { + return; + } + + long timeout = mTimeout; + while (timeout > 0) { + try { + Thread.sleep(TIME_SLICE); + } catch (InterruptedException e) { + Assert.fail("unexpected InterruptedException"); + } + + if (check()) { + return; + } + + timeout -= TIME_SLICE; + } + + Assert.fail("unexpected timeout"); + } + + /** + * Instantiate and start polling for a given condition with a default 3000ms timeout. + * + * @param condition The condition to check for success. + */ + public static void waitFor(final PollingCheckCondition condition) { + new PollingCheck(DEFAULT_TIMEOUT) { + @Override + protected boolean check() { + return condition.canProceed(); + } + }.run(); + } + + /** + * Instantiate and start polling for a given condition. + * + * @param timeout Time out in ms + * @param condition The condition to check for success. + */ + public static void waitFor(long timeout, final PollingCheckCondition condition) { + new PollingCheck(timeout) { + @Override + protected boolean check() { + return condition.canProceed(); + } + }.run(); + } +} + diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java new file mode 100644 index 000000000000..830b3d549773 --- /dev/null +++ b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 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.view.menu; + +import android.app.Activity; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View; + +import com.android.frameworks.coretests.R; + +public class ContextMenuActivity extends Activity { + + static final String LABEL_ITEM = "Item"; + static final String LABEL_SUBMENU = "Submenu"; + static final String LABEL_SUBITEM = "Subitem"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.context_menu); + registerForContextMenu(getTargetLtr()); + registerForContextMenu(getTargetRtl()); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + menu.add(LABEL_ITEM); + menu.addSubMenu(LABEL_SUBMENU).add(LABEL_SUBITEM); + } + + View getTargetLtr() { + return findViewById(R.id.context_menu_target_ltr); + } + + View getTargetRtl() { + return findViewById(R.id.context_menu_target_rtl); + } +} diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java new file mode 100644 index 000000000000..59d4e55d8d45 --- /dev/null +++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 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.view.menu; + +import android.content.Context; +import android.graphics.Point; +import android.support.test.filters.MediumTest; +import android.test.ActivityInstrumentationTestCase; +import android.util.PollingCheck; +import android.view.Display; +import android.view.View; +import android.view.WindowManager; +import android.widget.espresso.ContextMenuUtils; + +@MediumTest +public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> { + + public ContextMenuTest() { + super("com.android.frameworks.coretests", ContextMenuActivity.class); + } + + public void testContextMenuPositionLtr() throws InterruptedException { + testMenuPosition(getActivity().getTargetLtr()); + } + + public void testContextMenuPositionRtl() throws InterruptedException { + testMenuPosition(getActivity().getTargetRtl()); + } + + private void testMenuPosition(View target) throws InterruptedException { + final int minScreenDimension = getMinScreenDimension(); + if (minScreenDimension < 320) { + // Assume there is insufficient room for the context menu to be aligned properly. + return; + } + + int offsetX = target.getWidth() / 2; + int offsetY = target.getHeight() / 2; + + getInstrumentation().runOnMainSync(() -> target.performLongClick(offsetX, offsetY)); + + PollingCheck.waitFor( + () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBMENU)); + + ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY); + + ContextMenuUtils.clickMenuItem(ContextMenuActivity.LABEL_SUBMENU); + + PollingCheck.waitFor( + () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBITEM)); + + if (minScreenDimension < getCascadingMenuTreshold()) { + // A non-cascading submenu should be displayed at the same location as its parent. + // Not testing cascading submenu position, as it is positioned differently. + ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY); + } + } + + /** + * Returns the minimum of the default display's width and height. + */ + private int getMinScreenDimension() { + final WindowManager windowManager = (WindowManager) getActivity().getSystemService( + Context.WINDOW_SERVICE); + final Display display = windowManager.getDefaultDisplay(); + final Point displaySize = new Point(); + display.getRealSize(displaySize); + return Math.min(displaySize.x, displaySize.y); + } + + /** + * Returns the minimum display size where cascading submenus are supported. + */ + private int getCascadingMenuTreshold() { + // Use the same dimension resource as in MenuPopupHelper.createPopup(). + return getActivity().getResources().getDimensionPixelSize( + com.android.internal.R.dimen.cascading_menus_min_smallest_width); + } +} diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java index c8218aa490f2..487a881082e7 100644 --- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java +++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java @@ -17,25 +17,32 @@ package android.widget.espresso; import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.RootMatchers.withDecorView; import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; import static android.support.test.espresso.matcher.ViewMatchers.hasFocus; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast; import static android.support.test.espresso.matcher.ViewMatchers.isEnabled; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.not; -import com.android.internal.view.menu.ListMenuItemView; - import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.ViewInteraction; import android.support.test.espresso.matcher.ViewMatchers; +import android.view.View; import android.widget.MenuPopupWindow.MenuDropDownListView; +import com.android.internal.view.menu.ListMenuItemView; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + /** * Espresso utility methods for the context menu. */ @@ -82,10 +89,15 @@ public final class ContextMenuUtils { private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel, boolean enabled) { onContextMenu().check(matches( - hasDescendant(allOf( - isAssignableFrom(ListMenuItemView.class), - enabled ? isEnabled() : not(isEnabled()), - hasDescendant(withText(itemLabel)))))); + hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled)))); + } + + private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) { + return allOf( + isAssignableFrom(ListMenuItemView.class), + hasDescendant(withText(itemLabel)), + enabled ? isEnabled() : not(isEnabled()), + isDisplayingAtLeast(90)); } /** @@ -107,4 +119,70 @@ public final class ContextMenuUtils { public static void assertContextMenuContainsItemDisabled(String itemLabel) { asssertContextMenuContainsItemWithEnabledState(itemLabel, false); } + + /** + * Asserts that the context menu window is aligned to a given view with a given offset. + * + * @param anchor Anchor view. + * @param offsetX x offset + * @param offsetY y offset. + * @throws AssertionError if the assertion fails + */ + public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) { + int [] expectedLocation = new int[2]; + anchor.getLocationOnScreen(expectedLocation); + expectedLocation[0] += offsetX; + expectedLocation[1] += offsetY; + + final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + + onContextMenu().check(matches(new TypeSafeMatcher<View>() { + @Override + public void describeTo(Description description) { + description.appendText("root view "); + description.appendText(rtl ? "right" : "left"); + description.appendText("="); + description.appendText(Integer.toString(offsetX)); + description.appendText(", top="); + description.appendText(Integer.toString(offsetY)); + } + + @Override + public boolean matchesSafely(View view) { + View rootView = view.getRootView(); + int [] actualLocation = new int[2]; + rootView.getLocationOnScreen(actualLocation); + if (rtl) { + actualLocation[0] += rootView.getWidth(); + } + return expectedLocation[0] == actualLocation[0] + && expectedLocation[1] == actualLocation[1]; + } + })); + } + + /** + * Check is the menu item is clickable (i.e. visible and enabled). + * + * @param itemLabel Label of the item. + * @return True if the menu item is clickable. + */ + public static boolean isMenuItemClickable(String itemLabel) { + try { + onContextMenu().check(matches( + hasDescendant(getVisibleMenuItemMatcher(itemLabel, true)))); + return true; + } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) { + return false; + } + } + + /** + * Click on a menu item with the specified label + * @param itemLabel Label of the item. + */ + public static void clickMenuItem(String itemLabel) { + onView(getVisibleMenuItemMatcher(itemLabel, true)) + .inRoot(withDecorView(hasFocus())).perform(click()); + } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index d256b12fe285..d32db8491b3a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -924,6 +924,9 @@ class SettingsProtoDumpUtil { Settings.Global.CONTACTS_DATABASE_WAL_ENABLED, GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED); dumpSetting(s, p, + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS, + GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS); + dumpSetting(s, p, Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION); dumpSetting(s, p, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 81b8622c548f..4320b6aa572c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -76,6 +76,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { @Override public void handleSetListening(boolean listening) { + if (mController == null) return; if (listening) { mController.addCallback(mCallback); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 9e265e2295c3..52b4c0ac4e1a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -235,6 +235,7 @@ public class DndTile extends QSTileImpl<BooleanState> { public void handleSetListening(boolean listening) { if (mListening == listening) return; mListening = listening; + if (mController == null) return; if (mListening) { mController.addCallback(mZenCallback); Prefs.registerListener(mContext, mPrefListener); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index b3ff4e5b890c..12daff1f12f9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -98,6 +98,8 @@ public class NfcTile extends QSTileImpl<BooleanState> { protected void handleUpdateState(BooleanState state, Object arg) { final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled); final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled); + + if (getAdapter() == null) return; state.value = getAdapter().isEnabled(); state.label = mContext.getString(R.string.quick_settings_nfc_label); state.icon = new DrawableIcon(state.value ? mEnable : mDisable); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0cce2d9ae56d..470005788016 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1738,6 +1738,9 @@ public class ActivityManagerService extends IActivityManager.Stub final ActivityManagerConstants mConstants; + // Encapsulates the global setting "hidden_api_blacklist_exemptions" + final HiddenApiBlacklist mHiddenApiBlacklist; + PackageManagerInternal mPackageManagerInt; // VoiceInteraction session ID that changes for each new request except when @@ -2687,6 +2690,42 @@ public class ActivityManagerService extends IActivityManager.Stub } } + /** + * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the + * latest value via a content observer. + */ + static class HiddenApiBlacklist extends ContentObserver { + + private final Context mContext; + private boolean mBlacklistDisabled; + + public HiddenApiBlacklist(Handler handler, Context context) { + super(handler); + mContext = context; + } + + public void registerObserver() { + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS), + false, + this); + update(); + } + + private void update() { + mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS)); + } + + boolean isDisabled() { + return mBlacklistDisabled; + } + + public void onChange(boolean selfChange) { + update(); + } + } + @VisibleForTesting public ActivityManagerService(Injector injector) { mInjector = injector; @@ -2716,6 +2755,7 @@ public class ActivityManagerService extends IActivityManager.Stub mUiHandler = injector.getUiHandler(null); mUserController = null; mVrController = null; + mHiddenApiBlacklist = null; } // Note: This method is invoked on the main thread but may need to attach various @@ -2848,6 +2888,8 @@ public class ActivityManagerService extends IActivityManager.Stub } }; + mHiddenApiBlacklist = new HiddenApiBlacklist(mHandler, mContext); + Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); } @@ -3891,9 +3933,9 @@ public class ActivityManagerService extends IActivityManager.Stub runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES; } - if (!app.info.isAllowedToUseHiddenApi()) { - // This app is not allowed to use undocumented and private APIs. - // Set up its runtime with the appropriate flag. + if (!app.info.isAllowedToUseHiddenApi() && !mHiddenApiBlacklist.isDisabled()) { + // This app is not allowed to use undocumented and private APIs, or blacklisting is + // enabled. Set up its runtime with the appropriate flag. runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS; } @@ -14165,6 +14207,7 @@ public class ActivityManagerService extends IActivityManager.Stub NETWORK_ACCESS_TIMEOUT_MS, NETWORK_ACCESS_TIMEOUT_DEFAULT_MS); final boolean supportsLeanbackOnly = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK_ONLY); + mHiddenApiBlacklist.registerObserver(); // Transfer any global setting for forcing RTL layout, into a System Property SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0"); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 21f14cddd396..505480ea537e 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -285,7 +285,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { int delta = add ? +1 : -1; switch (request.type) { case REQUEST: - case TRACK_DEFAULT: mNumRequestNetworkRequests += delta; break; @@ -294,6 +293,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { mNumBackgroundNetworkRequests += delta; break; + case TRACK_DEFAULT: case LISTEN: break; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index e5f4282eefe0..0cba76ba7346 100644..100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -660,7 +660,8 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly void startQueuedActions() { assertRunOnServiceThread(); - for (HdmiCecFeatureAction action : mActions) { + // Use copied action list in that start() may remove itself. + for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) { if (!action.started()) { Slog.i(TAG, "Starting queued action:" + action); action.start(); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index a52bd4e8883b..ab3c9996c59a 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -286,14 +286,14 @@ public class Installer extends SystemService { int dexoptNeeded, @Nullable String outputPath, int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade, int targetSdkVersion, - @Nullable String profileName, @Nullable String dexMetadataPath) - throws InstallerException { + @Nullable String profileName, @Nullable String dexMetadataPath, + @Nullable String compilationReason) throws InstallerException { assertValidInstructionSet(instructionSet); if (!checkBeforeRemote()) return; try { mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade, - targetSdkVersion, profileName, dexMetadataPath); + targetSdkVersion, profileName, dexMetadataPath, compilationReason); } catch (Exception e) { throw InstallerException.from(e); } diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 232743c699a8..b6804ba577e6 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -262,11 +262,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub { int dexFlags, String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade, int targetSdkVersion, @Nullable String profileName, - @Nullable String dexMetadataPath) throws InstallerException { + @Nullable String dexMetadataPath, @Nullable String dexoptCompilationReason) + throws InstallerException { final StringBuilder builder = new StringBuilder(); - // The version. Right now it's 6. - builder.append("6 "); + // The version. Right now it's 7. + builder.append("7 "); builder.append("dexopt"); @@ -285,6 +286,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { encodeParameter(builder, targetSdkVersion); encodeParameter(builder, profileName); encodeParameter(builder, dexMetadataPath); + encodeParameter(builder, dexoptCompilationReason); commands.add(builder.toString()); } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 126ee8033051..51e035b1676d 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -34,7 +34,6 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.pm.Installer.InstallerException; -import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.DexoptUtils; import com.android.server.pm.dex.PackageDexUsage; @@ -63,7 +62,8 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT; -import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getReasonName; + import static dalvik.system.DexFile.getSafeModeCompilerFilter; import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; @@ -236,7 +236,8 @@ public class PackageDexOptimizer { for (String dexCodeIsa : dexCodeInstructionSets) { int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid, - packageStats, options.isDowngrade(), profileName, dexMetadataPath); + packageStats, options.isDowngrade(), profileName, dexMetadataPath, + options.getCompilationReason()); // The end result is: // - FAILED if any path failed, // - PERFORMED if at least one path needed compilation, @@ -261,7 +262,7 @@ public class PackageDexOptimizer { private int dexOptPath(PackageParser.Package pkg, String path, String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, - String profileName, String dexMetadataPath) { + String profileName, String dexMetadataPath, int compilationReason) { int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext, profileUpdated, downgrade); if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { @@ -288,7 +289,7 @@ public class PackageDexOptimizer { mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo, false /* downgrade*/, pkg.applicationInfo.targetSdkVersion, - profileName, dexMetadataPath); + profileName, dexMetadataPath, getReasonName(compilationReason)); if (packageStats != null) { long endTime = System.currentTimeMillis(); @@ -399,7 +400,7 @@ public class PackageDexOptimizer { // Note this trades correctness for performance since the resulting slow down is // unacceptable in some cases until b/64530081 is fixed. String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK; - + int reason = options.getCompilationReason(); try { for (String isa : dexUseInfo.getLoaderIsas()) { // Reuse the same dexopt path as for the primary apks. We don't need all the @@ -410,7 +411,7 @@ public class PackageDexOptimizer { /*oatDir*/ null, dexoptFlags, compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser, options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null, - /*dexMetadataPath*/ null); + /*dexMetadataPath*/ null, getReasonName(reason)); } return DEX_OPT_PERFORMED; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3466f55596cb..49976350633e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -575,6 +575,7 @@ public class PackageManagerService extends IPackageManager.Stub } // Compilation reasons. + public static final int REASON_UNKNOWN = -1; public static final int REASON_FIRST_BOOT = 0; public static final int REASON_BOOT = 1; public static final int REASON_INSTALL = 2; @@ -9710,7 +9711,7 @@ public class PackageManagerService extends IPackageManager.Stub final long startTime = System.nanoTime(); final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */, - getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT), + causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT, false /* bootComplete */); final int elapsedTimeSeconds = @@ -9737,7 +9738,7 @@ public class PackageManagerService extends IPackageManager.Stub * and {@code numberOfPackagesFailed}. */ private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog, - final String compilerFilter, boolean bootComplete) { + final int compilationReason, boolean bootComplete) { int numberOfPackagesVisited = 0; int numberOfPackagesOptimized = 0; @@ -9837,13 +9838,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - String pkgCompilerFilter = compilerFilter; + int pkgCompilationReason = compilationReason; if (useProfileForDexopt) { // Use background dexopt mode to try and use the profile. Note that this does not // guarantee usage of the profile. - pkgCompilerFilter = - PackageManagerServiceCompilerMapping.getCompilerFilterForReason( - PackageManagerService.REASON_BACKGROUND_DEXOPT); + pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT; } // checkProfiles is false to avoid merging profiles during boot which @@ -9854,7 +9853,7 @@ public class PackageManagerService extends IPackageManager.Stub int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0; int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( pkg.packageName, - pkgCompilerFilter, + pkgCompilationReason, dexoptFlags)); switch (primaryDexOptStaus) { @@ -9954,8 +9953,8 @@ public class PackageManagerService extends IPackageManager.Stub int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) | (force ? DexoptOptions.DEXOPT_FORCE : 0) | (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0); - return performDexOpt(new DexoptOptions(packageName, targetCompilerFilter, - splitName, flags)); + return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN, + targetCompilerFilter, splitName, flags)); } /** @@ -10064,7 +10063,8 @@ public class PackageManagerService extends IPackageManager.Stub final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), - options.getCompilerFilter(), options.getSplitName(), + options.getCompilationReason(), options.getCompilerFilter(), + options.getSplitName(), options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); for (PackageParser.Package depPackage : deps) { // TODO: Analyze and investigate if we (should) profile libraries. diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java index 19b0d9bc4b90..fce828581c54 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java @@ -123,4 +123,14 @@ public class PackageManagerServiceCompilerMapping { return value; } + + public static String getReasonName(int reason) { + if (reason == PackageManagerService.REASON_UNKNOWN) { + return "unknown"; + } + if (reason < 0 || reason >= REASON_STRINGS.length) { + throw new IllegalArgumentException("reason " + reason + " invalid"); + } + return REASON_STRINGS[reason]; + } } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 0e2730cbd944..3e63fb42f0ef 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -549,13 +549,12 @@ public class DexManager { mPackageDexUsage.maybeWriteAsync(); } - // Try to optimize the package according to the install reason. - String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason( - PackageManagerService.REASON_INSTALL); DexUseInfo dexUseInfo = mPackageDexUsage.getPackageUseInfo(searchResult.mOwningPackageName) .getDexUseInfoMap().get(dexPath); - DexoptOptions options = new DexoptOptions(info.packageName, compilerFilter, /*flags*/0); + // Try to optimize the package according to the install reason. + DexoptOptions options = new DexoptOptions(info.packageName, + PackageManagerService.REASON_INSTALL, /*flags*/0); int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, dexUseInfo, options); diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java index d4f95cb6b99f..a7a7686b2a6b 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java +++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java @@ -77,15 +77,21 @@ public final class DexoptOptions { // It only applies for primary apk and it's always null if mOnlySecondaryDex is true. private final String mSplitName; + // The reason for invoking dexopt (see PackageManagerService.REASON_* constants). + // A -1 value denotes an unknown reason. + private final int mCompilationReason; + public DexoptOptions(String packageName, String compilerFilter, int flags) { - this(packageName, compilerFilter, /*splitName*/ null, flags); + this(packageName, /*compilationReason*/ -1, compilerFilter, /*splitName*/ null, flags); } - public DexoptOptions(String packageName, int compilerReason, int flags) { - this(packageName, getCompilerFilterForReason(compilerReason), flags); + public DexoptOptions(String packageName, int compilationReason, int flags) { + this(packageName, compilationReason, getCompilerFilterForReason(compilationReason), + /*splitName*/ null, flags); } - public DexoptOptions(String packageName, String compilerFilter, String splitName, int flags) { + public DexoptOptions(String packageName, int compilationReason, String compilerFilter, + String splitName, int flags) { int validityMask = DEXOPT_CHECK_FOR_PROFILES_UPDATES | DEXOPT_FORCE | @@ -104,6 +110,7 @@ public final class DexoptOptions { mCompilerFilter = compilerFilter; mFlags = flags; mSplitName = splitName; + mCompilationReason = compilationReason; } public String getPackageName() { @@ -157,4 +164,8 @@ public final class DexoptOptions { public int getFlags() { return mFlags; } + + public int getCompilationReason() { + return mCompilationReason; + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java index f559986a6f15..93064bc4ab92 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java @@ -118,7 +118,7 @@ public class DexoptOptionsTests { public void testCreateDexoptOptionsSplit() { int flags = DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE; - DexoptOptions opt = new DexoptOptions(mPackageName, mCompilerFilter, mSplitName, flags); + DexoptOptions opt = new DexoptOptions(mPackageName, -1, mCompilerFilter, mSplitName, flags); assertEquals(mPackageName, opt.getPackageName()); assertEquals(mCompilerFilter, opt.getCompilerFilter()); assertEquals(mSplitName, opt.getSplitName()); diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index f009fb145fc2..7e86966e2c1b 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -172,7 +172,7 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P } /** - * Get the timing advance value for LTE, as a value between 0..63. + * Get the timing advance value for LTE, as a value in range of 0..1282. * Integer.MAX_VALUE is reported when there is no active RRC * connection. Refer to 3GPP 36.213 Sec 4.2.3 * @return the LTE timing advance, if available. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 71e7ca1fd30c..dfccff44f1f0 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -52,6 +52,7 @@ import android.telephony.ims.aidl.IImsMmTelFeature; import android.telephony.ims.aidl.IImsRcsFeature; import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; import com.android.ims.internal.IImsServiceFeatureCallback; @@ -6236,84 +6237,106 @@ public class TelephonyManager { return false; } - /** - * Returns the IMS Registration Status - * @hide - */ - public boolean isImsRegistered() { - try { - ITelephony telephony = getITelephony(); - if (telephony == null) - return false; - return telephony.isImsRegistered(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { - return false; - } - } - /** - * Returns the IMS Registration Status for a particular Subscription ID + * Returns the IMS Registration Status for a particular Subscription ID. * * @param subId Subscription ID * @return true if IMS status is registered, false if the IMS status is not registered or a * RemoteException occurred. - * * @hide */ public boolean isImsRegistered(int subId) { + try { + return getITelephony().isImsRegistered(subId); + } catch (RemoteException | NullPointerException ex) { + return false; + } + } + + /** + * Returns the IMS Registration Status for a particular Subscription ID, which is determined + * when the TelephonyManager is created using {@link #createForSubscriptionId(int)}. If an + * invalid subscription ID is used during creation, will the default subscription ID will be + * used. + * + * @return true if IMS status is registered, false if the IMS status is not registered or a + * RemoteException occurred. + * @see SubscriptionManager#getDefaultSubscriptionId() + * @hide + */ + public boolean isImsRegistered() { try { - return getITelephony().isImsRegisteredForSubscriber(subId); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { + return getITelephony().isImsRegistered(getSubId()); + } catch (RemoteException | NullPointerException ex) { return false; } } /** - * Returns the Status of Volte + * The current status of Voice over LTE for the subscription associated with this instance when + * it was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was + * used during creation, the default subscription ID will be used. + * @return true if Voice over LTE is available or false if it is unavailable or unknown. + * @see SubscriptionManager#getDefaultSubscriptionId() * @hide */ public boolean isVolteAvailable() { - try { - return getITelephony().isVolteAvailable(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { - return false; - } - } + try { + return getITelephony().isVolteAvailable(getSubId()); + } catch (RemoteException | NullPointerException ex) { + return false; + } + } /** - * Returns the Status of video telephony (VT) + * The availability of Video Telephony (VT) for the subscription ID specified when this instance + * was created using {@link #createForSubscriptionId(int)}. If an invalid subscription ID was + * used during creation, the default subscription ID will be used. To query the + * underlying technology that VT is available on, use {@link #getImsRegTechnologyForMmTel}. + * @return true if VT is available, or false if it is unavailable or unknown. * @hide */ public boolean isVideoTelephonyAvailable() { try { - return getITelephony().isVideoTelephonyAvailable(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { + return getITelephony().isVideoTelephonyAvailable(getSubId()); + } catch (RemoteException | NullPointerException ex) { return false; } } /** - * Returns the Status of Wi-Fi Calling + * Returns the Status of Wi-Fi calling (Voice over WiFi) for the subscription ID specified. + * @param subId the subscription ID. + * @return true if VoWiFi is available, or false if it is unavailable or unknown. * @hide */ public boolean isWifiCallingAvailable() { try { - return getITelephony().isWifiCallingAvailable(); - } catch (RemoteException ex) { - return false; - } catch (NullPointerException ex) { + return getITelephony().isWifiCallingAvailable(getSubId()); + } catch (RemoteException | NullPointerException ex) { return false; } } + /** + * The technology that IMS is registered for for the MMTEL feature. + * @param subId subscription ID to get IMS registration technology for. + * @return The IMS registration technology that IMS is registered to for the MMTEL feature. + * Valid return results are: + * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} for LTE registration, + * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} for IWLAN registration, or + * - {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE} if we are not registered or the + * result is unavailable. + * @hide + */ + public @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegTechnologyForMmTel() { + try { + return getITelephony().getImsRegTechnologyForMmTel(getSubId()); + } catch (RemoteException ex) { + return ImsRegistrationImplBase.REGISTRATION_TECH_NONE; + } + } + /** * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone. * diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index bfdd4533275b..1fdbae9186b7 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -80,7 +80,7 @@ public abstract class ImsFeature { public static final String EXTRA_PHONE_ID = "android:phone_id"; /** - * Invalid feature value\ + * Invalid feature value * @hide */ public static final int FEATURE_INVALID = -1; diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2b4c059cf69f..02cc82cf56b0 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1123,33 +1123,33 @@ interface ITelephony { boolean isHearingAidCompatibilitySupported(); /** - * Get IMS Registration Status - */ - boolean isImsRegistered(); - - /** * Get IMS Registration Status on a particular subid. * * @param subId user preferred subId. * * @return {@code true} if the IMS status is registered. */ - boolean isImsRegisteredForSubscriber(int subId); + boolean isImsRegistered(int subId); /** - * Returns the Status of Wi-Fi Calling + * Returns the Status of Wi-Fi Calling for the subscription id specified. */ - boolean isWifiCallingAvailable(); + boolean isWifiCallingAvailable(int subId); /** - * Returns the Status of Volte + * Returns the Status of VoLTE for the subscription ID specified. */ - boolean isVolteAvailable(); + boolean isVolteAvailable(int subId); /** - * Returns the Status of VT (video telephony) + * Returns the Status of VT (video telephony) for the subscription ID specified. */ - boolean isVideoTelephonyAvailable(); + boolean isVideoTelephonyAvailable(int subId); + + /** + * Returns the MMTEL IMS registration technology for the subsciption ID specified. + */ + int getImsRegTechnologyForMmTel(int subId); /** * Returns the unique device ID of phone, for example, the IMEI for diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java index b4342df58549..ffd1f063e48b 100644 --- a/tests/net/java/android/net/IpSecTransformTest.java +++ b/tests/net/java/android/net/IpSecTransformTest.java @@ -17,6 +17,7 @@ package android.net; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import android.support.test.filters.SmallTest; @@ -56,6 +57,6 @@ public class IpSecTransformTest { IpSecTransform config1 = new IpSecTransform(null, config); IpSecTransform config2 = new IpSecTransform(null, config); - assertFalse(IpSecTransform.equals(config1, config2)); + assertTrue(IpSecTransform.equals(config1, config2)); } } |