summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapi/current.txt2
-rw-r--r--api/system-current.txt4
-rw-r--r--api/test-current.txt4
-rw-r--r--cmds/statsd/src/atom_field_options.proto4
-rw-r--r--core/java/android/os/SELinux.java8
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/util/PackageUtils.java8
-rw-r--r--core/jni/Android.bp2
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp6
-rw-r--r--core/jni/fd_utils.cpp2
-rw-r--r--core/res/res/values/config.xml9
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--media/java/android/media/MediaHTTPConnection.java244
-rw-r--r--media/jni/android_media_MediaHTTPConnection.cpp9
-rw-r--r--packages/NetworkStack/Android.bp1
-rw-r--r--packages/NetworkStack/res/values/config.xml37
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java189
-rw-r--r--packages/NetworkStack/tests/Android.bp2
-rw-r--r--packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java15
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java9
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java46
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java2
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java21
-rw-r--r--services/core/java/com/android/server/media/AudioPlayerStateMonitor.java173
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java10
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java3
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java29
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java (renamed from core/java/com/android/internal/net/NetworkStatsFactory.java)2
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java1
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java69
-rw-r--r--services/core/jni/Android.bp8
-rw-r--r--services/core/jni/com_android_server_net_NetworkStatsFactory.cpp (renamed from core/jni/com_android_internal_net_NetworkStatsFactory.cpp)44
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/net/java/android/net/shared/NetworkMonitorUtils.java12
-rw-r--r--telecomm/java/android/telecom/CallRedirectionService.java2
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java44
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthTdscdma.java41
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthWcdma.java8
-rw-r--r--telephony/java/android/telephony/PhoneCapability.java19
-rw-r--r--telephony/java/android/telephony/ServiceState.java1
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java6
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java37
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl4
-rw-r--r--tests/benchmarks/Android.bp29
-rw-r--r--tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java (renamed from core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java)3
-rw-r--r--tests/net/Android.bp54
-rw-r--r--tests/net/java/android/net/netlink/InetDiagSocketTest.java3
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java (renamed from tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java)6
-rw-r--r--tests/net/jni/Android.bp23
-rw-r--r--tests/net/jni/test_onload.cpp44
-rw-r--r--tools/stats_log_api_gen/Android.bp1
-rw-r--r--tools/stats_log_api_gen/Collation.cpp48
-rw-r--r--tools/stats_log_api_gen/Collation.h7
-rw-r--r--tools/stats_log_api_gen/main.cpp395
-rw-r--r--tools/stats_log_api_gen/test.proto22
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp53
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