diff options
30 files changed, 730 insertions, 315 deletions
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/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/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/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/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 88955d7e4667..524548f6233d 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; @@ -238,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 @@ -1769,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)); } } @@ -6712,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/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/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/net/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl index e1fe9e5cdc21..1e7726472ff6 100644 --- a/services/net/java/android/net/ip/IIpClient.aidl +++ b/services/net/java/android/net/ip/IIpClient.aidl @@ -27,10 +27,10 @@ oneway interface IIpClient { void shutdown(); void startProvisioning(in ProvisioningConfigurationParcelable req); void stop(); - void setL2KeyAndGroupHint(in String l2Key, in String groupHint); void setTcpBufferSizes(in String tcpBufferSizes); void setHttpProxy(in ProxyInfo proxyInfo); void setMulticastFilter(boolean enabled); void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt); void removeKeepalivePacketFilter(int slot); + void setL2KeyAndGroupHint(in String l2Key, in String groupHint); } 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/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 f9d9baba0beb..2b4209c519b1 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10696,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/net/Android.bp b/tests/net/Android.bp index 45eeb2a2067a..c8ef82ec9acc 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -28,6 +28,7 @@ java_defaults { "libbpf", "libbpf_android", "libc++", + "libcgrouprc", "libcrypto", "libcutils", "libdexfile", 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 |