diff options
60 files changed, 1248 insertions, 620 deletions
diff --git a/api/current.txt b/api/current.txt index 19e0af95a15c..8b9a5af540ef 100755 --- a/api/current.txt +++ b/api/current.txt @@ -40418,6 +40418,8 @@ package android.system { public final class ErrnoException extends java.lang.Exception { ctor public ErrnoException(String, int); ctor public ErrnoException(String, int, Throwable); + method @NonNull public java.io.IOException rethrowAsIOException() throws java.io.IOException; + method @NonNull public java.net.SocketException rethrowAsSocketException() throws java.net.SocketException; field public final int errno; } diff --git a/api/system-current.txt b/api/system-current.txt index 82bf26c2a9c6..cf55fbef1ff5 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7706,7 +7706,7 @@ package android.telephony.mbms { package android.telephony.mbms.vendor { - public class MbmsDownloadServiceBase extends android.os.Binder { + public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface { ctor public MbmsDownloadServiceBase(); method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException; method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException; @@ -7739,7 +7739,7 @@ package android.telephony.mbms.vendor { method public void updateGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>); } - public class MbmsStreamingServiceBase extends android.os.Binder { + public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface { ctor public MbmsStreamingServiceBase(); method public android.os.IBinder asBinder(); method public void dispose(int) throws android.os.RemoteException; diff --git a/api/test-current.txt b/api/test-current.txt index e9dae4ed0925..e813523f46a2 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1589,7 +1589,7 @@ package android.telephony.mbms { package android.telephony.mbms.vendor { - public class MbmsDownloadServiceBase extends android.os.Binder { + public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface { ctor public MbmsDownloadServiceBase(); method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException; method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException; @@ -1622,7 +1622,7 @@ package android.telephony.mbms.vendor { method public void updateGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>); } - public class MbmsStreamingServiceBase extends android.os.Binder { + public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface { ctor public MbmsStreamingServiceBase(); method public android.os.IBinder asBinder(); method public void dispose(int) throws android.os.RemoteException; diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto index 7dfe7d6ecb7e..39de357cd6d2 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -82,4 +82,6 @@ extend google.protobuf.FieldOptions { optional bool is_uid = 50001 [default = false]; optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC]; -}
\ No newline at end of file + + optional string log_from_module = 50004; +} diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java index 8ffafe4bc364..86d9f89f2a7c 100644 --- a/core/java/android/os/SELinux.java +++ b/core/java/android/os/SELinux.java @@ -31,12 +31,15 @@ import java.io.IOException; public class SELinux { private static final String TAG = "SELinux"; - /** Keep in sync with ./external/libselinux/include/selinux/android.h */ + /** Keep in sync with ./external/selinux/libselinux/include/selinux/android.h */ private static final int SELINUX_ANDROID_RESTORECON_NOCHANGE = 1; private static final int SELINUX_ANDROID_RESTORECON_VERBOSE = 2; private static final int SELINUX_ANDROID_RESTORECON_RECURSE = 4; private static final int SELINUX_ANDROID_RESTORECON_FORCE = 8; private static final int SELINUX_ANDROID_RESTORECON_DATADATA = 16; + private static final int SELINUX_ANDROID_RESTORECON_SKIPCE = 32; + private static final int SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS = 64; + private static final int SELINUX_ANDROID_RESTORECON_SKIP_SEHASH = 128; /** * Determine whether SELinux is disabled or enabled. @@ -175,7 +178,8 @@ public class SELinux { @UnsupportedAppUsage public static boolean restoreconRecursive(File file) { try { - return native_restorecon(file.getCanonicalPath(), SELINUX_ANDROID_RESTORECON_RECURSE); + return native_restorecon(file.getCanonicalPath(), + SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIP_SEHASH); } catch (IOException e) { Slog.e(TAG, "Error getting canonical path. Restorecon failed for " + file.getPath(), e); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 946d38667fea..8c4d9be0f7f5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7319,15 +7319,6 @@ public final class Settings { "call_screening_default_component"; /** - * Specifies the component name currently configured to be the default application to - * perform the user-defined call redirection service with Telecom. - * @hide - */ - @UnsupportedAppUsage - public static final String CALL_REDIRECTION_DEFAULT_APPLICATION = - "call_redirection_default_application"; - - /** * Specifies the package name currently configured to be the emergency assistance application * * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java index a5e38189f39b..8061bf36fa6a 100644 --- a/core/java/android/util/PackageUtils.java +++ b/core/java/android/util/PackageUtils.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.Signature; +import libcore.util.HexEncoding; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.MessageDigest; @@ -125,6 +127,10 @@ public final class PackageUtils { * @return The digest or null if an error occurs. */ public static @Nullable String computeSha256Digest(@NonNull byte[] data) { - return ByteStringUtils.toHexString(computeSha256DigestBytes(data)); + byte[] sha256DigestBytes = computeSha256DigestBytes(data); + if (sha256DigestBytes == null) { + return null; + } + return HexEncoding.encodeToString(sha256DigestBytes, true /* uppercase */); } } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 6024f68a1c3a..e508b02a7dba 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -196,7 +196,6 @@ cc_library_shared { "android_content_res_Configuration.cpp", "android_animation_PropertyValuesHolder.cpp", "android_security_Scrypt.cpp", - "com_android_internal_net_NetworkStatsFactory.cpp", "com_android_internal_os_ClassLoaderFactory.cpp", "com_android_internal_os_FuseAppLoop.cpp", "com_android_internal_os_Zygote.cpp", @@ -288,6 +287,7 @@ cc_library_shared { "libnativewindow", "libhwui", "libdl", + "libdl_android", "libstatslog", "server_configurable_flags", ], diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 79850d03160a..d04295f11680 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -213,7 +213,6 @@ extern int register_android_content_res_Configuration(JNIEnv* env); extern int register_android_animation_PropertyValuesHolder(JNIEnv *env); extern int register_android_security_Scrypt(JNIEnv *env); extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env); -extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env); extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env); extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env); extern int register_com_android_internal_os_Zygote(JNIEnv *env); @@ -1538,7 +1537,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_animation_PropertyValuesHolder), REG_JNI(register_android_security_Scrypt), REG_JNI(register_com_android_internal_content_NativeLibraryHelper), - REG_JNI(register_com_android_internal_net_NetworkStatsFactory), REG_JNI(register_com_android_internal_os_FuseAppLoop), }; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index d8c68b436bb3..d26425ae0969 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -69,6 +69,7 @@ #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> +#include <cutils/ashmem.h> #include <cutils/fs.h> #include <cutils/multiuser.h> #include <private/android_filesystem_config.h> @@ -1486,6 +1487,11 @@ static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclas } else { ALOGE("Unable to fetch Blastula pool socket file descriptor"); } + + /* + * ashmem initialization to avoid dlopen overhead + */ + ashmem_init(); } /** diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 8e6db0b74dec..2071b989aef7 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -453,7 +453,6 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ } if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) { - LOG(INFO) << "Ignoring open file descriptor " << fd; continue; } @@ -487,7 +486,6 @@ void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_ } if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) { - LOG(INFO) << "Ignoring open file descriptor " << fd; continue; } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 7698d271cfac..f1e9d659e0fd 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -302,14 +302,15 @@ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> <integer translatable="false" name="config_networkAvoidBadWifi">1</integer> - <!-- The URL returned by ConnectivityManager#getCaptivePortalServerUrl. The actual returned - value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL. This is the default value - used if that setting is unset. + <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl. + If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL, + and if that value is empty, the framework will use a hard-coded default. This is *NOT* a URL that will always be used by the system network validation to detect captive portals: NetworkMonitor may use different strategies and will not necessarily use this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays instead. --> - <string translatable="false" name="config_networkDefaultCaptivePortalServerUrl">http://connectivitycheck.gstatic.com/generate_204</string> + <!--suppress CheckTagEmptyBody --> + <string translatable="false" name="config_networkCaptivePortalServerUrl"></string> <!-- If the hardware supports specially marking packets that caused a wakeup of the main CPU, set this value to the mark used. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 05303c96ea80..e98a98487f36 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1945,7 +1945,7 @@ <java-symbol type="integer" name="config_networkNotifySwitchType" /> <java-symbol type="array" name="config_networkNotifySwitches" /> <java-symbol type="integer" name="config_networkAvoidBadWifi" /> - <java-symbol type="string" name="config_networkDefaultCaptivePortalServerUrl" /> + <java-symbol type="string" name="config_networkCaptivePortalServerUrl" /> <java-symbol type="integer" name="config_networkWakeupPacketMark" /> <java-symbol type="integer" name="config_networkWakeupPacketMask" /> <java-symbol type="bool" name="config_apfDrop802_3Frames" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index af03aacc7a8a..64dc17828aa5 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -537,7 +537,6 @@ public class SettingsBackupTest { Settings.Secure.BACKUP_ENABLED, Settings.Secure.BACKUP_PROVISIONED, Settings.Secure.BACKUP_TRANSPORT, - Settings.Secure.CALL_REDIRECTION_DEFAULT_APPLICATION, Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT, Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup? Settings.Secure.CARRIER_APPS_HANDLED, diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java index 3838a99969f0..b5c4cca12ff7 100644 --- a/media/java/android/media/MediaHTTPConnection.java +++ b/media/java/android/media/MediaHTTPConnection.java @@ -24,6 +24,7 @@ import android.os.IBinder; import android.os.StrictMode; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -37,7 +38,6 @@ import java.net.URL; import java.net.UnknownServiceException; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @@ -47,23 +47,42 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // connection timeout - 30 sec private static final int CONNECT_TIMEOUT_MS = 30 * 1000; + @GuardedBy("this") + @UnsupportedAppUsage + private long mCurrentOffset = -1; + + @GuardedBy("this") + @UnsupportedAppUsage + private URL mURL = null; + + @GuardedBy("this") + @UnsupportedAppUsage + private Map<String, String> mHeaders = null; + + // volatile so that disconnect() can be called without acquiring a lock. + // All other access is @GuardedBy("this"). + @UnsupportedAppUsage + private volatile HttpURLConnection mConnection = null; + + @GuardedBy("this") + @UnsupportedAppUsage + private long mTotalSize = -1; + + @GuardedBy("this") + private InputStream mInputStream = null; + + @GuardedBy("this") + @UnsupportedAppUsage + private boolean mAllowCrossDomainRedirect = true; + + @GuardedBy("this") + @UnsupportedAppUsage + private boolean mAllowCrossProtocolRedirect = true; + // from com.squareup.okhttp.internal.http private final static int HTTP_TEMP_REDIRECT = 307; private final static int MAX_REDIRECTS = 20; - class ConnectionState { - public HttpURLConnection mConnection = null; - public InputStream mInputStream = null; - public long mCurrentOffset = -1; - public Map<String, String> mHeaders = null; - public URL mURL = null; - public long mTotalSize = -1; - public boolean mAllowCrossDomainRedirect = true; - public boolean mAllowCrossProtocolRedirect = true; - } - private final AtomicReference<ConnectionState> mConnectionStateHolder = - new AtomicReference<ConnectionState>(); - @UnsupportedAppUsage public MediaHTTPConnection() { CookieHandler cookieHandler = CookieHandler.getDefault(); @@ -76,34 +95,24 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage - public IBinder connect(String uri, String headers) { + public synchronized IBinder connect(String uri, String headers) { if (VERBOSE) { Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers); } - ConnectionState connectionState = mConnectionStateHolder.get(); - synchronized (this) { - if (connectionState == null) { - connectionState = new ConnectionState(); - mConnectionStateHolder.set(connectionState); - } - } - try { disconnect(); - connectionState.mAllowCrossDomainRedirect = true; - connectionState.mURL = new URL(uri); - connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState); + mAllowCrossDomainRedirect = true; + mURL = new URL(uri); + mHeaders = convertHeaderStringToMap(headers); } catch (MalformedURLException e) { return null; - } finally { - mConnectionStateHolder.set(connectionState); } return native_getIMemory(); } - private boolean parseBoolean(String val) { + private static boolean parseBoolean(String val) { try { return Long.parseLong(val) != 0; } catch (NumberFormatException e) { @@ -113,21 +122,18 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } /* returns true iff header is internal */ - private boolean filterOutInternalHeaders( - String key, String val, ConnectionState connectionState) { + private synchronized boolean filterOutInternalHeaders(String key, String val) { if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) { - connectionState.mAllowCrossDomainRedirect = parseBoolean(val); + mAllowCrossDomainRedirect = parseBoolean(val); // cross-protocol redirects are also controlled by this flag - connectionState.mAllowCrossProtocolRedirect = - connectionState.mAllowCrossDomainRedirect; + mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect; } else { return false; } return true; } - private Map<String, String> convertHeaderStringToMap(String headers, - ConnectionState connectionState) { + private synchronized Map<String, String> convertHeaderStringToMap(String headers) { HashMap<String, String> map = new HashMap<String, String>(); String[] pairs = headers.split("\r\n"); @@ -137,7 +143,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { String key = pair.substring(0, colonPos); String val = pair.substring(colonPos + 1); - if (!filterOutInternalHeaders(key, val, connectionState)) { + if (!filterOutInternalHeaders(key, val)) { map.put(key, val); } } @@ -149,28 +155,36 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public void disconnect() { - ConnectionState connectionState = mConnectionStateHolder.getAndSet(null); - if (connectionState != null) { - teardownConnection(connectionState); - connectionState.mHeaders = null; - connectionState.mURL = null; + HttpURLConnection connectionToDisconnect = mConnection; + // Call disconnect() before blocking for the lock in order to ensure that any + // other thread that is blocked in readAt() will return quickly. + if (connectionToDisconnect != null) { + connectionToDisconnect.disconnect(); + } + synchronized (this) { + // It's unlikely but possible that while we were waiting to acquire the lock, another + // thread concurrently started a new connection; if so, we're disconnecting that one + // here, too. + teardownConnection(); + mHeaders = null; + mURL = null; } } - private void teardownConnection(ConnectionState connectionState) { - if (connectionState.mConnection != null) { - if (connectionState.mInputStream != null) { + private synchronized void teardownConnection() { + if (mConnection != null) { + if (mInputStream != null) { try { - connectionState.mInputStream.close(); + mInputStream.close(); } catch (IOException e) { } - connectionState.mInputStream = null; + mInputStream = null; } - connectionState.mConnection.disconnect(); - connectionState.mConnection = null; + mConnection.disconnect(); + mConnection = null; - connectionState.mCurrentOffset = -1; + mCurrentOffset = -1; } } @@ -197,44 +211,42 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { return false; } - private void seekTo(long offset, ConnectionState connectionState) throws IOException { - teardownConnection(connectionState); + private synchronized void seekTo(long offset) throws IOException { + teardownConnection(); try { int response; int redirectCount = 0; - URL url = connectionState.mURL; + URL url = mURL; // do not use any proxy for localhost (127.0.0.1) boolean noProxy = isLocalHost(url); while (true) { if (noProxy) { - connectionState.mConnection = - (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); + mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); } else { - connectionState.mConnection = (HttpURLConnection) url.openConnection(); + mConnection = (HttpURLConnection)url.openConnection(); } - connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); + mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); // handle redirects ourselves if we do not allow cross-domain redirect - connectionState.mConnection.setInstanceFollowRedirects( - connectionState.mAllowCrossDomainRedirect); + mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); - if (connectionState.mHeaders != null) { - for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) { - connectionState.mConnection.setRequestProperty( + if (mHeaders != null) { + for (Map.Entry<String, String> entry : mHeaders.entrySet()) { + mConnection.setRequestProperty( entry.getKey(), entry.getValue()); } } if (offset > 0) { - connectionState.mConnection.setRequestProperty( + mConnection.setRequestProperty( "Range", "bytes=" + offset + "-"); } - response = connectionState.mConnection.getResponseCode(); + response = mConnection.getResponseCode(); if (response != HttpURLConnection.HTTP_MULT_CHOICE && response != HttpURLConnection.HTTP_MOVED_PERM && response != HttpURLConnection.HTTP_MOVED_TEMP && @@ -248,7 +260,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new NoRouteToHostException("Too many redirects: " + redirectCount); } - String method = connectionState.mConnection.getRequestMethod(); + String method = mConnection.getRequestMethod(); if (response == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { // "If the 307 status code is received in response to a @@ -256,35 +268,34 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // automatically redirect the request" throw new NoRouteToHostException("Invalid redirect"); } - String location = connectionState.mConnection.getHeaderField("Location"); + String location = mConnection.getHeaderField("Location"); if (location == null) { throw new NoRouteToHostException("Invalid redirect"); } - url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location); + url = new URL(mURL /* TRICKY: don't use url! */, location); if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { throw new NoRouteToHostException("Unsupported protocol redirect"); } - boolean sameProtocol = - connectionState.mURL.getProtocol().equals(url.getProtocol()); - if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) { + boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); + if (!mAllowCrossProtocolRedirect && !sameProtocol) { throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); } - boolean sameHost = connectionState.mURL.getHost().equals(url.getHost()); - if (!connectionState.mAllowCrossDomainRedirect && !sameHost) { + boolean sameHost = mURL.getHost().equals(url.getHost()); + if (!mAllowCrossDomainRedirect && !sameHost) { throw new NoRouteToHostException("Cross-domain redirects are disallowed"); } if (response != HTTP_TEMP_REDIRECT) { // update effective URL, unless it is a Temporary Redirect - connectionState.mURL = url; + mURL = url; } } - if (connectionState.mAllowCrossDomainRedirect) { + if (mAllowCrossDomainRedirect) { // remember the current, potentially redirected URL if redirects // were handled by HttpURLConnection - connectionState.mURL = connectionState.mConnection.getURL(); + mURL = mConnection.getURL(); } if (response == HttpURLConnection.HTTP_PARTIAL) { @@ -292,9 +303,10 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // because what we want is not just the length of the range // returned but the size of the full content if available. - String contentRange = connectionState.mConnection.getHeaderField("Content-Range"); + String contentRange = + mConnection.getHeaderField("Content-Range"); - connectionState.mTotalSize = -1; + mTotalSize = -1; if (contentRange != null) { // format is "bytes xxx-yyy/zzz // where "zzz" is the total number of bytes of the @@ -306,7 +318,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { contentRange.substring(lastSlashPos + 1); try { - connectionState.mTotalSize = Long.parseLong(total); + mTotalSize = Long.parseLong(total); } catch (NumberFormatException e) { } } @@ -314,7 +326,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } else if (response != HttpURLConnection.HTTP_OK) { throw new IOException(); } else { - connectionState.mTotalSize = connectionState.mConnection.getContentLength(); + mTotalSize = mConnection.getContentLength(); } if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { @@ -323,14 +335,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new ProtocolException(); } - connectionState.mInputStream = - new BufferedInputStream(connectionState.mConnection.getInputStream()); + mInputStream = + new BufferedInputStream(mConnection.getInputStream()); - connectionState.mCurrentOffset = offset; + mCurrentOffset = offset; } catch (IOException e) { - connectionState.mTotalSize = -1; - teardownConnection(connectionState); - connectionState.mCurrentOffset = -1; + mTotalSize = -1; + teardownConnection(); + mCurrentOffset = -1; throw e; } @@ -338,28 +350,22 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage - public int readAt(long offset, int size) { - ConnectionState connectionState = mConnectionStateHolder.get(); - if (connectionState != null) { - return native_readAt(offset, size, connectionState); - } - return -1; + public synchronized int readAt(long offset, int size) { + return native_readAt(offset, size); } - private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) { + private synchronized int readAt(long offset, byte[] data, int size) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); try { - synchronized(this) { - if (offset != connectionState.mCurrentOffset) { - seekTo(offset, connectionState); - } + if (offset != mCurrentOffset) { + seekTo(offset); } - int n = connectionState.mInputStream.read(data, 0, size); + int n = mInputStream.read(data, 0, size); if (n == -1) { // InputStream signals EOS using a -1 result, our semantics @@ -367,7 +373,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { n = 0; } - connectionState.mCurrentOffset += n; + mCurrentOffset += n; if (VERBOSE) { Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); @@ -399,47 +405,35 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override public synchronized long getSize() { - ConnectionState connectionState = mConnectionStateHolder.get(); - if (connectionState != null) { - if (connectionState.mConnection == null) { - try { - seekTo(0, connectionState); - } catch (IOException e) { - return -1; - } + if (mConnection == null) { + try { + seekTo(0); + } catch (IOException e) { + return -1; } - return connectionState.mTotalSize; } - return -1; + return mTotalSize; } @Override @UnsupportedAppUsage public synchronized String getMIMEType() { - ConnectionState connectionState = mConnectionStateHolder.get(); - if (connectionState != null) { - if (connectionState.mConnection == null) { - try { - seekTo(0, connectionState); - } catch (IOException e) { - return "application/octet-stream"; - } + if (mConnection == null) { + try { + seekTo(0); + } catch (IOException e) { + return "application/octet-stream"; } - return connectionState.mConnection.getContentType(); } - return null; + return mConnection.getContentType(); } @Override @UnsupportedAppUsage - public String getUri() { - ConnectionState connectionState = mConnectionStateHolder.get(); - if (connectionState != null) { - return connectionState.mURL.toString(); - } - return null; + public synchronized String getUri() { + return mURL.toString(); } @Override @@ -452,7 +446,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { private native final void native_finalize(); private native final IBinder native_getIMemory(); - private native int native_readAt(long offset, int size, ConnectionState connectionState); + private native final int native_readAt(long offset, int size); static { System.loadLibrary("media_jni"); diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp index d28c15c98d16..365e045689f0 100644 --- a/media/jni/android_media_MediaHTTPConnection.cpp +++ b/media/jni/android_media_MediaHTTPConnection.cpp @@ -109,8 +109,7 @@ static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) { gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); CHECK(gFields.context != NULL); - gFields.readAtMethodID = env->GetMethodID( - clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I"); + gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I"); } static void android_media_MediaHTTPConnection_native_setup( @@ -133,7 +132,7 @@ static jobject android_media_MediaHTTPConnection_native_getIMemory( } static jint android_media_MediaHTTPConnection_native_readAt( - JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) { + JNIEnv *env, jobject thiz, jlong offset, jint size) { sp<JMediaHTTPConnection> conn = getObject(env, thiz); if (size > JMediaHTTPConnection::kBufferSize) { size = JMediaHTTPConnection::kBufferSize; @@ -142,7 +141,7 @@ static jint android_media_MediaHTTPConnection_native_readAt( jbyteArray byteArrayObj = conn->getByteArrayObj(); jint n = env->CallIntMethod( - thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState); + thiz, gFields.readAtMethodID, offset, byteArrayObj, size); if (n > 0) { env->GetByteArrayRegion( @@ -159,7 +158,7 @@ static const JNINativeMethod gMethods[] = { { "native_getIMemory", "()Landroid/os/IBinder;", (void *)android_media_MediaHTTPConnection_native_getIMemory }, - { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I", + { "native_readAt", "(JI)I", (void *)android_media_MediaHTTPConnection_native_readAt }, { "native_init", "()V", diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index 262e6f633917..5817118bc861 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -39,6 +39,7 @@ android_library { ":services-networkstack-shared-srcs", ], static_libs: [ + "androidx.annotation_annotation", "ipmemorystore-client", "netd_aidl_interface-java", "networkstack-aidl-interfaces-java", diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml index 52425e57ba3a..90f96e0f7a18 100644 --- a/packages/NetworkStack/res/values/config.xml +++ b/packages/NetworkStack/res/values/config.xml @@ -1,5 +1,38 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <!-- Captive portal http url --> - <string name="config_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string> + <!-- + OEMs that wish to change the below settings must do so via a runtime resource overlay package + and *NOT* by changing this file. This file is part of the NetworkStack mainline module. + The overlays must apply to the config_* values, not the default_* values. The default_* + values are meant to be the default when no other configuration is specified. + --> + + <!-- HTTP URL for network validation, to use for detecting captive portals. --> + <string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string> + + <!-- HTTPS URL for network validation, to use for confirming internet connectivity. --> + <string name="default_captive_portal_https_url" translatable="false">https://www.google.com/generate_204</string> + + <!-- List of fallback URLs to use for detecting captive portals. --> + <string-array name="default_captive_portal_fallback_urls" translatable="false"> + <item>http://www.google.com/gen_204</item> + <item>http://play.googleapis.com/generate_204</item> + </string-array> + + <!-- List of fallback probe specs to use for detecting captive portals. + This is an alternative to fallback URLs that provides more flexibility on detection rules. + Empty, so unused by default. --> + <string-array name="default_captive_portal_fallback_probe_specs" translatable="false"> + </string-array> + + <!-- Configuration hooks for the above settings. + Empty by default but may be overridden by RROs. --> + <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook --> + <string name="config_captive_portal_http_url" translatable="false"></string> + <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook --> + <string name="config_captive_portal_https_url" translatable="false"></string> + <string-array name="config_captive_portal_fallback_urls" translatable="false"> + </string-array> + <string-array name="config_captive_portal_fallback_probe_specs" translatable="false"> + </string-array> </resources>
\ No newline at end of file diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 6f31f9b56ace..cceb3be23762 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -28,6 +28,7 @@ import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVI import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.captiveportal.CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs; import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE; import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS; import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK; @@ -42,6 +43,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; @@ -80,6 +82,9 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; +import androidx.annotation.ArrayRes; +import androidx.annotation.StringRes; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.RingBufferIndices; import com.android.internal.util.State; @@ -94,7 +99,6 @@ import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -102,6 +106,7 @@ import java.util.Random; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.function.Function; /** * {@hide} @@ -111,15 +116,6 @@ public class NetworkMonitor extends StateMachine { private static final boolean DBG = true; private static final boolean VDBG = false; private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG); - // TODO: use another permission for CaptivePortalLoginActivity once it has its own certificate - private static final String PERMISSION_NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS"; - // Default configuration values for captive portal detection probes. - // TODO: append a random length parameter to the default HTTPS url. - // TODO: randomize browser version ids in the default User-Agent String. - private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204"; - private static final String DEFAULT_FALLBACK_URL = "http://www.google.com/gen_204"; - private static final String DEFAULT_OTHER_FALLBACK_URLS = - "http://play.googleapis.com/generate_204"; private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/60.0.3112.32 Safari/537.36"; @@ -379,7 +375,7 @@ public class NetworkMonitor extends StateMachine { mUseHttps = getUseHttpsValidation(); mCaptivePortalUserAgent = getCaptivePortalUserAgent(); mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl()); - mCaptivePortalHttpUrl = makeURL(deps.getCaptivePortalServerHttpUrl(context)); + mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl()); mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls(); mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs(); mRandom = deps.getRandom(); @@ -542,10 +538,6 @@ public class NetworkMonitor extends StateMachine { return HANDLED; case CMD_NETWORK_DISCONNECTED: logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED); - if (mLaunchCaptivePortalAppBroadcastReceiver != null) { - mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver); - mLaunchCaptivePortalAppBroadcastReceiver = null; - } quit(); return HANDLED; case CMD_FORCE_REEVALUATION: @@ -779,6 +771,10 @@ public class NetworkMonitor extends StateMachine { @Override public void exit() { + if (mLaunchCaptivePortalAppBroadcastReceiver != null) { + mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver); + mLaunchCaptivePortalAppBroadcastReceiver = null; + } hideProvisioningNotification(); } } @@ -902,9 +898,10 @@ public class NetworkMonitor extends StateMachine { mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver( ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(), CMD_LAUNCH_CAPTIVE_PORTAL_APP); + // Display the sign in notification. + // Only do this once for every time we enter MaybeNotifyState. b/122164725 + showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction); } - // Display the sign in notification. - showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction); // Retest for captive portal occasionally. sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */, CAPTIVE_PORTAL_REEVALUATE_DELAY_MS); @@ -1178,8 +1175,22 @@ public class NetworkMonitor extends StateMachine { } private String getCaptivePortalServerHttpsUrl() { - return mDependencies.getSetting(mContext, - Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL); + return getSettingFromResource(mContext, R.string.config_captive_portal_https_url, + R.string.default_captive_portal_https_url, + Settings.Global.CAPTIVE_PORTAL_HTTPS_URL); + } + + /** + * Get the captive portal server HTTP URL that is configured on the device. + * + * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as + * it has its own updatable strategies to detect captive portals. The framework only advises + * on one URL that can be used, while NetworkMonitor may implement more complex logic. + */ + public String getCaptivePortalServerHttpUrl() { + return getSettingFromResource(mContext, R.string.config_captive_portal_http_url, + R.string.default_captive_portal_http_url, + Settings.Global.CAPTIVE_PORTAL_HTTP_URL); } private int getConsecutiveDnsTimeoutThreshold() { @@ -1207,24 +1218,23 @@ public class NetworkMonitor extends StateMachine { private URL[] makeCaptivePortalFallbackUrls() { try { - String separator = ","; - String firstUrl = mDependencies.getSetting(mContext, - Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL); - String joinedUrls = firstUrl + separator + mDependencies.getSetting(mContext, - Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, - DEFAULT_OTHER_FALLBACK_URLS); - List<URL> urls = new ArrayList<>(); - for (String s : joinedUrls.split(separator)) { - URL u = makeURL(s); - if (u == null) { - continue; - } - urls.add(u); - } - if (urls.isEmpty()) { - Log.e(TAG, String.format("could not create any url from %s", joinedUrls)); + final String firstUrl = mDependencies.getSetting(mContext, + Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, null); + + final URL[] settingProviderUrls; + if (!TextUtils.isEmpty(firstUrl)) { + final String otherUrls = mDependencies.getSetting(mContext, + Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, ""); + // otherUrls may be empty, but .split() ignores trailing empty strings + final String separator = ","; + final String[] urls = (firstUrl + separator + otherUrls).split(separator); + settingProviderUrls = convertStrings(urls, this::makeURL, new URL[0]); + } else { + settingProviderUrls = new URL[0]; } - return urls.toArray(new URL[urls.size()]); + + return getArrayConfig(settingProviderUrls, R.array.config_captive_portal_fallback_urls, + R.array.default_captive_portal_fallback_urls, this::makeURL); } catch (Exception e) { // Don't let a misconfiguration bootloop the system. Log.e(TAG, "Error parsing configured fallback URLs", e); @@ -1236,15 +1246,14 @@ public class NetworkMonitor extends StateMachine { try { final String settingsValue = mDependencies.getSetting( mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null); - // Probe specs only used if configured in settings - if (TextUtils.isEmpty(settingsValue)) { - return null; - } - - final Collection<CaptivePortalProbeSpec> specs = - CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue); - final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()]; - return specs.toArray(specsArray); + final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0]; + final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue) + ? emptySpecs + : parseCaptivePortalProbeSpecs(settingsValue).toArray(emptySpecs); + + return getArrayConfig(providerValue, R.array.config_captive_portal_fallback_probe_specs, + R.array.default_captive_portal_fallback_probe_specs, + CaptivePortalProbeSpec::parseSpecOrNull); } catch (Exception e) { // Don't let a misconfiguration bootloop the system. Log.e(TAG, "Error parsing configured fallback probe specs", e); @@ -1252,6 +1261,83 @@ public class NetworkMonitor extends StateMachine { } } + /** + * Read a setting from a resource or the settings provider. + * + * <p>The configuration resource is prioritized, then the provider value, then the default + * resource value. + * @param context The context + * @param configResource The resource id for the configuration parameter + * @param defaultResource The resource id for the default value + * @param symbol The symbol in the settings provider + * @return The best available value + */ + @NonNull + private String getSettingFromResource(@NonNull final Context context, + @StringRes int configResource, @StringRes int defaultResource, + @NonNull String symbol) { + final Resources res = context.getResources(); + String setting = res.getString(configResource); + + if (!TextUtils.isEmpty(setting)) return setting; + + setting = mDependencies.getSetting(context, symbol, null); + if (!TextUtils.isEmpty(setting)) return setting; + + return res.getString(defaultResource); + } + + /** + * Get an array configuration from resources or the settings provider. + * + * <p>The configuration resource is prioritized, then the provider values, then the default + * resource values. + * @param providerValue Values obtained from the setting provider. + * @param configResId ID of the configuration resource. + * @param defaultResId ID of the default resource. + * @param resourceConverter Converter from the resource strings to stored setting class. Null + * return values are ignored. + */ + private <T> T[] getArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId, + @ArrayRes int defaultResId, @NonNull Function<String, T> resourceConverter) { + final Resources res = mContext.getResources(); + String[] configValue = res.getStringArray(configResId); + + if (configValue.length == 0) { + if (providerValue.length > 0) { + return providerValue; + } + + configValue = res.getStringArray(defaultResId); + } + + return convertStrings(configValue, resourceConverter, Arrays.copyOf(providerValue, 0)); + } + + /** + * Convert a String array to an array of some other type using the specified converter. + * + * <p>Any null value, or value for which the converter throws a {@link RuntimeException}, will + * not be added to the output array, so the output array may be smaller than the input. + */ + private <T> T[] convertStrings( + @NonNull String[] strings, Function<String, T> converter, T[] emptyArray) { + final ArrayList<T> convertedValues = new ArrayList<>(strings.length); + for (String configString : strings) { + T convertedValue = null; + try { + convertedValue = converter.apply(configString); + } catch (Exception e) { + Log.e(TAG, "Error parsing configuration", e); + // Fall through + } + if (convertedValue != null) { + convertedValues.add(convertedValue); + } + } + return convertedValues.toArray(emptyArray); + } + private String getCaptivePortalUserAgent() { return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT); @@ -1693,19 +1779,6 @@ public class NetworkMonitor extends StateMachine { } /** - * Get the captive portal server HTTP URL that is configured on the device. - * - * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as - * it has its own updatable strategies to detect captive portals. The framework only advises - * on one URL that can be used, while NetworkMonitor may implement more complex logic. - */ - public String getCaptivePortalServerHttpUrl(Context context) { - final String defaultUrl = - context.getResources().getString(R.string.config_captive_portal_http_url); - return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(context, defaultUrl); - } - - /** * Get the value of a global integer setting. * @param symbol Name of the setting * @param defaultValue Value to return if the setting is not defined. diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp index 424cd1fe84dd..fe3c1e8eb3e5 100644 --- a/packages/NetworkStack/tests/Android.bp +++ b/packages/NetworkStack/tests/Android.bp @@ -46,6 +46,8 @@ android_test { "libcrypto", "libcutils", "libdexfile", + "ld-android", + "libdl_android", "libhidl-gen-utils", "libhidlbase", "libhidltransport", diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index 6665aae65d90..1c11586ce59a 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -30,7 +30,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; @@ -45,6 +44,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; +import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.INetworkMonitorCallbacks; import android.net.InetAddresses; @@ -95,6 +95,7 @@ public class NetworkMonitorTest { private static final String LOCATION_HEADER = "location"; private @Mock Context mContext; + private @Mock Resources mResources; private @Mock IpConnectivityLog mLogger; private @Mock SharedLog mValidationLogger; private @Mock NetworkInfo mNetworkInfo; @@ -150,14 +151,20 @@ public class NetworkMonitorTest { .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT); when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS), anyInt())).thenReturn(1); - when(mDependencies.getCaptivePortalServerHttpUrl(any())).thenReturn(TEST_HTTP_URL); - when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), - anyString())).thenReturn(TEST_HTTPS_URL); + when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any())) + .thenReturn(TEST_HTTP_URL); + when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any())) + .thenReturn(TEST_HTTPS_URL); + doReturn(mNetwork).when(mNetwork).getPrivateDnsBypassingCopy(); when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm); when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony); when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi); + when(mContext.getResources()).thenReturn(mResources); + + when(mResources.getString(anyInt())).thenReturn(""); + when(mResources.getStringArray(anyInt())).thenReturn(new String[0]); when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI); setFallbackUrl(TEST_FALLBACK_URL); diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index f79a51b13afd..47b646c1a667 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -48,6 +48,7 @@ import android.content.pm.PermissionInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -1288,9 +1289,13 @@ class AlarmManagerService extends SystemService { // because kernel doesn't keep this after reboot setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); - // Also sure that we're booting with a halfway sensible current time if (mNativeData != 0) { - final long systemBuildTime = Environment.getRootDirectory().lastModified(); + // Ensure that we're booting with a halfway sensible current time. Use the + // most recent of Build.TIME, the root file system's timestamp, and the + // value of the ro.build.date.utc system property (which is in seconds). + final long systemBuildTime = Long.max( + 1000L * SystemProperties.getLong("ro.build.date.utc", -1L), + Long.max(Environment.getRootDirectory().lastModified(), Build.TIME)); if (System.currentTimeMillis() < systemBuildTime) { Slog.i(TAG, "Current time only " + System.currentTimeMillis() + ", advancing to build time " + systemBuildTime); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b786018324d5..28c3dbc75687 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -108,7 +108,6 @@ import android.net.VpnService; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; -import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; @@ -133,6 +132,7 @@ import android.os.ServiceSpecificException; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -237,6 +237,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final boolean LOGD_BLOCKED_NETWORKINFO = true; + /** + * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed + * by OEMs for configuration purposes, as this value is overridden by + * Settings.Global.CAPTIVE_PORTAL_HTTP_URL. + * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose + * (preferably via runtime resource overlays). + */ + private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL = + "http://connectivitycheck.gstatic.com/generate_204"; + // TODO: create better separation between radio types and network types // how long to wait before switching back to a radio's default network @@ -1628,8 +1638,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private boolean disallowedBecauseSystemCaller() { // TODO: start throwing a SecurityException when GnssLocationProvider stops calling - // requestRouteToHost. - if (isSystem(Binder.getCallingUid())) { + // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost + // for devices launched with Q and above. However, existing devices upgrading to Q and + // above must continued to be supported for few more releases. + if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt( + "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) { log("This method exists only for app backwards compatibility" + " and must not be called by system services."); return true; @@ -1765,14 +1778,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // callback from each caller type. Need to re-factor NetdEventListenerService to allow // multiple NetworkMonitor registrants. if (nai != null && nai.satisfies(mDefaultRequest)) { - final long token = Binder.clearCallingIdentity(); - try { - nai.networkMonitor().notifyDnsResponse(returnCode); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } finally { - Binder.restoreCallingIdentity(token); - } + Binder.withCleanCallingIdentity(() -> + nai.networkMonitor().notifyDnsResponse(returnCode)); } } @@ -6708,9 +6715,20 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getCaptivePortalServerUrl() { enforceConnectivityInternalPermission(); - final String defaultUrl = mContext.getResources().getString( - R.string.config_networkDefaultCaptivePortalServerUrl); - return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl); + String settingUrl = mContext.getResources().getString( + R.string.config_networkCaptivePortalServerUrl); + + if (!TextUtils.isEmpty(settingUrl)) { + return settingUrl; + } + + settingUrl = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.CAPTIVE_PORTAL_HTTP_URL); + if (!TextUtils.isEmpty(settingUrl)) { + return settingUrl; + } + + return DEFAULT_CAPTIVE_PORTAL_HTTP_URL; } @Override diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 0a91721f31d6..7875e93c80f9 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -88,10 +88,10 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; -import com.android.internal.net.NetworkStatsFactory; import com.android.internal.util.DumpUtils; import com.android.internal.util.HexDump; import com.android.internal.util.Preconditions; +import com.android.server.net.NetworkStatsFactory; import com.google.android.collect.Maps; diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 7a8d23a2295c..85787f25336f 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -248,6 +248,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private final LocalLog mLocalLog = new LocalLog(100); + private final LocalLog mListenLog = new LocalLog(100); + private PreciseDataConnectionState mPreciseDataConnectionState = new PreciseDataConnectionState(); @@ -305,6 +307,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } mDefaultSubId = newDefaultSubId; mDefaultPhoneId = newDefaultPhoneId; + mLocalLog.log("Default subscription updated: mDefaultPhoneId=" + + mDefaultPhoneId + ", mDefaultSubId" + mDefaultSubId); } } } @@ -598,10 +602,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { boolean notifyNow, int subId) { int callerUserId = UserHandle.getCallingUserId(); mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - if (VDBG) { - log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events) + String str = "listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId=" - + UserHandle.myUserId() + " callerUserId=" + callerUserId); + + UserHandle.myUserId() + " callerUserId=" + callerUserId; + mListenLog.log(str); + if (VDBG) { + log(str); } if (events != PhoneStateListener.LISTEN_NONE) { @@ -1399,8 +1405,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType) && (mDataConnectionState[phoneId] != state || mDataConnectionNetworkType[phoneId] != networkType)) { - String str = "onDataConnectionStateChanged(" + state - + ", " + networkType + ")"; + String str = "onDataConnectionStateChanged(" + + TelephonyManager.dataStateToString(state) + + ", " + TelephonyManager.getNetworkTypeName(networkType) + + ") subId=" + subId + ", phoneId=" + phoneId; log(str); mLocalLog.log(str); for (Record r : mRecords) { @@ -1916,12 +1924,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mEmergencyNumberList=" + mEmergencyNumberList); pw.println("mCallQuality=" + mCallQuality); pw.println("mCallAttributes=" + mCallAttributes); + pw.println("mDefaultPhoneId" + mDefaultPhoneId); + pw.println("mDefaultSubId" + mDefaultSubId); pw.decreaseIndent(); pw.println("local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); + pw.println("listen logs:"); + mListenLog.dump(fd, pw, args); pw.decreaseIndent(); pw.println("registrations: count=" + recordCount); pw.increaseIndent(); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index b03628930dd6..3399a76f358f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -787,7 +787,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return -1; } } - process = getNextArg(); + process = getNextArgRequired(); } else { // Compatibility with old syntax: process is specified first. process = cmd; @@ -2919,15 +2919,22 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" start: start tracing IPC transactions."); pw.println(" stop: stop tracing IPC transactions and dump the results to file."); pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to."); - pw.println(" profile [start|stop] [--user <USER_ID> current] [--sampling INTERVAL]"); - pw.println(" [--streaming] <PROCESS> <FILE>"); - pw.println(" Start and stop profiler on a process. The given <PROCESS> argument"); + pw.println(" profile start [--user <USER_ID> current]"); + pw.println(" [--sampling INTERVAL | --streaming] <PROCESS> <FILE>"); + pw.println(" Start profiler on a process. The given <PROCESS> argument"); pw.println(" may be either a process name or pid. Options are:"); pw.println(" --user <USER_ID> | current: When supplying a process name,"); - pw.println(" specify user of process to profile; uses current user if not specified."); + pw.println(" specify user of process to profile; uses current user if not"); + pw.println(" specified."); pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds"); - pw.println(" between samples"); - pw.println(" --streaming: stream the profiling output to the specified file"); + pw.println(" between samples."); + pw.println(" --streaming: stream the profiling output to the specified file."); + pw.println(" profile stop [--user <USER_ID> current] <PROCESS>"); + pw.println(" Stop profiler on a process. The given <PROCESS> argument"); + pw.println(" may be either a process name or pid. Options are:"); + pw.println(" --user <USER_ID> | current: When supplying a process name,"); + pw.println(" specify user of process to profile; uses current user if not"); + pw.println(" specified."); pw.println(" dumpheap [--user <USER_ID> current] [-n] [-g] <PROCESS> <FILE>"); pw.println(" Dump the heap of a process. The given <PROCESS> argument may"); pw.println(" be either a process name or pid. Options are:"); diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java index 648c782a7d1e..603d7cfb4525 100644 --- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java @@ -18,14 +18,11 @@ package com.android.server.media; import android.annotation.NonNull; import android.content.Context; +import android.media.AudioManager; import android.media.AudioPlaybackConfiguration; -import android.media.IAudioService; -import android.media.IPlaybackConfigDispatcher; -import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -42,11 +39,11 @@ import java.util.Set; /** * Monitors the state changes of audio players. */ -class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { +class AudioPlayerStateMonitor { private static boolean DEBUG = MediaSessionService.DEBUG; private static String TAG = "AudioPlayerStateMonitor"; - private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor(); + private static AudioPlayerStateMonitor sInstance; /** * Listener for handling the active state changes of audio players. @@ -96,96 +93,33 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { private final Map<OnAudioPlayerActiveStateChangedListener, MessageHandler> mListenerMap = new ArrayMap<>(); @GuardedBy("mLock") - private final Set<Integer> mActiveAudioUids = new ArraySet<>(); + @SuppressWarnings("WeakerAccess") /* synthetic access */ + final Set<Integer> mActiveAudioUids = new ArraySet<>(); @GuardedBy("mLock") - private ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs = + @SuppressWarnings("WeakerAccess") /* synthetic access */ + ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs = new ArrayMap<>(); // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video) // The UID whose audio playback becomes active at the last comes first. // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID. @GuardedBy("mLock") - private final IntArray mSortedAudioPlaybackClientUids = new IntArray(); + @SuppressWarnings("WeakerAccess") /* synthetic access */ + final IntArray mSortedAudioPlaybackClientUids = new IntArray(); - @GuardedBy("mLock") - private boolean mRegisteredToAudioService; - - static AudioPlayerStateMonitor getInstance() { - return sInstance; - } - - private AudioPlayerStateMonitor() { - } - - /** - * Called when the {@link AudioPlaybackConfiguration} is updated. - * <p>If an app starts audio playback, the app's local media session will be the media button - * session. If the app has multiple media sessions, the playback active local session will be - * picked. - * - * @param configs List of the current audio playback configuration - */ - @Override - public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, - boolean flush) { - if (flush) { - Binder.flushPendingCommands(); - } - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - // Update mActiveAudioUids - mActiveAudioUids.clear(); - ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs = - new ArrayMap<>(); - for (AudioPlaybackConfiguration config : configs) { - if (config.isActive()) { - mActiveAudioUids.add(config.getClientUid()); - activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config); - } - } - - // Update mSortedAuioPlaybackClientUids. - for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) { - AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i); - final int uid = config.getClientUid(); - if (!mPrevActiveAudioPlaybackConfigs.containsKey( - config.getPlayerInterfaceId())) { - if (DEBUG) { - Log.d(TAG, "Found a new active media playback. " + - AudioPlaybackConfiguration.toLogFriendlyString(config)); - } - // New active audio playback. - int index = mSortedAudioPlaybackClientUids.indexOf(uid); - if (index == 0) { - // It's the lastly played music app already. Skip updating. - continue; - } else if (index > 0) { - mSortedAudioPlaybackClientUids.remove(index); - } - mSortedAudioPlaybackClientUids.add(0, uid); - } - } - // Notify the active state change of audio players. - for (AudioPlaybackConfiguration config : configs) { - final int pii = config.getPlayerInterfaceId(); - boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null; - if (wasActive != config.isActive()) { - sendAudioPlayerActiveStateChangedMessageLocked( - config, /* isRemoved */ false); - } - } - for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) { - sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true); - } - - // Update mPrevActiveAudioPlaybackConfigs - mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs; + static AudioPlayerStateMonitor getInstance(Context context) { + synchronized (AudioPlayerStateMonitor.class) { + if (sInstance == null) { + sInstance = new AudioPlayerStateMonitor(context); } - } finally { - Binder.restoreCallingIdentity(token); + return sInstance; } } + private AudioPlayerStateMonitor(Context context) { + AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + am.registerAudioPlaybackCallback(new AudioManagerPlaybackListener(), null); + } + /** * Registers OnAudioPlayerActiveStateChangedListener. */ @@ -275,20 +209,6 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } } - public void registerSelfIntoAudioServiceIfNeeded(IAudioService audioService) { - synchronized (mLock) { - try { - if (!mRegisteredToAudioService) { - audioService.registerPlaybackCallback(this); - mRegisteredToAudioService = true; - } - } catch (RemoteException e) { - Log.wtf(TAG, "Failed to register playback callback", e); - mRegisteredToAudioService = false; - } - } - } - @GuardedBy("mLock") private void sendAudioPlayerActiveStateChangedMessageLocked( final AudioPlaybackConfiguration config, final boolean isRemoved) { @@ -296,4 +216,59 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { messageHandler.sendAudioPlayerActiveStateChangedMessage(config, isRemoved); } } + + private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback { + @Override + public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) { + synchronized (mLock) { + // Update mActiveAudioUids + mActiveAudioUids.clear(); + ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs = + new ArrayMap<>(); + for (AudioPlaybackConfiguration config : configs) { + if (config.isActive()) { + mActiveAudioUids.add(config.getClientUid()); + activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config); + } + } + + // Update mSortedAuioPlaybackClientUids. + for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) { + AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i); + final int uid = config.getClientUid(); + if (!mPrevActiveAudioPlaybackConfigs.containsKey( + config.getPlayerInterfaceId())) { + if (DEBUG) { + Log.d(TAG, "Found a new active media playback. " + + AudioPlaybackConfiguration.toLogFriendlyString(config)); + } + // New active audio playback. + int index = mSortedAudioPlaybackClientUids.indexOf(uid); + if (index == 0) { + // It's the lastly played music app already. Skip updating. + continue; + } else if (index > 0) { + mSortedAudioPlaybackClientUids.remove(index); + } + mSortedAudioPlaybackClientUids.add(0, uid); + } + } + // Notify the active state change of audio players. + for (AudioPlaybackConfiguration config : configs) { + final int pii = config.getPlayerInterfaceId(); + boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null; + if (wasActive != config.isActive()) { + sendAudioPlayerActiveStateChangedMessageLocked( + config, /* isRemoved */ false); + } + } + for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) { + sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true); + } + + // Update mPrevActiveAudioPlaybackConfigs + mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs; + } + } + } } diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index a7df0e23f63b..47f22702cc02 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -16,14 +16,10 @@ package com.android.server.media; -import com.android.internal.util.DumpUtils; -import com.android.server.Watchdog; - import android.annotation.NonNull; import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -57,6 +53,9 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; +import com.android.internal.util.DumpUtils; +import com.android.server.Watchdog; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -115,7 +114,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub mAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); - mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); + mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(context); mAudioPlayerStateMonitor.registerListener( new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() { static final long WAIT_MS = 500; @@ -166,7 +165,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } }, mHandler); - mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService); AudioRoutesInfo audioRoutes = null; try { diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 442354bbb6b9..29529b8643c1 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -669,6 +669,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { PlaybackState state; long duration = -1; synchronized (mLock) { + if (mDestroyed) { + return null; + } state = mPlaybackState; if (mMetadata != null && mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) { duration = mMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION); diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 68b2a583e020..67f605ccecfb 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -93,8 +93,8 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.NoSuchElementException; +import java.util.Set; /** * System implementation of MediaSessionManager @@ -164,7 +164,7 @@ public class MediaSessionService extends SystemService implements Monitor { mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); mAudioService = getAudioService(); - mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); + mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(getContext()); mAudioPlayerStateMonitor.registerListener( (config, isRemoved) -> { if (isRemoved || !config.isActive() || config.getPlayerType() @@ -179,7 +179,6 @@ public class MediaSessionService extends SystemService implements Monitor { } } }, null /* handler */); - mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService); mContentResolver = getContext().getContentResolver(); mSettingsObserver = new SettingsObserver(); mSettingsObserver.observe(); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 863ef67d4f0f..ca0fbe1c98ab 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -3462,9 +3462,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Process state of UID changed; if needed, will trigger * {@link #updateRulesForDataUsageRestrictionsUL(int)} and - * {@link #updateRulesForPowerRestrictionsUL(int)} + * {@link #updateRulesForPowerRestrictionsUL(int)}. Returns true if the state was updated. */ - private void updateUidStateUL(int uid, int uidState) { + private boolean updateUidStateUL(int uid, int uidState) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL"); try { final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); @@ -3483,14 +3483,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } updateRulesForPowerRestrictionsUL(uid); } - updateNetworkStats(uid, isUidStateForeground(uidState)); + return true; } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } + return false; } - private void removeUidStateUL(int uid) { + private boolean removeUidStateUL(int uid) { final int index = mUidState.indexOfKey(uid); if (index >= 0) { final int oldUidState = mUidState.valueAt(index); @@ -3505,9 +3506,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateRuleForRestrictPowerUL(uid); } updateRulesForPowerRestrictionsUL(uid); - updateNetworkStats(uid, false); + return true; } } + return false; } // adjust stats accounting based on foreground status @@ -4419,21 +4421,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } } - }; void handleUidChanged(int uid, int procState, long procStateSeq) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged"); try { + boolean updated; synchronized (mUidRulesFirstLock) { // We received a uid state change callback, add it to the history so that it // will be useful for debugging. mLogger.uidStateChanged(uid, procState, procStateSeq); // Now update the network policy rules as per the updated uid state. - updateUidStateUL(uid, procState); + updated = updateUidStateUL(uid, procState); // Updating the network rules is done, so notify AMS about this. mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq); } + // Do this without the lock held. handleUidChanged() and handleUidGone() are + // called from the handler, so there's no multi-threading issue. + if (updated) { + updateNetworkStats(uid, isUidStateForeground(procState)); + } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } @@ -4442,8 +4449,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void handleUidGone(int uid) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidGone"); try { + boolean updated; synchronized (mUidRulesFirstLock) { - removeUidStateUL(uid); + updated = removeUidStateUL(uid); + } + // Do this without the lock held. handleUidChanged() and handleUidGone() are + // called from the handler, so there's no multi-threading issue. + if (updated) { + updateNetworkStats(uid, false); } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 1f3b4c4121d1..bf34d8fa6b26 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.net; +package com.android.server.net; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4c076781731c..f237c4bca57b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -129,7 +129,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index c30babd464f4..b2677cb77d9c 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -67,6 +67,7 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; @@ -128,8 +129,6 @@ public final class TvInputManagerService extends SystemService { private final WatchLogHandler mWatchLogHandler; - private IBinder.DeathRecipient mDeathRecipient; - public TvInputManagerService(Context context) { super(context); @@ -484,7 +483,7 @@ public final class TvInputManagerService extends SystemService { userState.packageSet.clear(); userState.contentRatingSystemList.clear(); userState.clientStateMap.clear(); - userState.callbackSet.clear(); + userState.mCallbacks.kill(); userState.mainSessionToken = null; mUserStates.remove(userId); @@ -749,39 +748,45 @@ public final class TvInputManagerService extends SystemService { if (DEBUG) { Slog.d(TAG, "notifyInputAddedLocked(inputId=" + inputId + ")"); } - for (ITvInputManagerCallback callback : userState.callbackSet) { + int n = userState.mCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { try { - callback.onInputAdded(inputId); + userState.mCallbacks.getBroadcastItem(i).onInputAdded(inputId); } catch (RemoteException e) { Slog.e(TAG, "failed to report added input to callback", e); } } + userState.mCallbacks.finishBroadcast(); } private void notifyInputRemovedLocked(UserState userState, String inputId) { if (DEBUG) { Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")"); } - for (ITvInputManagerCallback callback : userState.callbackSet) { + int n = userState.mCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { try { - callback.onInputRemoved(inputId); + userState.mCallbacks.getBroadcastItem(i).onInputRemoved(inputId); } catch (RemoteException e) { Slog.e(TAG, "failed to report removed input to callback", e); } } + userState.mCallbacks.finishBroadcast(); } private void notifyInputUpdatedLocked(UserState userState, String inputId) { if (DEBUG) { Slog.d(TAG, "notifyInputUpdatedLocked(inputId=" + inputId + ")"); } - for (ITvInputManagerCallback callback : userState.callbackSet) { + int n = userState.mCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { try { - callback.onInputUpdated(inputId); + userState.mCallbacks.getBroadcastItem(i).onInputUpdated(inputId); } catch (RemoteException e) { Slog.e(TAG, "failed to report updated input to callback", e); } } + userState.mCallbacks.finishBroadcast(); } private void notifyInputStateChangedLocked(UserState userState, String inputId, @@ -791,13 +796,15 @@ public final class TvInputManagerService extends SystemService { + ", state=" + state + ")"); } if (targetCallback == null) { - for (ITvInputManagerCallback callback : userState.callbackSet) { + int n = userState.mCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { try { - callback.onInputStateChanged(inputId, state); + userState.mCallbacks.getBroadcastItem(i).onInputStateChanged(inputId, state); } catch (RemoteException e) { Slog.e(TAG, "failed to report state change to callback", e); } } + userState.mCallbacks.finishBroadcast(); } else { try { targetCallback.onInputStateChanged(inputId, state); @@ -819,13 +826,15 @@ public final class TvInputManagerService extends SystemService { } inputState.info = inputInfo; - for (ITvInputManagerCallback callback : userState.callbackSet) { + int n = userState.mCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { try { - callback.onTvInputInfoUpdated(inputInfo); + userState.mCallbacks.getBroadcastItem(i).onTvInputInfoUpdated(inputInfo); } catch (RemoteException e) { Slog.e(TAG, "failed to report updated input info to callback", e); } } + userState.mCallbacks.finishBroadcast(); } private void setStateLocked(String inputId, int state, int userId) { @@ -1003,22 +1012,8 @@ public final class TvInputManagerService extends SystemService { try { synchronized (mLock) { final UserState userState = getOrCreateUserStateLocked(resolvedUserId); - userState.callbackSet.add(callback); - mDeathRecipient = new IBinder.DeathRecipient() { - @Override - public void binderDied() { - synchronized (mLock) { - if (userState.callbackSet != null) { - userState.callbackSet.remove(callback); - } - } - } - }; - - try { - callback.asBinder().linkToDeath(mDeathRecipient, 0); - } catch (RemoteException e) { - Slog.e(TAG, "client process has already died", e); + if (!userState.mCallbacks.register(callback)) { + Slog.e(TAG, "client process has already died"); } } } finally { @@ -1034,8 +1029,7 @@ public final class TvInputManagerService extends SystemService { try { synchronized (mLock) { UserState userState = getOrCreateUserStateLocked(resolvedUserId); - userState.callbackSet.remove(callback); - callback.asBinder().unlinkToDeath(mDeathRecipient, 0); + userState.mCallbacks.unregister(callback); } } finally { Binder.restoreCallingIdentity(identity); @@ -2104,11 +2098,13 @@ public final class TvInputManagerService extends SystemService { } pw.decreaseIndent(); - pw.println("callbackSet:"); + pw.println("mCallbacks:"); pw.increaseIndent(); - for (ITvInputManagerCallback callback : userState.callbackSet) { - pw.println(callback.toString()); + int n = userState.mCallbacks.beginBroadcast(); + for (int j = 0; j < n; ++j) { + pw.println(userState.mCallbacks.getRegisteredCallbackItem(j).toString()); } + userState.mCallbacks.finishBroadcast(); pw.decreaseIndent(); pw.println("mainSessionToken: " + userState.mainSessionToken); @@ -2139,8 +2135,9 @@ public final class TvInputManagerService extends SystemService { // A mapping from the token of a TV input session to its state. private final Map<IBinder, SessionState> sessionStateMap = new HashMap<>(); - // A set of callbacks. - private final Set<ITvInputManagerCallback> callbackSet = new HashSet<>(); + // A list of callbacks. + private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks = + new RemoteCallbackList<ITvInputManagerCallback>(); // The token of a "main" TV input session. private IBinder mainSessionToken = null; diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 07a6c70befd6..b5381aea4752 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -51,6 +51,7 @@ cc_library_static { "com_android_server_PersistentDataBlockService.cpp", "com_android_server_GraphicsStatsService.cpp", "onload.cpp", + ":lib_networkStatsFactory_native", ], include_dirs: [ @@ -140,3 +141,10 @@ cc_defaults { } } } + +filegroup { + name: "lib_networkStatsFactory_native", + srcs: [ + "com_android_server_net_NetworkStatsFactory.cpp", + ], +} diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp index 8259ffcd419d..9cd743b3466a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp @@ -21,9 +21,9 @@ #include <sys/stat.h> #include <sys/types.h> -#include <core_jni_helpers.h> #include <jni.h> +#include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> @@ -333,29 +333,27 @@ static const JNINativeMethod gMethods[] = { (void*) readNetworkStatsDev }, }; -int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { - int err = RegisterMethodsOrDie(env, - "com/android/internal/net/NetworkStatsFactory", gMethods, +int register_android_server_net_NetworkStatsFactory(JNIEnv* env) { + int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods, NELEM(gMethods)); - - gStringClass = FindClassOrDie(env, "java/lang/String"); - gStringClass = MakeGlobalRefOrDie(env, gStringClass); - - jclass clazz = FindClassOrDie(env, "android/net/NetworkStats"); - gNetworkStatsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "I"); - gNetworkStatsClassInfo.capacity = GetFieldIDOrDie(env, clazz, "capacity", "I"); - gNetworkStatsClassInfo.iface = GetFieldIDOrDie(env, clazz, "iface", "[Ljava/lang/String;"); - gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); - gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); - gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); - gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); - gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); - gNetworkStatsClassInfo.defaultNetwork = GetFieldIDOrDie(env, clazz, "defaultNetwork", "[I"); - gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); - gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); - gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J"); - gNetworkStatsClassInfo.txPackets = GetFieldIDOrDie(env, clazz, "txPackets", "[J"); - gNetworkStatsClassInfo.operations = GetFieldIDOrDie(env, clazz, "operations", "[J"); + gStringClass = env->FindClass("java/lang/String"); + gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass)); + + jclass clazz = env->FindClass("android/net/NetworkStats"); + gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); + gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); + gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); + gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); + gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); + gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I"); + gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I"); + gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I"); + gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); + gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); + gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); + gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); + gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); return err; } diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 83347bb68e49..4b0bbae2ab62 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -54,6 +54,7 @@ int register_android_server_HardwarePropertiesManagerService(JNIEnv* env); int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_server_GraphicsStatsService(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); +int register_android_server_net_NetworkStatsFactory(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); }; @@ -102,6 +103,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_SyntheticPasswordManager(env); register_android_server_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); + register_android_server_net_NetworkStatsFactory(env); register_android_server_net_NetworkStatsService(env); return JNI_VERSION_1_4; } diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java index a17cb4647158..bb4a603ba421 100644 --- a/services/net/java/android/net/shared/NetworkMonitorUtils.java +++ b/services/net/java/android/net/shared/NetworkMonitorUtils.java @@ -21,9 +21,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; -import android.content.Context; import android.net.NetworkCapabilities; -import android.provider.Settings; /** @hide */ public class NetworkMonitorUtils { @@ -45,16 +43,6 @@ public class NetworkMonitorUtils { "android.permission.ACCESS_NETWORK_CONDITIONS"; /** - * Get the captive portal server HTTP URL that is configured on the device. - */ - public static String getCaptivePortalServerHttpUrl(Context context, String defaultUrl) { - final String settingUrl = Settings.Global.getString( - context.getContentResolver(), - Settings.Global.CAPTIVE_PORTAL_HTTP_URL); - return settingUrl != null ? settingUrl : defaultUrl; - } - - /** * Return whether validation is required for a network. * @param dfltNetCap Default requested network capabilities. * @param nc Network capabilities of the network to test. diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java index d01c889864f2..37fab09cd745 100644 --- a/telecomm/java/android/telecom/CallRedirectionService.java +++ b/telecomm/java/android/telecom/CallRedirectionService.java @@ -121,8 +121,6 @@ public abstract class CallRedirectionService extends Service { * * @param handle the new phone number to dial * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call. - * If {@code null}, no change will be made to the - * {@link PhoneAccountHandle} used to place the call. * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog * if the confirmFirst is true, and if the redirection request of this * response was sent with a true flag of allowInteractiveResponse via diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 1bb1bc4b534f..0dd661413dfd 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2557,6 +2557,48 @@ public class CarrierConfigManager { public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string"; + /** + * Passing this value as {@link KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the + * subscription from a group instead of adding it to a group. + * + * TODO: Expose in a future release. + * + * @hide + */ + public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000"; + + /** + * The UUID of a Group of related subscriptions in which to place the current subscription. + * + * A grouped subscription will behave for billing purposes and other UI purposes as though it + * is a transparent extension of other subscriptions in the group. + * + * <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from + * its current group. + * + * TODO: unhide this key. + * + * @hide + */ + public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = + "key_subscription_group_uuid_string"; + + /** + * A boolean property indicating whether this subscription should be managed as an opportunistic + * subscription. + * + * If true, then this subscription will be selected based on available coverage and will not be + * available for a user in settings menus for selecting macro network providers. If unset, + * defaults to “false”. + * + * TODO: unhide this key. + * + * @hide + */ + public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = + "key_is_opportunistic_subscription_bool"; + + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -2948,6 +2990,8 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN, false); + sDefaults.putString(KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); + sDefaults.putBoolean(KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false); } /** diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java index ddbd851bbce5..b562f3270fba 100644 --- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java @@ -34,14 +34,14 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen private static final String LOG_TAG = "CellSignalStrengthTdscdma"; private static final boolean DBG = false; - private static final int TDSCDMA_RSSI_MAX = -51; - private static final int TDSCDMA_RSSI_GREAT = -77; - private static final int TDSCDMA_RSSI_GOOD = -87; - private static final int TDSCDMA_RSSI_MODERATE = -97; - private static final int TDSCDMA_RSSI_POOR = -107; - - private static final int TDSCDMA_RSCP_MIN = -120; + // These levels are arbitrary but carried over from SignalStrength.java for consistency. private static final int TDSCDMA_RSCP_MAX = -24; + private static final int TDSCDMA_RSCP_GREAT = -49; + private static final int TDSCDMA_RSCP_GOOD = -73; + private static final int TDSCDMA_RSCP_MODERATE = -97; + private static final int TDSCDMA_RSCP_POOR = -110; + private static final int TDSCDMA_RSCP_MIN = -120; + private int mRssi; // in dBm [-113, -51], CellInfo.UNAVAILABLE @@ -135,11 +135,11 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen /** @hide */ @Override public void updateLevel(PersistableBundle cc, ServiceState ss) { - if (mRssi > TDSCDMA_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; - else if (mRssi >= TDSCDMA_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT; - else if (mRssi >= TDSCDMA_RSSI_GOOD) mLevel = SIGNAL_STRENGTH_GOOD; - else if (mRssi >= TDSCDMA_RSSI_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE; - else if (mRssi >= TDSCDMA_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR; + if (mRscp > TDSCDMA_RSCP_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + else if (mRscp >= TDSCDMA_RSCP_GREAT) mLevel = SIGNAL_STRENGTH_GREAT; + else if (mRscp >= TDSCDMA_RSCP_GOOD) mLevel = SIGNAL_STRENGTH_GOOD; + else if (mRscp >= TDSCDMA_RSCP_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE; + else if (mRscp >= TDSCDMA_RSCP_POOR) mLevel = SIGNAL_STRENGTH_POOR; else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } @@ -159,6 +159,23 @@ public final class CellSignalStrengthTdscdma extends CellSignalStrength implemen } /** + * Get the RSSI as dBm value -113..-51dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. + * + * @hide + */ + public int getRssi() { + return mRssi; + } + + /** + * Get the BER as an ASU value 0..7, 99, or {@link CellInfo#UNAVAILABLE UNAVAILABLE}. + * @hide + */ + public int getBitErrorRate() { + return mBitErrorRate; + } + + /** * Get the RSCP in ASU. * * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69 diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java index efa3647f0e9b..c721cdc06217 100644 --- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java @@ -66,7 +66,7 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp"; // Default to RSSI for backwards compatibility with older devices - private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI; + private static final String DEFAULT_LEVEL_CALCULATION_METHOD = LEVEL_CALCULATION_METHOD_RSSI; private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or @@ -161,14 +161,14 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements int[] rscpThresholds; if (cc == null) { - calcMethod = sLevelCalculationMethod; + calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD; rscpThresholds = sRscpThresholds; } else { // TODO: abstract this entire thing into a series of functions calcMethod = cc.getString( CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, - sLevelCalculationMethod); - if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod; + DEFAULT_LEVEL_CALCULATION_METHOD); + if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD; rscpThresholds = cc.getIntArray( CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY); if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) { diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java index 21dad77d29b7..c1906ebeec9f 100644 --- a/telephony/java/android/telephony/PhoneCapability.java +++ b/telephony/java/android/telephony/PhoneCapability.java @@ -30,6 +30,25 @@ import java.util.Objects; * @hide */ public class PhoneCapability implements Parcelable { + // Hardcoded default DSDS capability. + public static final PhoneCapability DEFAULT_DSDS_CAPABILITY; + // Hardcoded default Single SIM single standby capability. + public static final PhoneCapability DEFAULT_SSSS_CAPABILITY; + + static { + ModemInfo modemInfo1 = new ModemInfo(0, 0, true, true); + ModemInfo modemInfo2 = new ModemInfo(1, 0, true, true); + + List<ModemInfo> logicalModemList = new ArrayList<>(); + logicalModemList.add(modemInfo1); + logicalModemList.add(modemInfo2); + DEFAULT_DSDS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false); + + logicalModemList = new ArrayList<>(); + logicalModemList.add(modemInfo1); + DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false); + } + public final int maxActiveVoiceCalls; public final int maxActiveData; public final int max5G; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index f928ba0350aa..f4a6984001cb 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -1045,6 +1045,7 @@ public class ServiceState implements Parcelable { mIsEmergencyOnly = false; mLteEarfcnRsrpBoost = 0; mNrFrequencyRange = FREQUENCY_RANGE_UNKNOWN; + mNetworkRegistrationInfos.clear(); addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setDomain(NetworkRegistrationInfo.DOMAIN_CS) .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 1f9f32df83c7..801f93777d4e 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2588,8 +2588,7 @@ public class SubscriptionManager { * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. * @param executor The executor of where the callback will execute. * @param callback Callback will be triggered once it succeeds or failed. - * See {@link TelephonyManager.SetOpportunisticSubscriptionResult} - * for more details. Pass null if don't care about the result. + * Pass null if don't care about the result. * * @hide * @@ -2597,7 +2596,8 @@ public class SubscriptionManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int subId, boolean needValidation, - @Nullable @CallbackExecutor Executor executor, @Nullable Consumer<Integer> callback) { + @Nullable @CallbackExecutor Executor executor, @Nullable + @TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) { if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId); try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index e6e54ea0f1bf..2b4209c519b1 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2647,7 +2647,7 @@ public class TelephonyManager { */ /** {@hide} */ @UnsupportedAppUsage - public static String getNetworkTypeName(int type) { + public static String getNetworkTypeName(@NetworkType int type) { switch (type) { case NETWORK_TYPE_GPRS: return "GPRS"; @@ -4788,6 +4788,22 @@ public class TelephonyManager { } } + /** + * Convert data state to string + * + * @return The data state in string format. + * @hide + */ + public static String dataStateToString(@DataState int state) { + switch (state) { + case DATA_DISCONNECTED: return "DISCONNECTED"; + case DATA_CONNECTING: return "CONNECTING"; + case DATA_CONNECTED: return "CONNECTED"; + case DATA_SUSPENDED: return "SUSPENDED"; + } + return "UNKNOWN(" + state + ")"; + } + /** * @hide */ @@ -10680,6 +10696,25 @@ public class TelephonyManager { } /** + * It indicates whether modem is enabled or not per slot. + * It's the corresponding status of {@link #enableModemForSlot}. + * + * @param slotIndex which slot it's checking. + * @hide + */ + public boolean isModemEnabledForSlot(int slotIndex) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName()); + } + } catch (RemoteException ex) { + Log.e(TAG, "enableModem RemoteException", ex); + } + return false; + } + + /** * Indicate if the user is allowed to use multiple SIM cards at the same time to register * on the network (e.g. Dual Standby or Dual Active) when the device supports it, or if the * usage is restricted. This API is used to prevent usage of multiple SIM card, based on diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 26d0c82b2d00..d173cc9c44e5 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1955,5 +1955,7 @@ interface ITelephony { /** * Get the IRadio HAL Version encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown */ - int getRadioHalVersion(); + int getRadioHalVersion(); + + boolean isModemEnabledForSlot(int slotIndex, String callingPackage); } diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp new file mode 100644 index 000000000000..f16ddb9bc68e --- /dev/null +++ b/tests/benchmarks/Android.bp @@ -0,0 +1,29 @@ +// 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. + +// build framework base core benchmarks +// ============================================================ + +java_library { + name: "networkStatsFactory-benchmarks", + installable: true, + + srcs: ["src/**/*.java"], + + libs: [ + "caliper-api-target", + "services.core", + ], + +} diff --git a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java index c2134649655a..ef014f0d4e53 100644 --- a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java +++ b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.android.internal.net; +package com.android.server.net; import android.net.NetworkStats; import android.os.SystemClock; +import com.android.server.net.NetworkStatsFactory; import com.google.caliper.AfterExperiment; import com.google.caliper.BeforeExperiment; import java.io.File; diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 176f54152256..c8ef82ec9acc 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -1,11 +1,8 @@ //######################################################################## // Build FrameworksNetTests package //######################################################################## - -android_test { - name: "FrameworksNetTests", - // Include all test java files. - srcs: ["java/**/*.java"], +java_defaults { + name: "FrameworksNetTests-jni-defaults", static_libs: [ "FrameworksNetCommonTests", "frameworks-base-testutils", @@ -21,6 +18,53 @@ android_test { "android.test.base", "android.test.mock", ], + jni_libs: [ + "ld-android", + "libartbase", + "libbacktrace", + "libbase", + "libbinder", + "libbinderthreadstate", + "libbpf", + "libbpf_android", + "libc++", + "libcgrouprc", + "libcrypto", + "libcutils", + "libdexfile", + "libdl_android", + "libhidl-gen-utils", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libjsoncpp", + "liblog", + "liblzma", + "libnativehelper", + "libnetdbpf", + "libnetdutils", + "libpackagelistparser", + "libpcre2", + "libprocessgroup", + "libselinux", + "libui", + "libutils", + "libvintf", + "libvndksupport", + "libtinyxml2", + "libunwindstack", + "libutilscallstack", + "libziparchive", + "libz", + "netd_aidl_interface-cpp", + "libnetworkstatsfactorytestjni", + ], +} + +android_test { + name: "FrameworksNetTests", + defaults: ["FrameworksNetTests-jni-defaults"], + srcs: ["java/**/*.java"], platform_apis: true, test_suites: ["device-tests"], certificate: "platform", diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java index 8b2b4e3cd443..2adbb06babf1 100644 --- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java +++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java @@ -45,6 +45,7 @@ import androidx.test.runner.AndroidJUnit4; import libcore.util.HexEncoding; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -189,6 +190,8 @@ public class InetDiagSocketTest { udp.close(); } + @Ignore + @Test public void testGetConnectionOwnerUid() throws Exception { checkGetConnectionOwnerUid("::", null); checkGetConnectionOwnerUid("::", "::"); diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java index 4ec4fdd80a00..95bc7d92d538 100644 --- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.net; +package com.android.server.net; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -70,6 +70,10 @@ public class NetworkStatsFactoryTest { IoUtils.deleteContents(mTestProc); } + // The libandroid_servers which have the native method is not available to + // applications. So in order to have a test support native library, the native code + // related to networkStatsFactory is compiled to a minimal native library and loaded here. + System.loadLibrary("networkstatsfactorytestjni"); mFactory = new NetworkStatsFactory(mTestProc, false); } diff --git a/tests/net/jni/Android.bp b/tests/net/jni/Android.bp new file mode 100644 index 000000000000..9225ffb24bd8 --- /dev/null +++ b/tests/net/jni/Android.bp @@ -0,0 +1,23 @@ +cc_library_shared { + name: "libnetworkstatsfactorytestjni", + + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wthread-safety", + ], + + srcs: [ + ":lib_networkStatsFactory_native", + "test_onload.cpp", + ], + + shared_libs: [ + "libbpf_android", + "liblog", + "libnativehelper", + "libnetdbpf", + "libnetdutils", + ], +} diff --git a/tests/net/jni/test_onload.cpp b/tests/net/jni/test_onload.cpp new file mode 100644 index 000000000000..5194ddb0d882 --- /dev/null +++ b/tests/net/jni/test_onload.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 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. + */ + +/* + * this is a mini native libaray for NetworkStatsFactoryTest to run properly. It + * load all the native method related to NetworkStatsFactory when test run + */ +#include <nativehelper/JNIHelp.h> +#include "jni.h" +#include "utils/Log.h" +#include "utils/misc.h" + +namespace android { +int register_android_server_net_NetworkStatsFactory(JNIEnv* env); +}; + +using namespace android; + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + ALOGE("GetEnv failed!"); + return result; + } + ALOG_ASSERT(env, "Could not retrieve the env!"); + register_android_server_net_NetworkStatsFactory(env); + return JNI_VERSION_1_4; +} diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index 5725f0cdae6e..4ce4406211ce 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -31,6 +31,7 @@ cc_binary_host { shared_libs: [ "libstats_proto_host", "libprotobuf-cpp-full", + "libbase", ], proto: { diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index 61174d99198b..49eee0708a45 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -48,7 +48,9 @@ AtomDecl::AtomDecl(const AtomDecl& that) primaryFields(that.primaryFields), exclusiveField(that.exclusiveField), uidField(that.uidField), - binaryFields(that.binaryFields) {} + binaryFields(that.binaryFields), + hasModule(that.hasModule), + moduleName(that.moduleName) {} AtomDecl::AtomDecl(int c, const string& n, const string& m) :code(c), @@ -375,30 +377,60 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { const Descriptor *atom = atomField->message_type(); AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name()); + + if (atomField->options().HasExtension(os::statsd::log_from_module)) { + atomDecl.hasModule = true; + atomDecl.moduleName = atomField->options().GetExtension(os::statsd::log_from_module); + } + vector<java_type_t> signature; errorCount += collate_atom(atom, &atomDecl, &signature); if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) { errorCount++; } - atoms->signatures.insert(signature); + + // Add the signature if does not already exist. + auto signature_to_modules_it = atoms->signatures_to_modules.find(signature); + if (signature_to_modules_it == atoms->signatures_to_modules.end()) { + set<string> modules; + if (atomDecl.hasModule) { + modules.insert(atomDecl.moduleName); + } + atoms->signatures_to_modules[signature] = modules; + } else { + if (atomDecl.hasModule) { + signature_to_modules_it->second.insert(atomDecl.moduleName); + } + } atoms->decls.insert(atomDecl); AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name()); vector<java_type_t> nonChainedSignature; if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) { - atoms->non_chained_signatures.insert(nonChainedSignature); + auto it = atoms->non_chained_signatures_to_modules.find(signature); + if (it == atoms->non_chained_signatures_to_modules.end()) { + set<string> modules_non_chained; + if (atomDecl.hasModule) { + modules_non_chained.insert(atomDecl.moduleName); + } + atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained; + } else { + if (atomDecl.hasModule) { + it->second.insert(atomDecl.moduleName); + } + } atoms->non_chained_decls.insert(nonChainedAtomDecl); } } if (dbg) { printf("signatures = [\n"); - for (set<vector<java_type_t>>::const_iterator it = - atoms->signatures.begin(); - it != atoms->signatures.end(); it++) { + for (map<vector<java_type_t>, set<string>>::const_iterator it = + atoms->signatures_to_modules.begin(); + it != atoms->signatures_to_modules.end(); it++) { printf(" "); - for (vector<java_type_t>::const_iterator jt = it->begin(); - jt != it->end(); jt++) { + for (vector<java_type_t>::const_iterator jt = it->first.begin(); + jt != it->first.end(); jt++) { printf(" %d", (int)*jt); } printf("\n"); diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index a8b270caefaf..e0ea207793f9 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -88,6 +88,9 @@ struct AtomDecl { vector<int> binaryFields; + bool hasModule = false; + string moduleName; + AtomDecl(); AtomDecl(const AtomDecl& that); AtomDecl(int code, const string& name, const string& message); @@ -99,10 +102,10 @@ struct AtomDecl { }; struct Atoms { - set<vector<java_type_t>> signatures; + map<vector<java_type_t>, set<string>> signatures_to_modules; set<AtomDecl> decls; set<AtomDecl> non_chained_decls; - set<vector<java_type_t>> non_chained_signatures; + map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules; }; /** diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 27e77fee83a3..73a0fe186181 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -12,6 +12,8 @@ #include <stdlib.h> #include <string.h> +#include "android-base/strings.h" + using namespace google::protobuf; using namespace std; @@ -22,6 +24,10 @@ const int PULL_ATOM_START_ID = 1000; int maxPushedAtomId = 2; +const string DEFAULT_MODULE_NAME = "DEFAULT"; +const string DEFAULT_CPP_NAMESPACE = "android,util"; +const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; + using android::os::statsd::Atom; /** @@ -99,40 +105,27 @@ java_type_name(java_type_t type) } } -static int write_stats_log_cpp(FILE *out, const Atoms &atoms, - const AtomDecl &attributionDecl) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - - fprintf(out, "#include <mutex>\n"); - fprintf(out, "#include <chrono>\n"); - fprintf(out, "#include <thread>\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "#include <cutils/properties.h>\n"); - fprintf(out, "#endif\n"); - fprintf(out, "#include <stats_event_list.h>\n"); - fprintf(out, "#include <log/log.h>\n"); - fprintf(out, "#include <statslog.h>\n"); - fprintf(out, "#include <utils/SystemClock.h>\n"); - fprintf(out, "\n"); +static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return atomDecl.hasModule && (moduleName == atomDecl.moduleName); +} - fprintf(out, "namespace android {\n"); - fprintf(out, "namespace util {\n"); - fprintf(out, "// the single event tag id for all stats logs\n"); - fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); - fprintf(out, "#else\n"); - fprintf(out, "const static bool kStatsdEnabled = false;\n"); - fprintf(out, "#endif\n"); +static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return modules.find(moduleName) != modules.end(); +} +static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) { std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed", - "audio_state_changed", - "call_state_changed", - "phone_signal_strength_changed", - "mobile_bytes_transfer_by_fg_bg", - "mobile_bytes_transfer"}; + "audio_state_changed", + "call_state_changed", + "phone_signal_strength_changed", + "mobile_bytes_transfer_by_fg_bg", + "mobile_bytes_transfer"}; fprintf(out, "const std::set<int> " "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n"); @@ -244,6 +237,56 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, "const std::map<int, std::vector<int>> " "AtomsInfo::kBytesFieldAtoms = " "getBinaryFieldAtoms();\n"); +} + +// Writes namespaces for the cpp and header files, returning the number of namespaces written. +void write_namespace(FILE* out, const string& cppNamespaces) { + vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); + for (string cppNamespace : cppNamespaceVec) { + fprintf(out, "namespace %s {\n", cppNamespace.c_str()); + } +} + +// Writes namespace closing brackets for cpp and header files. +void write_closing_namespace(FILE* out, const string& cppNamespaces) { + vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); + for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) { + fprintf(out, "} // namespace %s\n", it->c_str()); + } +} + +static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace, + const string& importHeader) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + + fprintf(out, "#include <mutex>\n"); + fprintf(out, "#include <chrono>\n"); + fprintf(out, "#include <thread>\n"); + fprintf(out, "#ifdef __ANDROID__\n"); + fprintf(out, "#include <cutils/properties.h>\n"); + fprintf(out, "#endif\n"); + fprintf(out, "#include <stats_event_list.h>\n"); + fprintf(out, "#include <log/log.h>\n"); + fprintf(out, "#include <%s>\n", importHeader.c_str()); + fprintf(out, "#include <utils/SystemClock.h>\n"); + fprintf(out, "\n"); + + write_namespace(out, cppNamespace); + fprintf(out, "// the single event tag id for all stats logs\n"); + fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); + fprintf(out, "#ifdef __ANDROID__\n"); + fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); + fprintf(out, "#else\n"); + fprintf(out, "const static bool kStatsdEnabled = false;\n"); + fprintf(out, "#endif\n"); + + // AtomsInfo is only used by statsd internally and is not needed for other modules. + if (moduleName == DEFAULT_MODULE_NAME) { + write_atoms_info_cpp(out, atoms); + } fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); @@ -251,15 +294,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, // Print write methods fprintf(out, "\n"); - for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin(); - signature != atoms.signatures.end(); signature++) { + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_to_modules_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "try_stats_write(int32_t code"); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -285,8 +332,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " stats_event_list event(kStatsEventTag);\n"); fprintf(out, " event << android::elapsedRealtimeNano();\n\n"); fprintf(out, " event << code;\n\n"); - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (const auto &chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -338,15 +385,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "\n"); } - for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin(); - signature != atoms.signatures.end(); signature++) { + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_to_modules_it->first; int argIndex; fprintf(out, "int \n"); fprintf(out, "stats_write(int32_t code"); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -373,8 +424,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " ret = try_stats_write(code"); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -407,15 +458,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "\n"); } - for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin(); - signature != atoms.non_chained_signatures.end(); signature++) { + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "try_stats_write_non_chained(int32_t code"); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); argIndex++; } @@ -427,8 +482,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " stats_event_list event(kStatsEventTag);\n"); fprintf(out, " event << android::elapsedRealtimeNano();\n\n"); fprintf(out, " event << code;\n\n"); - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (argIndex == 1) { fprintf(out, " event.begin();\n\n"); fprintf(out, " event.begin();\n"); @@ -461,15 +516,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "\n"); } - for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin(); - signature != atoms.non_chained_signatures.end(); signature++) { + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector<java_type_t> signature = signature_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "stats_write_non_chained(int32_t code"); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); argIndex++; } @@ -482,8 +541,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " ret = try_stats_write_non_chained(code"); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { fprintf(out, ", arg%d", argIndex); argIndex++; } @@ -508,8 +567,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, // Print footer fprintf(out, "\n"); - fprintf(out, "} // namespace util\n"); - fprintf(out, "} // namespace android\n"); + write_closing_namespace(out, cppNamespace); return 0; } @@ -550,14 +608,23 @@ static void write_cpp_usage( } static void write_cpp_method_header( - FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures, - const AtomDecl &attributionDecl) { - for (set<vector<java_type_t>>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { - fprintf(out, "int %s(int32_t code ", method_name.c_str()); + FILE* out, + const string& method_name, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, const string& moduleName) { + + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + + vector<java_type_t> signature = signature_to_modules_it->first; + fprintf(out, "int %s(int32_t code", method_name.c_str()); int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -580,7 +647,8 @@ static void write_cpp_method_header( } static int -write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) +write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace) { // Print prelude fprintf(out, "// This file is autogenerated\n"); @@ -593,8 +661,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "#include <set>\n"); fprintf(out, "\n"); - fprintf(out, "namespace android {\n"); - fprintf(out, "namespace util {\n"); + write_namespace(out, cppNamespace); fprintf(out, "\n"); fprintf(out, "/*\n"); fprintf(out, " * API For logging statistics events.\n"); @@ -612,6 +679,10 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio // Print constants for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } string constant = make_constant_name(atom->name); fprintf(out, "\n"); fprintf(out, " /**\n"); @@ -644,45 +715,49 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "};\n"); fprintf(out, "\n"); - fprintf(out, "struct StateAtomFieldOptions {\n"); - fprintf(out, " std::vector<int> primaryFields;\n"); - fprintf(out, " int exclusiveField;\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); + // This metadata is only used by statsd, which uses the default libstatslog. + if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, "struct AtomsInfo {\n"); - fprintf(out, - " const static std::set<int> " - "kNotTruncatingTimestampAtomWhiteList;\n"); - fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n"); - fprintf(out, - " const static std::set<int> kAtomsWithAttributionChain;\n"); - fprintf(out, - " const static std::map<int, StateAtomFieldOptions> " - "kStateAtomsFieldOptions;\n"); - fprintf(out, - " const static std::map<int, std::vector<int>> " - "kBytesFieldAtoms;"); - fprintf(out, "};\n"); + fprintf(out, "struct StateAtomFieldOptions {\n"); + fprintf(out, " std::vector<int> primaryFields;\n"); + fprintf(out, " int exclusiveField;\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, "struct AtomsInfo {\n"); + fprintf(out, + " const static std::set<int> " + "kNotTruncatingTimestampAtomWhiteList;\n"); + fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n"); + fprintf(out, + " const static std::set<int> kAtomsWithAttributionChain;\n"); + fprintf(out, + " const static std::map<int, StateAtomFieldOptions> " + "kStateAtomsFieldOptions;\n"); + fprintf(out, + " const static std::map<int, std::vector<int>> " + "kBytesFieldAtoms;"); + fprintf(out, "};\n"); - fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", - maxPushedAtomId); + fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", + maxPushedAtomId); + } // Print write methods fprintf(out, "//\n"); fprintf(out, "// Write methods\n"); fprintf(out, "//\n"); - write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl); + write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl, + moduleName); fprintf(out, "//\n"); fprintf(out, "// Write flattened methods\n"); fprintf(out, "//\n"); - write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures, - attributionDecl); + write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl, moduleName); fprintf(out, "\n"); - fprintf(out, "} // namespace util\n"); - fprintf(out, "} // namespace android\n"); + write_closing_namespace(out, cppNamespace); return 0; } @@ -705,15 +780,19 @@ static void write_java_usage(FILE* out, const string& method_name, const string& } static void write_java_method( - FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures, - const AtomDecl &attributionDecl) { - for (set<vector<java_type_t>>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + FILE* out, + const string& method_name, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl) { + + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector<java_type_t> signature = signature_to_modules_it->first; fprintf(out, " /** @hide */\n"); fprintf(out, " public static native int %s(int code", method_name.c_str()); int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { fprintf(out, ", %s[] %s", @@ -728,15 +807,17 @@ static void write_java_method( } } -static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) { +static void write_java_work_source_method(FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules) { fprintf(out, "\n // WorkSource methods.\n"); - for (set<vector<java_type_t>>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector<java_type_t> signature = signature_to_modules_it->first; // Determine if there is Attribution in this signature. int attributionArg = -1; int argIndexMax = 0; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { argIndexMax++; if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (attributionArg > -1) { @@ -756,8 +837,8 @@ static void write_java_work_source_method(FILE* out, const set<vector<java_type_ fprintf(out, " /** @hide */\n"); fprintf(out, " public static void write(int code"); int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { fprintf(out, ", WorkSource ws"); } else { @@ -864,9 +945,10 @@ write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionD // Print write methods fprintf(out, " // Write methods\n"); - write_java_method(out, "write", atoms.signatures, attributionDecl); - write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl); - write_java_work_source_method(out, atoms.signatures); + write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl); + write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl); + write_java_work_source_method(out, atoms.signatures_to_modules); fprintf(out, "}\n"); @@ -995,19 +1077,20 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att static int write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name, - const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) -{ + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl) { // Print write methods - for (set<vector<java_type_t>>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector<java_type_t> signature = signature_to_modules_it->first; int argIndex; fprintf(out, "static int\n"); fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code", - jni_function_name(java_method_name, *signature).c_str()); + jni_function_name(java_method_name, signature).c_str()); argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType), @@ -1025,8 +1108,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp // Prepare strings argIndex = 1; bool hadStringOrChain = false; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_STRING) { hadStringOrChain = true; fprintf(out, " const char* str%d;\n", argIndex); @@ -1121,8 +1204,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp argIndex = 1; fprintf(out, "\n int ret = android::util::%s(code", cpp_method_name.c_str()); - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_INT) { @@ -1147,8 +1230,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp // Clean up strings argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_STRING) { fprintf(out, " if (str%d != NULL) {\n", argIndex); fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n", @@ -1187,13 +1270,15 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp } void write_jni_registration(FILE* out, const string& java_method_name, - const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) { - for (set<vector<java_type_t>>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector<java_type_t> signature = signature_to_modules_it->first; fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n", java_method_name.c_str(), - jni_function_signature(*signature, attributionDecl).c_str(), - jni_function_name(java_method_name, *signature).c_str()); + jni_function_signature(signature, attributionDecl).c_str(), + jni_function_name(java_method_name, signature).c_str()); } } @@ -1218,17 +1303,18 @@ write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDe fprintf(out, "namespace android {\n"); fprintf(out, "\n"); - write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl); + write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl); write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained", - atoms.non_chained_signatures, attributionDecl); + atoms.non_chained_signatures_to_modules, attributionDecl); // Print registration function table fprintf(out, "/*\n"); fprintf(out, " * JNI registration.\n"); fprintf(out, " */\n"); fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n"); - write_jni_registration(out, "write", atoms.signatures, attributionDecl); - write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl); + write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl); + write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl); fprintf(out, "};\n"); fprintf(out, "\n"); @@ -1256,6 +1342,10 @@ print_usage() fprintf(stderr, " --help this message\n"); fprintf(stderr, " --java FILENAME the java file to output\n"); fprintf(stderr, " --jni FILENAME the jni file to output\n"); + fprintf(stderr, " --module NAME optional, module name to generate outputs for\n"); + fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n"); + fprintf(stderr, " comma separated namespace of the files\n"); + fprintf(stderr, " --importHeader NAME required for cpp/jni to say which header to import\n"); } /** @@ -1269,6 +1359,10 @@ run(int argc, char const*const* argv) string javaFilename; string jniFilename; + string moduleName = DEFAULT_MODULE_NAME; + string cppNamespace = DEFAULT_CPP_NAMESPACE; + string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT; + int index = 1; while (index < argc) { if (0 == strcmp("--help", argv[index])) { @@ -1302,6 +1396,27 @@ run(int argc, char const*const* argv) return 1; } jniFilename = argv[index]; + } else if (0 == strcmp("--module", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + moduleName = argv[index]; + } else if (0 == strcmp("--namespace", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + cppNamespace = argv[index]; + } else if (0 == strcmp("--importHeader", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + cppHeaderImport = argv[index]; } index++; } @@ -1333,8 +1448,18 @@ run(int argc, char const*const* argv) fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str()); return 1; } + // If this is for a specific module, the namespace must also be provided. + if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { + fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); + return 1; + } + // If this is for a specific module, the header file to import must also be provided. + if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) { + fprintf(stderr, "Must supply --headerImport if supplying a specific module\n"); + return 1; + } errorCount = android::stats_log_api_gen::write_stats_log_cpp( - out, atoms, attributionDecl); + out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport); fclose(out); } @@ -1345,8 +1470,12 @@ run(int argc, char const*const* argv) fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str()); return 1; } + // If this is for a specific module, the namespace must also be provided. + if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { + fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); + } errorCount = android::stats_log_api_gen::write_stats_log_header( - out, atoms, attributionDecl); + out, atoms, attributionDecl, moduleName, cppNamespace); fclose(out); } diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto index 188b765e241e..6922e9ce9dff 100644 --- a/tools/stats_log_api_gen/test.proto +++ b/tools/stats_log_api_gen/test.proto @@ -195,4 +195,24 @@ message GoodStateAtom3 { [(android.os.statsd.stateFieldOption).option = PRIMARY]; optional int32 state = 3 [(android.os.statsd.stateFieldOption).option = EXCLUSIVE]; -}
\ No newline at end of file +} + +message ModuleOneAtom { + optional int32 field = 1; +} + +message ModuleTwoAtom { + optional int32 field = 1; +} + +message NoModuleAtom { + optional string field = 1; +} + +message ModuleAtoms { + oneof event { + ModuleOneAtom module_one_atom = 1 [(android.os.statsd.log_from_module) = "module1"]; + ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.log_from_module) = "module2"]; + NoModuleAtom no_module_atom = 3; + } +} diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp index ad3bffacd442..f59bb6f49ce1 100644 --- a/tools/stats_log_api_gen/test_collation.cpp +++ b/tools/stats_log_api_gen/test_collation.cpp @@ -32,7 +32,7 @@ using std::vector; * Return whether the set contains a vector of the elements provided. */ static bool -set_contains_vector(const set<vector<java_type_t>>& s, int count, ...) +set_contains_vector(const map<vector<java_type_t>, set<string>>& s, int count, ...) { va_list args; vector<java_type_t> v; @@ -86,17 +86,17 @@ TEST(CollationTest, CollateStats) { int errorCount = collate_atoms(Event::descriptor(), &atoms); EXPECT_EQ(0, errorCount); - EXPECT_EQ(3ul, atoms.signatures.size()); + EXPECT_EQ(3ul, atoms.signatures_to_modules.size()); // IntAtom, AnotherIntAtom - EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT); // OutOfOrderAtom - EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT, JAVA_TYPE_INT); // AllTypesAtom EXPECT_SET_CONTAINS_SIGNATURE( - atoms.signatures, + atoms.signatures_to_modules, JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain JAVA_TYPE_DOUBLE, // double JAVA_TYPE_FLOAT, // float @@ -226,5 +226,46 @@ TEST(CollationTest, FailOnBadBinaryFieldAtom) { EXPECT_TRUE(errorCount > 0); } +TEST(CollationTest, PassOnLogFromModuleAtom) { + Atoms atoms; + int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms); + EXPECT_EQ(errorCount, 0); + EXPECT_EQ(atoms.decls.size(), 3ul); +} + +TEST(CollationTest, RecognizeModuleAtom) { + Atoms atoms; + int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms); + EXPECT_EQ(errorCount, 0); + EXPECT_EQ(atoms.decls.size(), 3ul); + for (const auto& atomDecl: atoms.decls) { + if (atomDecl.code == 1) { + EXPECT_TRUE(atomDecl.hasModule); + EXPECT_EQ(atomDecl.moduleName, "module1"); + } else if (atomDecl.code == 2) { + EXPECT_TRUE(atomDecl.hasModule); + EXPECT_EQ(atomDecl.moduleName, "module2"); + } else { + EXPECT_FALSE(atomDecl.hasModule); + } + } + + EXPECT_EQ(atoms.signatures_to_modules.size(), 2u); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_STRING); + for (auto signature_to_modules_it : atoms.signatures_to_modules) { + vector<java_type_t> signature = signature_to_modules_it.first; + if (signature[0] == JAVA_TYPE_STRING) { + EXPECT_EQ(signature_to_modules_it.second.size(), 0u); + } else if (signature[0] == JAVA_TYPE_INT) { + set<string> modules = signature_to_modules_it.second; + EXPECT_EQ(modules.size(), 2u); + // Assert that the set contains "module1" and "module2". + EXPECT_NE(modules.find("module1"), modules.end()); + EXPECT_NE(modules.find("module2"), modules.end()); + } + } +} + } // namespace stats_log_api_gen -} // namespace android
\ No newline at end of file +} // namespace android |