diff options
272 files changed, 4876 insertions, 2119 deletions
diff --git a/api/current.txt b/api/current.txt index 2b0269df2d8f..5295b474066a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -112,6 +112,7 @@ package android { field public static final String READ_LOGS = "android.permission.READ_LOGS"; field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS"; field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; + field public static final String READ_PRECISE_PHONE_STATE = "android.permission.READ_PRECISE_PHONE_STATE"; field public static final String READ_SMS = "android.permission.READ_SMS"; field public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS"; field public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS"; @@ -45416,6 +45417,7 @@ package android.telephony { method public long getDataLimitBytes(); method public long getDataUsageBytes(); method public long getDataUsageTime(); + method @Nullable public int[] getNetworkTypes(); method @Nullable public CharSequence getSummary(); method @Nullable public CharSequence getTitle(); method public void writeToParcel(android.os.Parcel, int); @@ -45435,6 +45437,7 @@ package android.telephony { method public static android.telephony.SubscriptionPlan.Builder createRecurring(java.time.ZonedDateTime, java.time.Period); method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int); method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long); + method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@Nullable int[]); method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence); method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence); } diff --git a/api/system-current.txt b/api/system-current.txt index 35fea93c93ed..73bfd203ff37 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1413,6 +1413,10 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); } + public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); + } + public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile { method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice); @@ -1421,12 +1425,20 @@ package android.bluetooth { field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; } + public final class BluetoothMap implements android.bluetooth.BluetoothProfile { + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int); + field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED"; + } + public final class BluetoothPan implements android.bluetooth.BluetoothProfile { method protected void finalize(); method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice); method public boolean isTetheringOn(); method public void setBluetoothTethering(boolean); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; field public static final int LOCAL_NAP_ROLE = 1; // 0x1 @@ -4415,6 +4427,7 @@ package android.net { } public final class NetworkCapabilities implements android.os.Parcelable { + method public boolean deduceRestrictedCapability(); method @NonNull public int[] getTransportTypes(); method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities); method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String); @@ -6770,6 +6783,7 @@ package android.provider { } public final class Settings { + method public static boolean checkAndNoteWriteSettingsOperation(@NonNull android.content.Context, int, @NonNull String, boolean); field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS"; field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS"; diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 8944dedd6c96..da1a76f8169d 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -138,11 +138,57 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power.stats@1.0", "libpackagelistparser", + "libstatsmetadata", "libsysutils", "libcutils", ], } +// ================ +// libstatsmetadata +// ================ + +genrule { + name: "atoms_info.h", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --atomsInfoHeader $(genDir)/atoms_info.h", + out: [ + "atoms_info.h", + ], +} + +genrule { + name: "atoms_info.cpp", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --atomsInfoCpp $(genDir)/atoms_info.cpp", + out: [ + "atoms_info.cpp", + ], +} + +cc_library_shared { + name: "libstatsmetadata", + host_supported: true, + generated_sources: [ + "atoms_info.cpp", + ], + generated_headers: [ + "atoms_info.h", + ], + cflags: [ + "-Wall", + "-Werror", + ], + export_generated_headers: [ + "atoms_info.h", + ], + shared_libs: [ + "libcutils", + "libstatslog", + ], +} + + // ========= // statsd // ========= diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp index 13f5c8ae5fd8..320a32ab4648 100644 --- a/cmds/statsd/src/FieldValue.cpp +++ b/cmds/statsd/src/FieldValue.cpp @@ -18,8 +18,8 @@ #include "Log.h" #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "atoms_info.h" #include "math.h" -#include "statslog.h" namespace android { namespace os { diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index ff7416c4b9e0..c9e026bf231c 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -23,6 +23,7 @@ #include <frameworks/base/cmds/statsd/src/active_config_list.pb.h> #include "StatsLogProcessor.h" #include "android-base/stringprintf.h" +#include "atoms_info.h" #include "external/StatsPullerManager.h" #include "guardrail/StatsdStats.h" #include "metrics/CountMetricProducer.h" diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp index b142caca3acc..dc69b78f0329 100644 --- a/cmds/statsd/src/external/PowerStatsPuller.cpp +++ b/cmds/statsd/src/external/PowerStatsPuller.cpp @@ -22,6 +22,7 @@ #include <vector> #include "PowerStatsPuller.h" +#include "statslog.h" #include "stats_log_util.h" using android::hardware::hidl_vec; diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index 0b9b6abfd6d6..ccfd666573c4 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -18,8 +18,8 @@ #include "Log.h" #include "StatsPullerManager.h" +#include "atoms_info.h" #include "puller_util.h" -#include "statslog.h" namespace android { namespace os { diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 23d2aceb4fc3..564b9ee8051c 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -16,7 +16,7 @@ #pragma once #include "config/ConfigKey.h" -#include "statslog.h" +#include "atoms_info.h" #include <gtest/gtest_prod.h> #include <log/log_time.h> diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 963205ee56f4..7b7d0cac0d30 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -19,6 +19,7 @@ #include "statslog.h" #include "CountMetricProducer.h" +#include "atoms_info.h" #include "condition/CombinationConditionTracker.h" #include "condition/SimpleConditionTracker.h" #include "guardrail/StatsdStats.h" diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 5cfb1239d30e..46442b57126c 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -32,8 +32,8 @@ #include "../metrics/GaugeMetricProducer.h" #include "../metrics/ValueMetricProducer.h" +#include "atoms_info.h" #include "stats_util.h" -#include "statslog.h" #include <inttypes.h> diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h index bfb84cf4d1b9..a28165d09cdf 100644 --- a/cmds/statsd/src/stats_log_util.h +++ b/cmds/statsd/src/stats_log_util.h @@ -19,9 +19,9 @@ #include <android/util/ProtoOutputStream.h> #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "atoms_info.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "guardrail/StatsdStats.h" -#include "statslog.h" namespace android { namespace os { diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp index bdc52b0af34c..32409184b02f 100644 --- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp +++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp @@ -24,6 +24,7 @@ #include <log/log.h> #include "src/external/GpuStatsPuller.h" +#include "statslog.h" #ifdef __ANDROID__ diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp index 266ea351b5d4..673082834e18 100644 --- a/cmds/statsd/tests/external/puller_util_test.cpp +++ b/cmds/statsd/tests/external/puller_util_test.cpp @@ -17,6 +17,7 @@ #include <gtest/gtest.h> #include <stdio.h> #include <vector> +#include "statslog.h" #include "../metrics/metrics_test_helper.h" #ifdef __ANDROID__ diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java index e9b0be2c4cd6..a923be62fbce 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -16,8 +16,12 @@ package android.bluetooth; +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -36,6 +40,7 @@ import java.util.concurrent.Executor; */ public final class BluetoothHidDevice implements BluetoothProfile { private static final String TAG = BluetoothHidDevice.class.getSimpleName(); + private static final boolean DBG = false; /** * Intent used to broadcast the change in connection state of the Input Host profile. @@ -682,4 +687,62 @@ public final class BluetoothHidDevice implements BluetoothProfile { return result; } + + /** + * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} + * and disconnects Hid device if connectionPolicy is + * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}. + * + * <p> The device should already be paired. + * Connection policy can be one of: + * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, + * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, + * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} + * + * @param device Paired bluetooth device + * @param connectionPolicy determines whether hid device should be connected or disconnected + * @return true if hid device is connected or disconnected, false otherwise + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setConnectionPolicy(@NonNull BluetoothDevice device, + @ConnectionPolicy int connectionPolicy) { + log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + try { + final IBluetoothHidDevice service = getService(); + if (service != null && isEnabled() + && isValidDevice(device)) { + if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + if (DBG) { + Log.d(TAG, msg); + } + } } diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java index 979dfd4e3ba5..f2ceabcc7d75 100644 --- a/core/java/android/bluetooth/BluetoothMap.java +++ b/core/java/android/bluetooth/BluetoothMap.java @@ -17,7 +17,10 @@ package android.bluetooth; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.content.Context; @@ -35,21 +38,35 @@ import java.util.List; * * @hide */ +@SystemApi public final class BluetoothMap implements BluetoothProfile { private static final String TAG = "BluetoothMap"; private static final boolean DBG = true; private static final boolean VDBG = false; + /** @hide */ + @SuppressLint("ActionValue") + @SystemApi public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED"; - /** There was an error trying to obtain the state */ + /** + * There was an error trying to obtain the state + * + * @hide + */ public static final int STATE_ERROR = -1; + /** @hide */ public static final int RESULT_FAILURE = 0; + /** @hide */ public static final int RESULT_SUCCESS = 1; - /** Connection canceled before completion. */ + /** + * Connection canceled before completion. + * + * @hide + */ public static final int RESULT_CANCELED = 2; private BluetoothAdapter mAdapter; @@ -71,6 +88,7 @@ public final class BluetoothMap implements BluetoothProfile { mProfileConnector.connect(context, listener); } + @SuppressLint("GenericException") protected void finalize() throws Throwable { try { close(); @@ -84,6 +102,8 @@ public final class BluetoothMap implements BluetoothProfile { * Other public functions of BluetoothMap will return default error * results once close() has been called. Multiple invocations of close() * are ok. + * + * @hide */ public synchronized void close() { mProfileConnector.disconnect(); @@ -98,6 +118,8 @@ public final class BluetoothMap implements BluetoothProfile { * * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not * connected to the Map service. + * + * @hide */ public int getState() { if (VDBG) log("getState()"); @@ -120,6 +142,8 @@ public final class BluetoothMap implements BluetoothProfile { * * @return The remote Bluetooth device, or null if not in connected or connecting state, or if * this proxy object is not connected to the Map service. + * + * @hide */ public BluetoothDevice getClient() { if (VDBG) log("getClient()"); @@ -141,6 +165,8 @@ public final class BluetoothMap implements BluetoothProfile { * Returns true if the specified Bluetooth device is connected. * Returns false if not connected, or if this proxy object is not * currently connected to the Map service. + * + * @hide */ public boolean isConnected(BluetoothDevice device) { if (VDBG) log("isConnected(" + device + ")"); @@ -161,6 +187,8 @@ public final class BluetoothMap implements BluetoothProfile { /** * Initiate connection. Initiation of outgoing connections is not * supported for MAP server. + * + * @hide */ public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")" + "not supported for MAPS"); @@ -172,6 +200,8 @@ public final class BluetoothMap implements BluetoothProfile { * * @param device Remote Bluetooth Device * @return false on error, true otherwise + * + * @hide */ @UnsupportedAppUsage public boolean disconnect(BluetoothDevice device) { @@ -196,6 +226,8 @@ public final class BluetoothMap implements BluetoothProfile { * devices. It tries to err on the side of false positives. * * @return True if this device might support Map. + * + * @hide */ public static boolean doesClassMatchSink(BluetoothClass btClass) { // TODO optimize the rule @@ -214,8 +246,11 @@ public final class BluetoothMap implements BluetoothProfile { * Get the list of connected devices. Currently at most one. * * @return list of connected devices + * + * @hide */ - public List<BluetoothDevice> getConnectedDevices() { + @SystemApi + public @NonNull List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothMap service = getService(); if (service != null && isEnabled()) { @@ -234,6 +269,8 @@ public final class BluetoothMap implements BluetoothProfile { * Get the list of devices matching specified states. Currently at most one. * * @return list of matching devices + * + * @hide */ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); @@ -254,6 +291,8 @@ public final class BluetoothMap implements BluetoothProfile { * Get connection state of device * * @return device connection state + * + * @hide */ public int getConnectionState(BluetoothDevice device) { if (DBG) log("getConnectionState(" + device + ")"); @@ -301,7 +340,7 @@ public final class BluetoothMap implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) - public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { + public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothMap service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -349,7 +388,7 @@ public final class BluetoothMap implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - public int getConnectionPolicy(BluetoothDevice device) { + public int getConnectionPolicy(@Nullable BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothMap service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index 4e9762737c07..f5de4addb072 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -16,9 +16,11 @@ package android.bluetooth; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; @@ -256,6 +258,41 @@ public final class BluetoothPan implements BluetoothProfile { } /** + * Set connection policy of the profile + * + * <p> The device should already be paired. + * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, + * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + * + * @param device Paired bluetooth device + * @param connectionPolicy is the connection policy to set to for this profile + * @return true if connectionPolicy is set, false on error + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setConnectionPolicy(@NonNull BluetoothDevice device, + @ConnectionPolicy int connectionPolicy) { + if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + try { + final IBluetoothPan service = getService(); + if (service != null && isEnabled() + && isValidDevice(device)) { + if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { + return false; + } + return service.setConnectionPolicy(device, connectionPolicy); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + + /** * {@inheritDoc} */ @Override diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 291015070385..74ee2c3fba01 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -274,15 +274,15 @@ public class BluetoothPbap implements BluetoothProfile { } /** - * Pbap does not store connection policy, so this function only disconnects Pbap if - * connectionPolicy is CONNECTION_POLICY_FORBIDDEN. + * Pbap does not store connection policy, so this function only disconnects pbap if + * connectionPolicy is {@link #CONNECTION_POLICY_FORBIDDEN}. * * <p> The device should already be paired. * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device - * @param connectionPolicy is the connection policy to set to for this profile + * @param connectionPolicy determines whether to disconnect the device * @return true if pbap is successfully disconnected, false otherwise * @hide */ diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl index 106b7be5c8d3..fe9141cb6a20 100644 --- a/core/java/android/net/INetworkPolicyListener.aidl +++ b/core/java/android/net/INetworkPolicyListener.aidl @@ -15,6 +15,7 @@ */ package android.net; +import android.telephony.SubscriptionPlan; /** {@hide} */ oneway interface INetworkPolicyListener { @@ -22,5 +23,6 @@ oneway interface INetworkPolicyListener { void onMeteredIfacesChanged(in String[] meteredIfaces); void onRestrictBackgroundChanged(boolean restrictBackground); void onUidPoliciesChanged(int uid, int uidPolicies); - void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, long networkTypeMask); + void onSubscriptionOverride(int subId, int overrideMask, int overrideValue); + void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans); } diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 90327663e34b..385cb1d68b57 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -76,7 +76,7 @@ interface INetworkPolicyManager { SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage); void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage); String getSubscriptionPlansOwner(int subId); - void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long networkTypeMask, long timeoutMillis, String callingPackage); + void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, long timeoutMillis, String callingPackage); void factoryReset(String subscriber); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index a5e567d274c1..f43385d1f2e0 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -587,15 +587,14 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are - * typically provided by restricted networks. + * Deduces that all the capabilities it provides are typically provided by restricted networks + * or not. * - * TODO: consider: - * - Renaming it to guessRestrictedCapability and make it set the - * restricted capability bit in addition to clearing it. + * @return {@code true} if the network should be restricted. * @hide */ - public void maybeMarkCapabilitiesRestricted() { + @SystemApi + public boolean deduceRestrictedCapability() { // Check if we have any capability that forces the network to be restricted. final boolean forceRestrictedCapability = (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0; @@ -609,8 +608,17 @@ public final class NetworkCapabilities implements Parcelable { final boolean hasRestrictedCapabilities = (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0; - if (forceRestrictedCapability - || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities)) { + return forceRestrictedCapability + || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities); + } + + /** + * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted. + * + * @hide + */ + public void maybeMarkCapabilitiesRestricted() { + if (deduceRestrictedCapability()) { removeCapability(NET_CAPABILITY_NOT_RESTRICTED); } } diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index 42ab9256a6ab..f10ea20467a8 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; @@ -27,7 +28,6 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Protocol; @@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide **/ public class NetworkFactory extends Handler { - /** @hide */ + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public static class SerialNumber { // Guard used by no network factory. public static final int NONE = -1; @@ -92,7 +92,7 @@ public class NetworkFactory extends Handler { * Also, network conditions may change for this bearer * allowing for a better score in the future. * msg.arg2 = the serial number of the factory currently responsible for the - * NetworkAgent handling this request, or SerialNumber.NONE if none. + * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. */ public static final int CMD_REQUEST_NETWORK = BASE; @@ -124,7 +124,6 @@ public class NetworkFactory extends Handler { private final Context mContext; private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); - private AsyncChannel mAsyncChannel; private final String LOG_TAG; private final SparseArray<NetworkRequestInfo> mNetworkRequests = @@ -135,7 +134,8 @@ public class NetworkFactory extends Handler { private int mRefCount = 0; private Messenger mMessenger = null; - private int mSerialNumber; + private NetworkProvider mProvider = null; + private int mProviderId; @UnsupportedAppUsage public NetworkFactory(Looper looper, Context context, String logTag, @@ -147,55 +147,43 @@ public class NetworkFactory extends Handler { } public void register() { - if (DBG) log("Registering NetworkFactory"); - if (mMessenger == null) { - mMessenger = new Messenger(this); - mSerialNumber = ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, - LOG_TAG); + if (mProvider != null) { + Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory"); + return; } + if (DBG) log("Registering NetworkFactory"); + + mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { + @Override + public void onNetworkRequested(@NonNull NetworkRequest request, int score, + int servingFactoryProviderId) { + handleAddRequest((NetworkRequest) request, score, servingFactoryProviderId); + } + + @Override + public void onRequestWithdrawn(@NonNull NetworkRequest request) { + handleRemoveRequest(request); + } + }; + + mMessenger = new Messenger(this); + mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider); } public void unregister() { - if (DBG) log("Unregistering NetworkFactory"); - if (mMessenger != null) { - ConnectivityManager.from(mContext).unregisterNetworkFactory(mMessenger); - mMessenger = null; + if (mProvider == null) { + Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory"); + return; } + if (DBG) log("Unregistering NetworkFactory"); + + ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider); + mProvider = null; } @Override public void handleMessage(Message msg) { switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - if (mAsyncChannel != null) { - log("Received new connection while already connected!"); - break; - } - if (VDBG) log("NetworkFactory fully connected"); - AsyncChannel ac = new AsyncChannel(); - ac.connected(null, this, msg.replyTo); - ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); - mAsyncChannel = ac; - for (Message m : mPreConnectedQueue) { - ac.sendMessage(m); - } - mPreConnectedQueue.clear(); - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - if (VDBG) log("CMD_CHANNEL_DISCONNECT"); - if (mAsyncChannel != null) { - mAsyncChannel.disconnect(); - mAsyncChannel = null; - } - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { - if (DBG) log("NetworkFactory channel lost"); - mAsyncChannel = null; - break; - } case CMD_REQUEST_NETWORK: { handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); break; @@ -219,13 +207,13 @@ public class NetworkFactory extends Handler { public final NetworkRequest request; public int score; public boolean requested; // do we have a request outstanding, limited by score - public int factorySerialNumber; + public int providerId; - NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber) { + NetworkRequestInfo(NetworkRequest request, int score, int providerId) { this.request = request; this.score = score; this.requested = false; - this.factorySerialNumber = factorySerialNumber; + this.providerId = providerId; } @Override @@ -240,7 +228,7 @@ public class NetworkFactory extends Handler { * * @param request the request to handle. * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingFactorySerialNumber the serial number of the NetworkFactory that + * @param servingProviderId the serial number of the NetworkFactory that * created the NetworkAgent currently satisfying this request. */ // TODO : remove this method. It is a stopgap measure to help sheperding a number @@ -258,27 +246,27 @@ public class NetworkFactory extends Handler { * * @param request the request to handle. * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingFactorySerialNumber the serial number of the NetworkFactory that + * @param servingProviderId the serial number of the NetworkFactory that * created the NetworkAgent currently satisfying this request. */ @VisibleForTesting protected void handleAddRequest(NetworkRequest request, int score, - int servingFactorySerialNumber) { + int servingProviderId) { NetworkRequestInfo n = mNetworkRequests.get(request.requestId); if (n == null) { if (DBG) { log("got request " + request + " with score " + score - + " and serial " + servingFactorySerialNumber); + + " and serial " + servingProviderId); } - n = new NetworkRequestInfo(request, score, servingFactorySerialNumber); + n = new NetworkRequestInfo(request, score, servingProviderId); mNetworkRequests.put(n.request.requestId, n); } else { if (VDBG) { log("new score " + score + " for exisiting request " + request - + " with serial " + servingFactorySerialNumber); + + " with serial " + servingProviderId); } n.score = score; - n.factorySerialNumber = servingFactorySerialNumber; + n.providerId = servingProviderId; } if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); @@ -333,8 +321,8 @@ public class NetworkFactory extends Handler { log(" n.requests = " + n.requested); log(" n.score = " + n.score); log(" mScore = " + mScore); - log(" n.factorySerialNumber = " + n.factorySerialNumber); - log(" mSerialNumber = " + mSerialNumber); + log(" n.providerId = " + n.providerId); + log(" mProviderId = " + mProviderId); } if (shouldNeedNetworkFor(n)) { if (VDBG) log(" needNetworkFor"); @@ -355,7 +343,7 @@ public class NetworkFactory extends Handler { // If the score of this request is higher or equal to that of this factory and some // other factory is responsible for it, then this factory should not track the request // because it has no hope of satisfying it. - && (n.score < mScore || n.factorySerialNumber == mSerialNumber) + && (n.score < mScore || n.providerId == mProviderId) // If this factory can't satisfy the capability needs of this request, then it // should not be tracked. && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) @@ -373,7 +361,7 @@ public class NetworkFactory extends Handler { // assigned to the factory // - This factory can't satisfy the capability needs of the request // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.factorySerialNumber != mSerialNumber) + && ((n.score > mScore && n.providerId != mProviderId) || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( mCapabilityFilter) || !acceptRequest(n.request, n.score)); @@ -408,12 +396,7 @@ public class NetworkFactory extends Handler { protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { post(() -> { if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - Message msg = obtainMessage(EVENT_UNFULFILLABLE_REQUEST, r); - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(msg); - } else { - mPreConnectedQueue.add(msg); - } + ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r); }); } @@ -444,8 +427,13 @@ public class NetworkFactory extends Handler { return mNetworkRequests.size(); } + /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ public int getSerialNumber() { - return mSerialNumber; + return mProviderId; + } + + public int getProviderId() { + return mProviderId; } protected void log(String s) { @@ -465,8 +453,8 @@ public class NetworkFactory extends Handler { @Override public String toString() { - StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mSerialNumber=") - .append(mSerialNumber).append(", ScoreFilter=") + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=") + .append(mProviderId).append(", ScoreFilter=") .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) .append("}"); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 53854c23baac..de962f8f25e3 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -31,6 +31,7 @@ import android.net.wifi.WifiInfo; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; +import android.telephony.SubscriptionPlan; import android.util.DebugUtils; import android.util.Pair; import android.util.Range; @@ -380,7 +381,8 @@ public class NetworkPolicyManager { @Override public void onMeteredIfacesChanged(String[] meteredIfaces) { } @Override public void onRestrictBackgroundChanged(boolean restrictBackground) { } @Override public void onUidPoliciesChanged(int uid, int uidPolicies) { } - @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, - long networkTypeMask) { } + @Override public void onSubscriptionOverride(int subId, int overrideMask, + int overrideValue) { } + @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { } } } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 1130f1db6256..c94c74a4ce22 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -740,11 +740,12 @@ public class Process { /** * Set the priority of a thread, based on Linux priorities. - * - * @param tid The identifier of the thread/process to change. + * + * @param tid The identifier of the thread/process to change. It should be + * the native thread id but not the managed id of {@link java.lang.Thread}. * @param priority A Linux priority level, from -20 for highest scheduling * priority to 19 for lowest scheduling priority. - * + * * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. * @throws SecurityException Throws SecurityException if your process does diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 26222544ffb5..c7e714559d05 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -15268,8 +15268,9 @@ public final class Settings { * current time. * @hide */ - public static boolean checkAndNoteWriteSettingsOperation(Context context, int uid, - String callingPackage, boolean throwException) { + @SystemApi + public static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, boolean throwException) { return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, PM_WRITE_SETTINGS, true); diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java index ec2050fb1a44..28a5c2086ede 100644 --- a/core/java/android/telephony/SubscriptionPlan.java +++ b/core/java/android/telephony/SubscriptionPlan.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.util.Range; import android.util.RecurrenceRule; @@ -33,6 +34,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Period; import java.time.ZonedDateTime; +import java.util.Arrays; import java.util.Iterator; import java.util.Objects; @@ -42,6 +44,14 @@ import java.util.Objects; * as explaining how much mobile data they have remaining, and what will happen * when they run out. * + * If specifying network types, the developer must supply at least one plan + * that applies to all network types (default), and all additional plans + * may not include a particular network type more than once. + * This is enforced by {@link SubscriptionManager} when setting the plans. + * + * Plan selection will prefer plans that have specific network types defined + * over plans that apply to all network types. + * * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) * @see SubscriptionManager#getSubscriptionPlans(int) */ @@ -80,6 +90,8 @@ public final class SubscriptionPlan implements Parcelable { private int dataLimitBehavior = LIMIT_BEHAVIOR_UNKNOWN; private long dataUsageBytes = BYTES_UNKNOWN; private long dataUsageTime = TIME_UNKNOWN; + private @NetworkType int[] networkTypes; + private long networkTypesBitMask; private SubscriptionPlan(RecurrenceRule cycleRule) { this.cycleRule = Preconditions.checkNotNull(cycleRule); @@ -93,6 +105,7 @@ public final class SubscriptionPlan implements Parcelable { dataLimitBehavior = source.readInt(); dataUsageBytes = source.readLong(); dataUsageTime = source.readLong(); + networkTypes = source.createIntArray(); } @Override @@ -109,6 +122,7 @@ public final class SubscriptionPlan implements Parcelable { dest.writeInt(dataLimitBehavior); dest.writeLong(dataUsageBytes); dest.writeLong(dataUsageTime); + dest.writeIntArray(networkTypes); } @Override @@ -121,13 +135,14 @@ public final class SubscriptionPlan implements Parcelable { .append(" dataLimitBehavior=").append(dataLimitBehavior) .append(" dataUsageBytes=").append(dataUsageBytes) .append(" dataUsageTime=").append(dataUsageTime) + .append(" networkTypes=").append(Arrays.toString(networkTypes)) .append("}").toString(); } @Override public int hashCode() { return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior, - dataUsageBytes, dataUsageTime); + dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes)); } @Override @@ -140,7 +155,8 @@ public final class SubscriptionPlan implements Parcelable { && dataLimitBytes == other.dataLimitBytes && dataLimitBehavior == other.dataLimitBehavior && dataUsageBytes == other.dataUsageBytes - && dataUsageTime == other.dataUsageTime; + && dataUsageTime == other.dataUsageTime + && Arrays.equals(networkTypes, other.networkTypes); } return false; } @@ -204,6 +220,32 @@ public final class SubscriptionPlan implements Parcelable { } /** + * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to. + * A null value means this SubscriptionPlan applies to all network types. + */ + public @Nullable @NetworkType int[] getNetworkTypes() { + return networkTypes; + } + + /** + * Return the networkTypes array converted to a {@link TelephonyManager.NetworkTypeBitMask} + * @hide + */ + public long getNetworkTypesBitMask() { + // calculate bitmask the first time and save for future calls + if (networkTypesBitMask == 0) { + if (networkTypes == null) { + networkTypesBitMask = ~0; + } else { + for (int networkType : networkTypes) { + networkTypesBitMask |= TelephonyManager.getBitMaskForNetworkType(networkType); + } + } + } + return networkTypesBitMask; + } + + /** * Return an iterator that will return all valid data usage cycles based on * any recurrence rules. The iterator starts from the currently active cycle * and walks backwards through time. @@ -335,5 +377,17 @@ public final class SubscriptionPlan implements Parcelable { plan.dataUsageTime = dataUsageTime; return this; } + + /** + * Set the network types this SubscriptionPlan applies to. + * + * @param networkTypes a set of all {@link NetworkType}s that apply to this plan. + * A null value means the plan applies to all network types, + * and an empty array means the plan applies to no network types. + */ + public @NonNull Builder setNetworkTypes(@Nullable @NetworkType int[] networkTypes) { + plan.networkTypes = networkTypes; + return this; + } } } diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 507790313bc2..0dd7338a5e3e 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -387,6 +387,25 @@ public final class Log { public static native int println_native(int bufID, int priority, String tag, String msg); /** + * Send a log message to the "radio" log buffer, which can be dumped with + * {@code adb logcat -b radio}. + * + * <p>Only the telephony mainline module should use it. + * + * <p>Note ART will protect {@code MODULE_LIBRARIES} system APIs from regular app code. + * + * @param priority Log priority. + * @param tag Used to identify the source of a log message. It usually identifies + * the class or activity where the log call occurs. + * @param message The message you would like logged. + * @hide + */ + public static int logToRadioBuffer(@Level int priority, @Nullable String tag, + @Nullable String message) { + return println_native(LOG_ID_RADIO, priority, tag, message); + } + + /** * Return the maximum payload the log daemon accepts without truncation. * @return LOGGER_ENTRY_MAX_PAYLOAD. */ diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java new file mode 100644 index 000000000000..c7659457bdf9 --- /dev/null +++ b/core/java/android/util/StatsEvent.java @@ -0,0 +1,829 @@ +/* + * 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. + */ + +package android.util; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.SystemClock; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; + +/** + * StatsEvent builds and stores the buffer sent over the statsd socket. + * This class defines and encapsulates the socket protocol. + * + * <p>Usage:</p> + * <pre> + * // Pushed event + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeBoolean(false) + * .writeString("annotated String field") + * .addBooleanAnnotation(annotationId, true) + * .usePooledBuffer() + * .build(); + * StatsLog.write(statsEvent); + * + * // Pulled event + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeBoolean(false) + * .writeString("annotated String field") + * .addBooleanAnnotation(annotationId, true) + * .build(); + * </pre> + * @hide + **/ +public final class StatsEvent { + // Type Ids. + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_INT = 0x00; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_LONG = 0x01; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_STRING = 0x02; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_LIST = 0x03; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_FLOAT = 0x04; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_BOOLEAN = 0x05; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_BYTE_ARRAY = 0x06; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_OBJECT = 0x07; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_KEY_VALUE_PAIRS = 0x08; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_ATTRIBUTION_CHAIN = 0x09; + + /** + * @hide + **/ + @VisibleForTesting + public static final byte TYPE_ERRORS = 0x0F; + + // Error flags. + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_NO_TIMESTAMP = 0x1; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_NO_ATOM_ID = 0x2; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_OVERFLOW = 0x4; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ATTRIBUTION_CHAIN_TOO_LONG = 0x8; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_TOO_MANY_KEY_VALUE_PAIRS = 0x10; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD = 0x20; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_INVALID_ANNOTATION_ID = 0x40; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ANNOTATION_ID_TOO_LARGE = 0x80; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_TOO_MANY_ANNOTATIONS = 0x100; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_TOO_MANY_FIELDS = 0x200; + + /** + * @hide + **/ + @VisibleForTesting + public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x1000; + + // Size limits. + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_ANNOTATION_COUNT = 15; + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_ATTRIBUTION_NODES = 127; + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_NUM_ELEMENTS = 127; + + /** + * @hide + **/ + @VisibleForTesting + public static final int MAX_KEY_VALUE_PAIRS = 127; + + private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068; + + // Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag. + // See android_util_StatsLog.cpp. + private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4; + + private final int mAtomId; + private final byte[] mPayload; + private Buffer mBuffer; + private final int mNumBytes; + + private StatsEvent(final int atomId, @Nullable final Buffer buffer, + @NonNull final byte[] payload, final int numBytes) { + mAtomId = atomId; + mBuffer = buffer; + mPayload = payload; + mNumBytes = numBytes; + } + + /** + * Returns a new StatsEvent.Builder for building StatsEvent object. + **/ + @NonNull + public static StatsEvent.Builder newBuilder() { + return new StatsEvent.Builder(Buffer.obtain()); + } + + /** + * Get the atom Id of the atom encoded in this StatsEvent object. + * + * @hide + **/ + public int getAtomId() { + return mAtomId; + } + + /** + * Get the byte array that contains the encoded payload that can be sent to statsd. + * + * @hide + **/ + @NonNull + public byte[] getBytes() { + return mPayload; + } + + /** + * Get the number of bytes used to encode the StatsEvent payload. + * + * @hide + **/ + public int getNumBytes() { + return mNumBytes; + } + + /** + * Recycle resources used by this StatsEvent object. + * No actions should be taken on this StatsEvent after release() is called. + **/ + public void release() { + if (mBuffer != null) { + mBuffer.release(); + mBuffer = null; + } + } + + /** + * Builder for constructing a StatsEvent object. + * + * <p>This class defines and encapsulates the socket encoding for the buffer. + * The write methods must be called in the same order as the order of fields in the + * atom definition.</p> + * + * <p>setAtomId() can be called anytime before build().</p> + * + * <p>Example:</p> + * <pre> + * // Atom definition. + * message MyAtom { + * optional int32 field1 = 1; + * optional int64 field2 = 2; + * optional string field3 = 3 [(annotation1) = true]; + * } + * + * // StatsEvent construction for pushed event. + * StatsEvent.newBuilder() + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeInt(3) // field1 + * .writeLong(8L) // field2 + * .writeString("foo") // field 3 + * .addBooleanAnnotation(annotation1Id, true) + * .usePooledBuffer() + * .build(); + * + * // StatsEvent construction for pulled event. + * StatsEvent.newBuilder() + * StatsEvent statsEvent = StatsEvent.newBuilder() + * .setAtomId(atomId) + * .writeInt(3) // field1 + * .writeLong(8L) // field2 + * .writeString("foo") // field 3 + * .addBooleanAnnotation(annotation1Id, true) + * .build(); + * </pre> + **/ + public static final class Builder { + // Fixed positions. + private static final int POS_NUM_ELEMENTS = 1; + private static final int POS_TIMESTAMP_NS = POS_NUM_ELEMENTS + Byte.BYTES; + private static final int POS_ATOM_ID = POS_TIMESTAMP_NS + Byte.BYTES + Long.BYTES; + + private final Buffer mBuffer; + private long mTimestampNs; + private int mAtomId; + private byte mCurrentAnnotationCount; + private int mPos; + private int mPosLastField; + private byte mLastType; + private int mNumElements; + private int mErrorMask; + private boolean mUsePooledBuffer = false; + + private Builder(final Buffer buffer) { + mBuffer = buffer; + mCurrentAnnotationCount = 0; + mAtomId = 0; + mTimestampNs = SystemClock.elapsedRealtimeNanos(); + mNumElements = 0; + + // Set mPos to 0 for writing TYPE_OBJECT at 0th position. + mPos = 0; + writeTypeId(TYPE_OBJECT); + + // Set mPos to after atom id's location in the buffer. + // First 2 elements in the buffer are event timestamp followed by the atom id. + mPos = POS_ATOM_ID + Byte.BYTES + Integer.BYTES; + mPosLastField = 0; + mLastType = 0; + } + + /** + * Sets the atom id for this StatsEvent. + **/ + @NonNull + public Builder setAtomId(final int atomId) { + mAtomId = atomId; + return this; + } + + /** + * Sets the timestamp in nanos for this StatsEvent. + **/ + @VisibleForTesting + @NonNull + public Builder setTimestampNs(final long timestampNs) { + mTimestampNs = timestampNs; + return this; + } + + /** + * Write a boolean field to this StatsEvent. + **/ + @NonNull + public Builder writeBoolean(final boolean value) { + // Write boolean typeId byte followed by boolean byte representation. + writeTypeId(TYPE_BOOLEAN); + mPos += mBuffer.putBoolean(mPos, value); + mNumElements++; + return this; + } + + /** + * Write an integer field to this StatsEvent. + **/ + @NonNull + public Builder writeInt(final int value) { + // Write integer typeId byte followed by 4-byte representation of value. + writeTypeId(TYPE_INT); + mPos += mBuffer.putInt(mPos, value); + mNumElements++; + return this; + } + + /** + * Write a long field to this StatsEvent. + **/ + @NonNull + public Builder writeLong(final long value) { + // Write long typeId byte followed by 8-byte representation of value. + writeTypeId(TYPE_LONG); + mPos += mBuffer.putLong(mPos, value); + mNumElements++; + return this; + } + + /** + * Write a float field to this StatsEvent. + **/ + @NonNull + public Builder writeFloat(final float value) { + // Write float typeId byte followed by 4-byte representation of value. + writeTypeId(TYPE_FLOAT); + mPos += mBuffer.putFloat(mPos, value); + mNumElements++; + return this; + } + + /** + * Write a String field to this StatsEvent. + **/ + @NonNull + public Builder writeString(@NonNull final String value) { + // Write String typeId byte, followed by 4-byte representation of number of bytes + // in the UTF-8 encoding, followed by the actual UTF-8 byte encoding of value. + final byte[] valueBytes = stringToBytes(value); + writeByteArray(valueBytes, TYPE_STRING); + return this; + } + + /** + * Write a byte array field to this StatsEvent. + **/ + @NonNull + public Builder writeByteArray(@NonNull final byte[] value) { + // Write byte array typeId byte, followed by 4-byte representation of number of bytes + // in value, followed by the actual byte array. + writeByteArray(value, TYPE_BYTE_ARRAY); + return this; + } + + private void writeByteArray(@NonNull final byte[] value, final byte typeId) { + writeTypeId(typeId); + final int numBytes = value.length; + mPos += mBuffer.putInt(mPos, numBytes); + mPos += mBuffer.putByteArray(mPos, value); + mNumElements++; + } + + /** + * Write an attribution chain field to this StatsEvent. + * + * The sizes of uids and tags must be equal. The AttributionNode at position i is + * made up of uids[i] and tags[i]. + * + * @param uids array of uids in the attribution nodes. + * @param tags array of tags in the attribution nodes. + **/ + @NonNull + public Builder writeAttributionChain( + @NonNull final int[] uids, @NonNull final String[] tags) { + final byte numUids = (byte) uids.length; + final byte numTags = (byte) tags.length; + + if (numUids != numTags) { + mErrorMask |= ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL; + } else if (numUids > MAX_ATTRIBUTION_NODES) { + mErrorMask |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG; + } else { + // Write attribution chain typeId byte, followed by 1-byte representation of + // number of attribution nodes, followed by encoding of each attribution node. + writeTypeId(TYPE_ATTRIBUTION_CHAIN); + mPos += mBuffer.putByte(mPos, numUids); + for (int i = 0; i < numUids; i++) { + // Each uid is encoded as 4-byte representation of its int value. + mPos += mBuffer.putInt(mPos, uids[i]); + + // Each tag is encoded as 4-byte representation of number of bytes in its + // UTF-8 encoding, followed by the actual UTF-8 bytes. + final byte[] tagBytes = stringToBytes(tags[i]); + mPos += mBuffer.putInt(mPos, tagBytes.length); + mPos += mBuffer.putByteArray(mPos, tagBytes); + } + mNumElements++; + } + return this; + } + + /** + * Write KeyValuePairsAtom entries to this StatsEvent. + * + * @param intMap Integer key-value pairs. + * @param longMap Long key-value pairs. + * @param stringMap String key-value pairs. + * @param floatMap Float key-value pairs. + **/ + @NonNull + public Builder writeKeyValuePairs( + @NonNull final SparseIntArray intMap, + @NonNull final SparseLongArray longMap, + @NonNull final SparseArray<String> stringMap, + @NonNull final SparseArray<Float> floatMap) { + final int intMapSize = intMap.size(); + final int longMapSize = longMap.size(); + final int stringMapSize = stringMap.size(); + final int floatMapSize = floatMap.size(); + final int totalCount = intMapSize + longMapSize + stringMapSize + floatMapSize; + + if (totalCount > MAX_KEY_VALUE_PAIRS) { + mErrorMask |= ERROR_TOO_MANY_KEY_VALUE_PAIRS; + } else { + writeTypeId(TYPE_KEY_VALUE_PAIRS); + mPos += mBuffer.putByte(mPos, (byte) totalCount); + + for (int i = 0; i < intMapSize; i++) { + final int key = intMap.keyAt(i); + final int value = intMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_INT); + mPos += mBuffer.putInt(mPos, value); + } + + for (int i = 0; i < longMapSize; i++) { + final int key = longMap.keyAt(i); + final long value = longMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_LONG); + mPos += mBuffer.putLong(mPos, value); + } + + for (int i = 0; i < stringMapSize; i++) { + final int key = stringMap.keyAt(i); + final String value = stringMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_STRING); + final byte[] valueBytes = stringToBytes(value); + mPos += mBuffer.putInt(mPos, valueBytes.length); + mPos += mBuffer.putByteArray(mPos, valueBytes); + } + + for (int i = 0; i < floatMapSize; i++) { + final int key = floatMap.keyAt(i); + final float value = floatMap.valueAt(i); + mPos += mBuffer.putInt(mPos, key); + writeTypeId(TYPE_FLOAT); + mPos += mBuffer.putFloat(mPos, value); + } + + mNumElements++; + } + + return this; + } + + /** + * Write a boolean annotation for the last field written. + **/ + @NonNull + public Builder addBooleanAnnotation( + final byte annotationId, final boolean value) { + // Ensure there's a field written to annotate. + if (0 == mPosLastField) { + mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD; + } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) { + mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS; + } else { + mPos += mBuffer.putByte(mPos, annotationId); + mPos += mBuffer.putByte(mPos, TYPE_BOOLEAN); + mPos += mBuffer.putBoolean(mPos, value); + mCurrentAnnotationCount++; + writeAnnotationCount(); + } + return this; + } + + /** + * Write an integer annotation for the last field written. + **/ + @NonNull + public Builder addIntAnnotation(final byte annotationId, final int value) { + if (0 == mPosLastField) { + mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD; + } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) { + mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS; + } else { + mPos += mBuffer.putByte(mPos, annotationId); + mPos += mBuffer.putByte(mPos, TYPE_INT); + mPos += mBuffer.putInt(mPos, value); + mCurrentAnnotationCount++; + writeAnnotationCount(); + } + return this; + } + + /** + * Indicates to reuse Buffer's byte array as the underlying payload in StatsEvent. + * This should be called for pushed events to reduce memory allocations and garbage + * collections. + **/ + @NonNull + public Builder usePooledBuffer() { + mUsePooledBuffer = true; + return this; + } + + /** + * Builds a StatsEvent object with values entered in this Builder. + **/ + @NonNull + public StatsEvent build() { + if (0L == mTimestampNs) { + mErrorMask |= ERROR_NO_TIMESTAMP; + } + if (0 == mAtomId) { + mErrorMask |= ERROR_NO_ATOM_ID; + } + if (mBuffer.hasOverflowed()) { + mErrorMask |= ERROR_OVERFLOW; + } + if (mNumElements > MAX_NUM_ELEMENTS) { + mErrorMask |= ERROR_TOO_MANY_FIELDS; + } + + int size = mPos; + mPos = POS_TIMESTAMP_NS; + writeLong(mTimestampNs); + writeInt(mAtomId); + if (0 == mErrorMask) { + mBuffer.putByte(POS_NUM_ELEMENTS, (byte) mNumElements); + } else { + mPos += mBuffer.putByte(mPos, TYPE_ERRORS); + mPos += mBuffer.putInt(mPos, mErrorMask); + mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3); + size = mPos; + } + + if (mUsePooledBuffer) { + return new StatsEvent(mAtomId, mBuffer, mBuffer.getBytes(), size); + } else { + // Create a copy of the buffer with the required number of bytes. + final byte[] payload = new byte[size]; + System.arraycopy(mBuffer.getBytes(), 0, payload, 0, size); + + // Return Buffer instance to the pool. + mBuffer.release(); + + return new StatsEvent(mAtomId, null, payload, size); + } + } + + private void writeTypeId(final byte typeId) { + mPosLastField = mPos; + mLastType = typeId; + mCurrentAnnotationCount = 0; + final byte encodedId = (byte) (typeId & 0x0F); + mPos += mBuffer.putByte(mPos, encodedId); + } + + private void writeAnnotationCount() { + // Use first 4 bits for annotation count and last 4 bits for typeId. + final byte encodedId = (byte) ((mCurrentAnnotationCount << 4) | (mLastType & 0x0F)); + mBuffer.putByte(mPosLastField, encodedId); + } + + @NonNull + private static byte[] stringToBytes(@Nullable final String value) { + return (null == value ? "" : value).getBytes(UTF_8); + } + } + + private static final class Buffer { + private static Object sLock = new Object(); + + @GuardedBy("sLock") + private static Buffer sPool; + + private final byte[] mBytes = new byte[MAX_PAYLOAD_SIZE]; + private boolean mOverflow = false; + + @NonNull + private static Buffer obtain() { + final Buffer buffer; + synchronized (sLock) { + buffer = null == sPool ? new Buffer() : sPool; + sPool = null; + } + buffer.reset(); + return buffer; + } + + private Buffer() { + } + + @NonNull + private byte[] getBytes() { + return mBytes; + } + + private void release() { + synchronized (sLock) { + if (null == sPool) { + sPool = this; + } + } + } + + private void reset() { + mOverflow = false; + } + + private boolean hasOverflowed() { + return mOverflow; + } + + /** + * Checks for available space in the byte array. + * + * @param index starting position in the buffer to start the check. + * @param numBytes number of bytes to check from index. + * @return true if space is available, false otherwise. + **/ + private boolean hasEnoughSpace(final int index, final int numBytes) { + final boolean result = index + numBytes < MAX_PAYLOAD_SIZE; + if (!result) { + mOverflow = true; + } + return result; + } + + /** + * Writes a byte into the buffer. + * + * @param index position in the buffer where the byte is written. + * @param value the byte to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putByte(final int index, final byte value) { + if (hasEnoughSpace(index, Byte.BYTES)) { + mBytes[index] = (byte) (value); + return Byte.BYTES; + } + return 0; + } + + /** + * Writes a boolean into the buffer. + * + * @param index position in the buffer where the boolean is written. + * @param value the boolean to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putBoolean(final int index, final boolean value) { + return putByte(index, (byte) (value ? 1 : 0)); + } + + /** + * Writes an integer into the buffer. + * + * @param index position in the buffer where the integer is written. + * @param value the integer to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putInt(final int index, final int value) { + if (hasEnoughSpace(index, Integer.BYTES)) { + // Use little endian byte order. + mBytes[index] = (byte) (value); + mBytes[index + 1] = (byte) (value >> 8); + mBytes[index + 2] = (byte) (value >> 16); + mBytes[index + 3] = (byte) (value >> 24); + return Integer.BYTES; + } + return 0; + } + + /** + * Writes a long into the buffer. + * + * @param index position in the buffer where the long is written. + * @param value the long to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putLong(final int index, final long value) { + if (hasEnoughSpace(index, Long.BYTES)) { + // Use little endian byte order. + mBytes[index] = (byte) (value); + mBytes[index + 1] = (byte) (value >> 8); + mBytes[index + 2] = (byte) (value >> 16); + mBytes[index + 3] = (byte) (value >> 24); + mBytes[index + 4] = (byte) (value >> 32); + mBytes[index + 5] = (byte) (value >> 40); + mBytes[index + 6] = (byte) (value >> 48); + mBytes[index + 7] = (byte) (value >> 56); + return Long.BYTES; + } + return 0; + } + + /** + * Writes a float into the buffer. + * + * @param index position in the buffer where the float is written. + * @param value the float to write. + * @return number of bytes written to buffer from this write operation. + **/ + private int putFloat(final int index, final float value) { + return putInt(index, Float.floatToIntBits(value)); + } + + /** + * Copies a byte array into the buffer. + * + * @param index position in the buffer where the byte array is copied. + * @param value the byte array to copy. + * @return number of bytes written to buffer from this write operation. + **/ + private int putByteArray(final int index, @NonNull final byte[] value) { + final int numBytes = value.length; + if (hasEnoughSpace(index, numBytes)) { + System.arraycopy(value, 0, mBytes, index, numBytes); + return numBytes; + } + return 0; + } + } +} diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index ae9966b7b934..23fd4f2f61d3 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -244,6 +244,19 @@ public final class StatsLog extends StatsLogInternal { */ private static native void writeImpl(@NonNull byte[] buffer, int size, int atomId); + /** + * Write an event to stats log using the raw format encapsulated in StatsEvent. + * After writing to stats log, release() is called on the StatsEvent object. + * No further action should be taken on the StatsEvent object following this call. + * + * @param statsEvent The StatsEvent object containing the encoded buffer of data to write. + * @hide + */ + public static void write(@NonNull final StatsEvent statsEvent) { + writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId()); + statsEvent.release(); + } + private static void enforceDumpCallingPermission(Context context) { context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission."); } diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 28eb79ae1f2a..5b4ff52376b3 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -16,12 +16,11 @@ package android.view; -import static android.view.DisplayEventReceiver.CONFIG_CHANGED_EVENT_SUPPRESS; import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP; import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.FrameInfo; import android.hardware.display.DisplayManagerGlobal; import android.os.Build; diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java index 696e048ffed8..876331b5c57f 100644 --- a/core/java/android/view/ContextThemeWrapper.java +++ b/core/java/android/view/ContextThemeWrapper.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.ContextWrapper; import android.content.res.AssetManager; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index b3d98b8de0a3..7a818ce78568 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -22,8 +22,8 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java index da4d92fa0c94..834dd7b6e7d8 100644 --- a/core/java/android/view/DisplayAdjustments.java +++ b/core/java/android/view/DisplayAdjustments.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 91acc4638c26..eaf297cc05d8 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 2efebf6457ab..f3b2800eef39 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -23,7 +23,7 @@ import static android.view.DisplayInfoProto.LOGICAL_WIDTH; import static android.view.DisplayInfoProto.NAME; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Rect; diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index 8e6e99a6d949..6035cbebb032 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.BaseRecordingCanvas; import android.graphics.CanvasProperty; import android.graphics.Paint; diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java index 2a43bcc00daf..35af0f252d2d 100644 --- a/core/java/android/view/DragEvent.java +++ b/core/java/android/view/DragEvent.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; import android.os.Parcel; diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java index dcdef3eaa275..de4112cbf1e1 100644 --- a/core/java/android/view/FrameMetrics.java +++ b/core/java/android/view/FrameMetrics.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java index 0f38e847f4bd..e4197abf8088 100644 --- a/core/java/android/view/FrameMetricsObserver.java +++ b/core/java/android/view/FrameMetricsObserver.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index 8fbbcf4b88c6..0fdbc9cf9e33 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -23,7 +23,7 @@ import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SC import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java index 3286bd623694..a72832760f96 100644 --- a/core/java/android/view/GhostView.java +++ b/core/java/android/view/GhostView.java @@ -15,7 +15,7 @@ */ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.RecordingCanvas; diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java index ecb727c79016..67c8b15b2ca5 100644 --- a/core/java/android/view/InputChannel.java +++ b/core/java/android/view/InputChannel.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index e723f91887c1..360deddf544d 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.RequiresPermission; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java index 4b88a6a54efe..5f9c4801ee66 100644 --- a/core/java/android/view/InputEvent.java +++ b/core/java/android/view/InputEvent.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java index e4b1a8d855ec..c0a3cec4547a 100644 --- a/core/java/android/view/InputEventConsistencyVerifier.java +++ b/core/java/android/view/InputEventConsistencyVerifier.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.Log; diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 7260a658a027..cab8bc549af6 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java index c5f4c23b7b15..86a309e3ed79 100644 --- a/core/java/android/view/InputEventSender.java +++ b/core/java/android/view/InputEventSender.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.Log; diff --git a/core/java/android/view/InputFilter.java b/core/java/android/view/InputFilter.java index 3aaf31ef406f..36d558630da9 100644 --- a/core/java/android/view/InputFilter.java +++ b/core/java/android/view/InputFilter.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java index 69ebc46cb456..74ce6ac02db3 100644 --- a/core/java/android/view/InputQueue.java +++ b/core/java/android/view/InputQueue.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Looper; import android.os.MessageQueue; import android.util.LongSparseArray; diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index bd033480ea87..90e0f3f89a0f 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.input.InputManager; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 60db6a57d187..c638717b13c0 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -20,7 +20,7 @@ import static android.view.Display.INVALID_DISPLAY; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 1fc7f0e36095..bf646c7cddb6 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Resources; @@ -31,10 +31,7 @@ import android.graphics.Canvas; import android.os.Build; import android.os.Handler; import android.os.Message; -import android.os.SystemProperties; import android.os.Trace; -import android.provider.DeviceConfig; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 833e78ff5c71..70873d7db92a 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -22,7 +22,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Matrix; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index b2f3f5edcd20..232e0f6f9a14 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -17,9 +17,9 @@ package android.view; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.AppOpsManager; import android.app.Notification; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index dfe34c80bb8f..18d0d7b98a42 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -17,8 +17,8 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index c686440171a2..166d3baa2fdf 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -16,8 +16,8 @@ package android.view; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityOptions; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index da599efb6eee..c9bd92ae84ba 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -19,9 +19,9 @@ package android.view; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; import android.app.WindowConfiguration.ActivityType; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java index ae3e1d0a9691..2249966a6b2d 100644 --- a/core/java/android/view/RemoteAnimationTarget.java +++ b/core/java/android/view/RemoteAnimationTarget.java @@ -30,8 +30,8 @@ import static android.view.RemoteAnimationTargetProto.TASK_ID; import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Point; import android.graphics.Rect; import android.os.Parcel; diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index 93f52a04d626..06cb51927ba8 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -19,7 +19,7 @@ package android.view; import android.animation.Animator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.CanvasProperty; import android.graphics.Paint; import android.graphics.RecordingCanvas; diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 1d721516a979..346f76cace7d 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 17f07b5a2ad4..3a6c8dd3720f 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo.Translator; import android.graphics.Canvas; import android.graphics.ColorSpace; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 2313b13befad..2c48af04aa18 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -32,7 +32,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java index 361ac932758e..0f851c1881f5 100644 --- a/core/java/android/view/SurfaceSession.java +++ b/core/java/android/view/SurfaceSession.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An instance of this class represents a connection to the surface diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index d11548d687b1..ec2ab6a5a4be 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -20,7 +20,7 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_OVERLA import static android.view.WindowManagerPolicyConstants.APPLICATION_MEDIA_SUBLAYER; import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAYER; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.CompatibilityInfo.Translator; import android.graphics.BlendMode; diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 0175ba201dd1..2062bb0bc87f 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java index 2ea95e90a8bf..de0f9e5c5cf6 100644 --- a/core/java/android/view/TouchDelegate.java +++ b/core/java/android/view/TouchDelegate.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.graphics.Region; import android.util.ArrayMap; diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 7154f2bdee42..a56633e3c5fa 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Pools.SynchronizedPool; /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 9d2040c5bdb4..3313537965c4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -43,7 +43,7 @@ import android.annotation.Size; import android.annotation.StyleRes; import android.annotation.TestApi; import android.annotation.UiThread; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.AutofillOptions; import android.content.ClipData; import android.content.Context; diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 9e914d4e7d41..774a2dea6311 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -18,8 +18,8 @@ package android.view; import android.annotation.FloatRange; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index c67fca59fe97..dda7b260533e 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -19,7 +19,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 937bd1b34e61..6125aadc57b6 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -24,7 +24,7 @@ import android.annotation.IdRes; import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.UiThread; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/view/ViewHierarchyEncoder.java b/core/java/android/view/ViewHierarchyEncoder.java index d5716bfaaf00..b0e0524a0d85 100644 --- a/core/java/android/view/ViewHierarchyEncoder.java +++ b/core/java/android/view/ViewHierarchyEncoder.java @@ -2,7 +2,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java index e23c687af49b..7830c57e53ec 100644 --- a/core/java/android/view/ViewOverlay.java +++ b/core/java/android/view/ViewOverlay.java @@ -17,7 +17,7 @@ package android.view; import android.animation.LayoutTransition; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 57a01a32e1b8..1ab3d3ab4974 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -32,10 +32,10 @@ import android.animation.LayoutTransition; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index c72baca0b93b..d7b0afc89eaa 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -18,7 +18,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.graphics.Region; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 73e0e4b2eb8b..cdafa470a542 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -26,8 +26,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.WindowConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; diff --git a/core/java/android/view/WindowAnimationFrameStats.java b/core/java/android/view/WindowAnimationFrameStats.java index 399dfba64461..dfc4f0cd4dc6 100644 --- a/core/java/android/view/WindowAnimationFrameStats.java +++ b/core/java/android/view/WindowAnimationFrameStats.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/WindowContentFrameStats.java b/core/java/android/view/WindowContentFrameStats.java index 9fa5a005055d..217197c96793 100644 --- a/core/java/android/view/WindowContentFrameStats.java +++ b/core/java/android/view/WindowContentFrameStats.java @@ -16,7 +16,7 @@ package android.view; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index bcc6a552f569..87bc534da92f 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -34,7 +34,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.graphics.Insets; import android.graphics.Rect; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 7433b6c8ce87..d9d92788a434 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -50,9 +50,9 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; import android.app.Presentation; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 379acbecb613..a930abe40341 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -18,8 +18,8 @@ package android.view; import android.animation.ValueAnimator; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index c3494432ebcb..cdeeaa438acb 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -17,7 +17,7 @@ package android.view; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Region; import android.os.Bundle; diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 2ac44d2fac22..2ba9f94869e4 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -17,7 +17,7 @@ package android.view.accessibility; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 4db6f4f808f2..723da77b6f7d 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -17,7 +17,7 @@ package android.view.accessibility; import android.accessibilityservice.IAccessibilityServiceConnection; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; import android.os.Bundle; diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 2e9d881f72f9..747bd706f316 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -29,7 +29,7 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 3b310fc13ee3..8e61a5e7c44b 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -26,7 +26,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.graphics.Region; import android.os.Bundle; diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index b382a1863af3..37c3a1361de1 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -19,7 +19,7 @@ package android.view.accessibility; import static com.android.internal.util.CollectionUtils.isEmpty; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcelable; import android.view.View; diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java index c42e9fec91bf..3d68692a3b5c 100644 --- a/core/java/android/view/accessibility/CaptioningManager.java +++ b/core/java/android/view/accessibility/CaptioningManager.java @@ -19,7 +19,7 @@ package android.view.accessibility; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java index 3b60aee8f604..43dcafc9b9ce 100644 --- a/core/java/android/view/animation/Animation.java +++ b/core/java/android/view/animation/Animation.java @@ -19,7 +19,7 @@ package android.view.animation; import android.annotation.AnimRes; import android.annotation.ColorInt; import android.annotation.InterpolatorRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.RectF; diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index c877b9cec812..075b0ab728fa 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -19,7 +19,7 @@ package android.view.animation; import android.annotation.AnimRes; import android.annotation.InterpolatorRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java index 58da04d8d38f..cfc6e39da876 100644 --- a/core/java/android/view/animation/Transformation.java +++ b/core/java/android/view/animation/Transformation.java @@ -17,7 +17,7 @@ package android.view.animation; import android.annotation.FloatRange; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Matrix; import android.graphics.Rect; diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java index 6c040d4c61aa..ec55a0273999 100644 --- a/core/java/android/view/animation/TranslateAnimation.java +++ b/core/java/android/view/animation/TranslateAnimation.java @@ -16,7 +16,7 @@ package android.view.animation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; diff --git a/core/java/android/view/animation/TranslateYAnimation.java b/core/java/android/view/animation/TranslateYAnimation.java index a6e0ccb18805..1a1dfbfd6f05 100644 --- a/core/java/android/view/animation/TranslateYAnimation.java +++ b/core/java/android/view/animation/TranslateYAnimation.java @@ -16,7 +16,7 @@ package android.view.animation; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Matrix; /** diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index fe07feef3bfa..34005ac02735 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -17,7 +17,7 @@ package android.view.inputmethod; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 032af1c5c7b5..d395f5294d6c 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -26,9 +26,9 @@ import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -2830,7 +2830,7 @@ public final class InputMethodManager { } /** - * This is kept due to {@link android.annotation.UnsupportedAppUsage}. + * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage}. * * <p>TODO(Bug 113914148): Check if we can remove this. We have accidentally exposed * WindowManagerInternal#getInputMethodWindowVisibleHeight to app developers and some of them diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java index 8dd0dcd45a1c..50e95c80cfed 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java +++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java @@ -16,7 +16,7 @@ package android.view.inputmethod; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.util.Slog; diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java index 95ca9deb2871..526ac6fd3570 100644 --- a/core/java/android/view/textclassifier/TextClassificationManager.java +++ b/core/java/android/view/textclassifier/TextClassificationManager.java @@ -19,8 +19,8 @@ package android.view.textclassifier; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.ContentObserver; import android.os.ServiceManager; diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java index b530ddfe86d6..05d12ce17d8c 100644 --- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java +++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java @@ -19,7 +19,7 @@ package android.view.textclassifier.logging; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.metrics.LogMaker; import android.util.Log; diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index f553ca512881..afddaa2ff58a 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -16,7 +16,7 @@ package android.view.textservice; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 9ff64d9b268a..acb35d63df9d 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -18,8 +18,8 @@ package android.view.textservice; import android.annotation.NonNull; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index 7e067197ced8..fafe81393888 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.File; import java.io.IOException; diff --git a/core/java/android/webkit/ConsoleMessage.java b/core/java/android/webkit/ConsoleMessage.java index e54849772f9a..5474557c9998 100644 --- a/core/java/android/webkit/ConsoleMessage.java +++ b/core/java/android/webkit/ConsoleMessage.java @@ -16,7 +16,7 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java index 5bf6aab3225d..448db58e2658 100644 --- a/core/java/android/webkit/JsResult.java +++ b/core/java/android/webkit/JsResult.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An instance of this class is passed as a parameter in various {@link WebChromeClient} action diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java index 8aeeb1c53241..c9a196017a75 100644 --- a/core/java/android/webkit/PluginData.java +++ b/core/java/android/webkit/PluginData.java @@ -16,7 +16,8 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.InputStream; import java.util.Map; diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index 5d704cb09dcb..844b156b84d3 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.ParseException; import android.net.Uri; import android.net.WebAddress; diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java index f23aae6be8c2..a48e10799be7 100644 --- a/core/java/android/webkit/UrlInterceptHandler.java +++ b/core/java/android/webkit/UrlInterceptHandler.java @@ -17,9 +17,8 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.webkit.CacheManager.CacheResult; -import android.webkit.PluginData; import java.util.Map; diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java index eeb28d73be85..c9dee00942c3 100644 --- a/core/java/android/webkit/UrlInterceptRegistry.java +++ b/core/java/android/webkit/UrlInterceptRegistry.java @@ -17,10 +17,8 @@ package android.webkit; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.webkit.CacheManager.CacheResult; -import android.webkit.PluginData; -import android.webkit.UrlInterceptHandler; import java.util.Iterator; import java.util.LinkedList; diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java index 7c8f33e181d6..219523b15ab0 100644 --- a/core/java/android/webkit/WebResourceResponse.java +++ b/core/java/android/webkit/WebResourceResponse.java @@ -18,7 +18,7 @@ package android.webkit; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.InputStream; import java.io.StringBufferInputStream; diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 7282008f7e3a..8a5b64d95f19 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -19,7 +19,7 @@ package android.webkit; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import java.lang.annotation.ElementType; diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java index e44d6ebf37d1..7046c5108783 100644 --- a/core/java/android/webkit/WebSyncManager.java +++ b/core/java/android/webkit/WebSyncManager.java @@ -16,7 +16,7 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 721ac2d9a6dc..271d5be3864e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -21,8 +21,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index f5657dff538f..df86926a95dc 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -19,10 +19,10 @@ package android.webkit; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; import android.app.ResourcesManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Resources; diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 678a25223ef5..941af6ef1d7a 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -17,10 +17,10 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.Application; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java index 7e00cded2c5a..6629fdc4cdee 100644 --- a/core/java/android/webkit/WebViewProviderInfo.java +++ b/core/java/android/webkit/WebViewProviderInfo.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.Signature; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/webkit/WebViewProviderResponse.java b/core/java/android/webkit/WebViewProviderResponse.java index 5622abe0e99f..b58cc4bb1577 100644 --- a/core/java/android/webkit/WebViewProviderResponse.java +++ b/core/java/android/webkit/WebViewProviderResponse.java @@ -16,7 +16,7 @@ package android.webkit; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.PackageInfo; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java index 12d3221fb7b5..9152b438618f 100644 --- a/core/java/android/webkit/WebViewUpdateService.java +++ b/core/java/android/webkit/WebViewUpdateService.java @@ -17,7 +17,7 @@ package android.webkit; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.RemoteException; /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 85e9e4950cba..2d99eab88dfc 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index bbcba2e12a2c..11a6acf5b934 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java index cfb93ec2321f..aa3590aaff0a 100644 --- a/core/java/android/widget/ActionMenuPresenter.java +++ b/core/java/android/widget/ActionMenuPresenter.java @@ -22,7 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index 7e58622db3b8..3a743562110f 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index f5bf7598aa5a..d87bdf482e43 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -16,8 +16,8 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java index 89ea0747b532..aa18d576c8f4 100644 --- a/core/java/android/widget/ActivityChooserView.java +++ b/core/java/android/widget/ActivityChooserView.java @@ -17,7 +17,7 @@ package android.widget; import android.annotation.StringRes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index c55f7d654548..52658404548c 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.DataSetObserver; import android.os.Build; diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index 67a70b48b534..d165bd0f0fa7 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -16,7 +16,7 @@ package android.widget; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 2bf1ba5cf017..6c38c8b9a0f5 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -21,7 +21,7 @@ import android.annotation.IdRes; import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.util.Log; diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 8785251b0a64..8d9ae58be290 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -18,7 +18,7 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/core/java/android/widget/BaseAdapter.java b/core/java/android/widget/BaseAdapter.java index 7b9365b08a41..27cf9a64a8d5 100644 --- a/core/java/android/widget/BaseAdapter.java +++ b/core/java/android/widget/BaseAdapter.java @@ -17,7 +17,7 @@ package android.widget; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.DataSetObservable; import android.database.DataSetObserver; import android.view.View; diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index b552aa6c85c4..4b2f738ef7ab 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.annotation.Widget; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index 8b70f41f050c..422d2d37321c 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -19,7 +19,7 @@ package android.widget; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java index 3fff5c233890..994a01c023d8 100644 --- a/core/java/com/android/internal/util/Preconditions.java +++ b/core/java/com/android/internal/util/Preconditions.java @@ -126,7 +126,9 @@ public class Preconditions { * @param reference an object reference * @return the non-null reference that was validated * @throws NullPointerException if {@code reference} is null + * @deprecated - use {@link java.util.Objects.requireNonNull} instead. */ + @Deprecated @UnsupportedAppUsage public static @NonNull <T> T checkNotNull(final T reference) { if (reference == null) { @@ -144,7 +146,9 @@ public class Preconditions { * be converted to a string using {@link String#valueOf(Object)} * @return the non-null reference that was validated * @throws NullPointerException if {@code reference} is null + * @deprecated - use {@link java.util.Objects.requireNonNull} instead. */ + @Deprecated @UnsupportedAppUsage public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) { if (reference == null) { @@ -154,26 +158,6 @@ public class Preconditions { } /** - * Ensures that an object reference passed as a parameter to the calling - * method is not null. - * - * @param reference an object reference - * @param messageTemplate a printf-style message template to use if the check fails; will - * be converted to a string using {@link String#format(String, Object...)} - * @param messageArgs arguments for {@code messageTemplate} - * @return the non-null reference that was validated - * @throws NullPointerException if {@code reference} is null - */ - public static @NonNull <T> T checkNotNull(final T reference, - final String messageTemplate, - final Object... messageArgs) { - if (reference == null) { - throw new NullPointerException(String.format(messageTemplate, messageArgs)); - } - return reference; - } - - /** * Ensures the truth of an expression involving the state of the calling * instance, but not involving any parameters to the calling method. * diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a42ba17c100e..e54215edaaf0 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2057,8 +2057,10 @@ android:protectionLevel="signature|privileged" /> <!-- Allows read only access to precise phone state. - @hide Pending API council approval --> + Allows reading of detailed information about phone state for special-use applications + such as dialers, carrier applications, or ims applications. --> <permission android:name="android.permission.READ_PRECISE_PHONE_STATE" + android:permissionGroup="android.permission-group.UNDEFINED" android:protectionLevel="signature|privileged" /> <!-- @SystemApi Allows read access to privileged phone state. diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java index 68b9b0079761..f4709ff0bc00 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java @@ -33,14 +33,15 @@ import android.os.ParcelFileDescriptor.AutoCloseInputStream; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.support.test.uiautomator.UiDevice; import android.test.InstrumentationTestCase; import android.util.Log; -import libcore.io.Streams; - import com.google.mockwebserver.MockResponse; import com.google.mockwebserver.MockWebServer; +import libcore.io.Streams; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -63,6 +64,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { private static final String TAG = "DownloadManagerBaseTest"; protected DownloadManager mDownloadManager = null; private MockWebServer mServer = null; + private UiDevice mUiDevice = null; protected String mFileType = "text/plain"; protected Context mContext = null; protected MultipleDownloadsCompletedReceiver mReceiver = null; @@ -234,6 +236,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { @Override public void setUp() throws Exception { mContext = getInstrumentation().getContext(); + mUiDevice = UiDevice.getInstance(getInstrumentation()); mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE); mServer = new MockWebServer(); mServer.play(); @@ -512,7 +515,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { Log.i(LOG_TAG, "Setting WiFi State to: " + enable); WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE); - manager.setWifiEnabled(enable); + mUiDevice.executeShellCommand("svc wifi " + (enable ? "enable" : "disable")); String timeoutMessage = "Timed out waiting for Wifi to be " + (enable ? "enabled!" : "disabled!"); diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java index c6c0b46d0505..b13bcd1311f6 100644 --- a/core/tests/coretests/src/android/net/NetworkKeyTest.java +++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java @@ -18,6 +18,7 @@ package android.net; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.net.wifi.ScanResult; @@ -107,7 +108,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_nullSsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.BSSID = VALID_BSSID; assertNull(NetworkKey.createFromScanResult(scanResult)); @@ -115,7 +116,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_emptySsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = ""; scanResult.BSSID = VALID_BSSID; @@ -124,7 +125,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_noneSsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = WifiManager.UNKNOWN_SSID; scanResult.BSSID = VALID_BSSID; @@ -133,7 +134,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_nullBssid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; assertNull(NetworkKey.createFromScanResult(scanResult)); @@ -141,7 +142,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_emptyBssid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; scanResult.BSSID = ""; @@ -150,7 +151,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_invalidBssid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; scanResult.BSSID = INVALID_BSSID; @@ -159,7 +160,7 @@ public class NetworkKeyTest { @Test public void createFromScanResult_validSsid() { - ScanResult scanResult = new ScanResult(); + ScanResult scanResult = mock(ScanResult.class); scanResult.SSID = VALID_UNQUOTED_SSID; scanResult.BSSID = VALID_BSSID; diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java new file mode 100644 index 000000000000..ac25e2734ac9 --- /dev/null +++ b/core/tests/coretests/src/android/util/StatsEventTest.java @@ -0,0 +1,474 @@ +/* + * 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. + */ + +package android.util; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.os.SystemClock; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.google.common.collect.Range; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Internal tests for {@link StatsEvent}. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class StatsEventTest { + + @Test + public void testNoFields() { + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder().usePooledBuffer().build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + final int expectedAtomId = 0; + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(3); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("Third element is not errors type") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS); + + final int errorMask = buffer.getInt(); + + assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask") + .that(errorMask).isEqualTo(StatsEvent.ERROR_NO_ATOM_ID); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testIntBooleanIntInt() { + final int expectedAtomId = 109; + final int field1 = 1; + final boolean field2 = true; + final int field3 = 3; + final int field4 = 4; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeInt(field1) + .writeBoolean(field2) + .writeInt(field3) + .writeInt(field4) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(6); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 1") + .that(buffer.getInt()).isEqualTo(field1); + + assertWithMessage("Second field is not Boolean") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); + + assertWithMessage("Incorrect field 2") + .that(buffer.get()).isEqualTo(1); + + assertWithMessage("Third field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 3") + .that(buffer.getInt()).isEqualTo(field3); + + assertWithMessage("Fourth field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 4") + .that(buffer.getInt()).isEqualTo(field4); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testStringFloatByteArray() { + final int expectedAtomId = 109; + final String field1 = "Str 1"; + final float field2 = 9.334f; + final byte[] field3 = new byte[] { 56, 23, 89, -120 }; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeString(field1) + .writeFloat(field2) + .writeByteArray(field3) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(5); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not String") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); + + final String field1Actual = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect field 1") + .that(field1Actual).isEqualTo(field1); + + assertWithMessage("Second field is not Float") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); + + assertWithMessage("Incorrect field 2") + .that(buffer.getFloat()).isEqualTo(field2); + + assertWithMessage("Third field is not byte array") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BYTE_ARRAY); + + final byte[] field3Actual = getByteArrayFromByteBuffer(buffer); + assertWithMessage("Incorrect field 3") + .that(field3Actual).isEqualTo(field3); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testAttributionChainLong() { + final int expectedAtomId = 109; + final int[] uids = new int[] { 1, 2, 3, 4, 5 }; + final String[] tags = new String[] { "1", "2", "3", "4", "5" }; + final long field2 = -230909823L; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeAttributionChain(uids, tags) + .writeLong(field2) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(4); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not Attribution Chain") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ATTRIBUTION_CHAIN); + + assertWithMessage("Incorrect number of attribution nodes") + .that(buffer.get()).isEqualTo((byte) uids.length); + + for (int i = 0; i < tags.length; i++) { + assertWithMessage("Incorrect uid in Attribution Chain") + .that(buffer.getInt()).isEqualTo(uids[i]); + + final String tag = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect tag in Attribution Chain") + .that(tag).isEqualTo(tags[i]); + } + + assertWithMessage("Second field is not Long") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect field 2") + .that(buffer.getLong()).isEqualTo(field2); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testKeyValuePairs() { + final int expectedAtomId = 109; + final SparseIntArray intMap = new SparseIntArray(); + final SparseLongArray longMap = new SparseLongArray(); + final SparseArray<String> stringMap = new SparseArray<>(); + final SparseArray<Float> floatMap = new SparseArray<>(); + intMap.put(1, -1); + intMap.put(2, -2); + stringMap.put(3, "abc"); + stringMap.put(4, "2h"); + floatMap.put(9, -234.344f); + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeKeyValuePairs(intMap, longMap, stringMap, floatMap) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(3); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not KeyValuePairs") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_KEY_VALUE_PAIRS); + + assertWithMessage("Incorrect number of key value pairs") + .that(buffer.get()).isEqualTo( + (byte) (intMap.size() + longMap.size() + stringMap.size() + + floatMap.size())); + + for (int i = 0; i < intMap.size(); i++) { + assertWithMessage("Incorrect key in intMap") + .that(buffer.getInt()).isEqualTo(intMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_INT in intMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("Incorrect value in intMap") + .that(buffer.getInt()).isEqualTo(intMap.valueAt(i)); + } + + for (int i = 0; i < longMap.size(); i++) { + assertWithMessage("Incorrect key in longMap") + .that(buffer.getInt()).isEqualTo(longMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_LONG in longMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + assertWithMessage("Incorrect value in longMap") + .that(buffer.getLong()).isEqualTo(longMap.valueAt(i)); + } + + for (int i = 0; i < stringMap.size(); i++) { + assertWithMessage("Incorrect key in stringMap") + .that(buffer.getInt()).isEqualTo(stringMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_STRING in stringMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); + final String value = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect value in stringMap") + .that(value).isEqualTo(stringMap.valueAt(i)); + } + + for (int i = 0; i < floatMap.size(); i++) { + assertWithMessage("Incorrect key in floatMap") + .that(buffer.getInt()).isEqualTo(floatMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_FLOAT in floatMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); + assertWithMessage("Incorrect value in floatMap") + .that(buffer.getFloat()).isEqualTo(floatMap.valueAt(i)); + } + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testSingleAnnotations() { + final int expectedAtomId = 109; + final int field1 = 1; + final byte field1AnnotationId = 45; + final boolean field1AnnotationValue = false; + final boolean field2 = true; + final byte field2AnnotationId = 1; + final int field2AnnotationValue = 23; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeInt(field1) + .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue) + .writeBoolean(field2) + .addIntAnnotation(field2AnnotationId, field2AnnotationValue) + .usePooledBuffer() + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(4); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + final byte field1Header = buffer.get(); + final int field1AnnotationValueCount = field1Header >> 4; + final byte field1Type = (byte) (field1Header & 0x0F); + assertWithMessage("First field is not Int") + .that(field1Type).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("First field annotation count is wrong") + .that(field1AnnotationValueCount).isEqualTo(1); + assertWithMessage("Incorrect field 1") + .that(buffer.getInt()).isEqualTo(field1); + assertWithMessage("First field's annotation id is wrong") + .that(buffer.get()).isEqualTo(field1AnnotationId); + assertWithMessage("First field's annotation type is wrong") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); + assertWithMessage("First field's annotation value is wrong") + .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0); + + final byte field2Header = buffer.get(); + final int field2AnnotationValueCount = field2Header >> 4; + final byte field2Type = (byte) (field2Header & 0x0F); + assertWithMessage("Second field is not boolean") + .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN); + assertWithMessage("Second field annotation count is wrong") + .that(field2AnnotationValueCount).isEqualTo(1); + assertWithMessage("Incorrect field 2") + .that(buffer.get()).isEqualTo(field2 ? 1 : 0); + assertWithMessage("Second field's annotation id is wrong") + .that(buffer.get()).isEqualTo(field2AnnotationId); + assertWithMessage("Second field's annotation type is wrong") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("Second field's annotation value is wrong") + .that(buffer.getInt()).isEqualTo(field2AnnotationValue); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) { + final int numBytes = buffer.getInt(); + byte[] bytes = new byte[numBytes]; + buffer.get(bytes); + return bytes; + } + + private static String getStringFromByteBuffer(final ByteBuffer buffer) { + final byte[] bytes = getByteArrayFromByteBuffer(buffer); + return new String(bytes, UTF_8); + } +} diff --git a/data/etc/OWNERS b/data/etc/OWNERS index ea66ee373785..70d467829269 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -1 +1 @@ -per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com +per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com, lorenzo@google.com diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 0756647d5774..3477aedefacf 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -238,6 +238,7 @@ applications that come with the platform <permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> + <permission name="android.permission.TETHER_PRIVILEGED"/> <permission name="android.permission.UPDATE_APP_OPS_STATS"/> </privapp-permissions> diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index f5fa8c546bed..e93e7dfbe22c 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -20,7 +20,7 @@ import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 08409869c626..e70529b6cd1a 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -22,7 +22,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 090d915a2f67..51b299c9ee5e 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -17,7 +17,7 @@ package android.graphics.drawable; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java index bad3791a9c24..3408b64e7536 100644 --- a/graphics/java/android/graphics/drawable/DrawableInflater.java +++ b/graphics/java/android/graphics/drawable/DrawableInflater.java @@ -16,19 +16,19 @@ package android.graphics.drawable; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.util.AttributeSet; import android.view.InflateException; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.lang.reflect.Constructor; import java.util.HashMap; diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java index 64fc7042dfc7..e8cb42e75ea2 100644 --- a/graphics/java/android/graphics/drawable/DrawableWrapper.java +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index b9945cc735d8..b50ec0d5e3fd 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -22,7 +22,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index 3658f89abae1..63662099c4c8 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -21,7 +21,7 @@ import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index bc8a4cbd7e9d..005a4d175fd5 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 760d554888ee..fb4146f04bc9 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 8561d95ddd88..99d27ba4c469 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 1540cc22e295..e5e4d4527fca 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.Resources; diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index db5f082bd853..43766b636adb 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -16,22 +16,22 @@ package android.graphics.drawable; -import com.android.internal.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; -import android.graphics.Canvas; -import android.graphics.Rect; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.util.AttributeSet; import android.util.MathUtils; import android.util.TypedValue; -import android.util.AttributeSet; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index 91ed061e511d..af7eed4b3897 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -16,14 +16,9 @@ package android.graphics.drawable; -import com.android.internal.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -34,6 +29,11 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; /** diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index f67188c22609..2920acbe514c 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -18,7 +18,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 276f3662189b..401e05ffc139 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -16,7 +16,7 @@ package android.graphics.drawable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources; import android.graphics.Canvas; diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index aa19b2a0e94c..e6fa866df3ab 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -16,7 +16,7 @@ package android.graphics.drawable; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.ColorStateList; import android.content.res.ComplexColor; diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java index bcee559d8291..4e6580ea5f53 100644 --- a/graphics/java/android/graphics/fonts/FontVariationAxis.java +++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java @@ -18,7 +18,7 @@ package android.graphics.fonts; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.text.TextUtils; diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index bd1a49205fd5..54710e58687c 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -19,7 +19,7 @@ package android.graphics.pdf; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Matrix; @@ -29,7 +29,9 @@ import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; + import com.android.internal.util.Preconditions; + import dalvik.system.CloseGuard; import libcore.io.IoUtils; diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index fad7d8062a22..7282bcfe4445 100644 --- a/keystore/java/android/security/Credentials.java +++ b/keystore/java/android/security/Credentials.java @@ -16,7 +16,7 @@ package android.security; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.android.org.bouncycastle.util.io.pem.PemObject; import com.android.org.bouncycastle.util.io.pem.PemReader; diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java index a50ff7984341..af188a95c929 100644 --- a/keystore/java/android/security/GateKeeper.java +++ b/keystore/java/android/security/GateKeeper.java @@ -16,7 +16,7 @@ package android.security; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index c0a04220cfe7..e9bc8026d25e 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,10 +16,10 @@ package android.security; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.Application; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.face.FaceManager; @@ -31,7 +31,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; -import android.security.KeyStoreException; import android.security.keymaster.ExportResult; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java index 234615d9c81d..8be85d6827f4 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java @@ -17,7 +17,7 @@ package android.security.keystore; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.security.KeyStore; import android.security.keymaster.ExportResult; import android.security.keymaster.KeyCharacteristics; diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index e3f43efff72b..630a6dd081a3 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -20,8 +20,8 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.security.GateKeeper; diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 219d04055eae..c21bdca3db77 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -219,7 +219,7 @@ Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette) : SkPixelRef(info.width(), info.height(), nullptr, - bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride()) + bytesPerPixel(buffer->getPixelFormat()) * (buffer->getStride() > 0 ? buffer->getStride() : buffer->getWidth())) , mInfo(validateAlpha(info)) , mPixelStorageType(PixelStorageType::Hardware) , mPalette(palette) diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java index f3c2a1684cda..8c40338e80fc 100644 --- a/location/java/android/location/Country.java +++ b/location/java/android/location/Country.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java index ae139499eeb2..e344b820ca2a 100644 --- a/location/java/android/location/CountryDetector.java +++ b/location/java/android/location/CountryDetector.java @@ -16,10 +16,8 @@ package android.location; -import java.util.HashMap; - import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; @@ -27,6 +25,8 @@ import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import java.util.HashMap; + /** * This class provides access to the system country detector service. This * service allows applications to obtain the country that the user is in. diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java index 70a83c5acdd9..eb67205f4de9 100644 --- a/location/java/android/location/CountryListener.java +++ b/location/java/android/location/CountryListener.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The listener for receiving the notification when the country is detected or diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java index 45d92ee7cc34..1c6e9b6e1836 100644 --- a/location/java/android/location/GeocoderParams.java +++ b/location/java/android/location/GeocoderParams.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java index 9570b26452e4..af57bfd30984 100644 --- a/location/java/android/location/Geofence.java +++ b/location/java/android/location/Geofence.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index 609a15e1be7e..8a5edc41a774 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -16,7 +16,7 @@ package android.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.SparseArray; diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index 9c36d76cf370..6f12c78e8621 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -18,7 +18,7 @@ package android.location; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Parcel; diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 7b24f44823d0..f17f7483a838 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -30,8 +30,8 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 0902acf176d4..adea73d25922 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index f9b2fe057995..9846436b3ac8 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -19,6 +19,7 @@ package com.android.internal.location; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -37,8 +38,6 @@ import com.android.internal.R; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.telephony.GsmAlphabet; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.UnsupportedEncodingException; import java.util.concurrent.TimeUnit; @@ -126,7 +125,7 @@ public class GpsNetInitiatedHandler { public static class GpsNiNotification { - @android.annotation.UnsupportedAppUsage + @android.compat.annotation.UnsupportedAppUsage public GpsNiNotification() { } public int notificationId; diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java index 155f788cb33e..c23f49976799 100644 --- a/location/java/com/android/internal/location/ProviderRequest.java +++ b/location/java/com/android/internal/location/ProviderRequest.java @@ -16,7 +16,7 @@ package com.android.internal.location; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.location.LocationRequest; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java index 5088798a2910..3cb224dd58cd 100644 --- a/media/java/android/media/AmrInputStream.java +++ b/media/java/android/media/AmrInputStream.java @@ -16,14 +16,14 @@ package android.media; -import java.io.InputStream; -import java.io.IOException; -import java.nio.ByteBuffer; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.MediaCodec.BufferInfo; import android.util.Log; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + /** * DO NOT USE diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java index 8ac26553bab4..c3dc118fec7e 100644 --- a/media/java/android/media/AsyncPlayer.java +++ b/media/java/android/media/AsyncPlayer.java @@ -17,9 +17,8 @@ package android.media; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.media.PlayerBase; import android.net.Uri; import android.os.PowerManager; import android.os.SystemClock; diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 820d82dd3bd1..bb874045817e 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.audiopolicy.AudioProductStrategy; import android.os.Build; import android.os.Bundle; diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index 62b18cbafcb1..51909db11a09 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -16,8 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; -import android.media.AudioSystem; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioDevicePort is a specialized type of AudioPort diff --git a/media/java/android/media/AudioDevicePortConfig.java b/media/java/android/media/AudioDevicePortConfig.java index 0c647ea85c60..51b8037b82f8 100644 --- a/media/java/android/media/AudioDevicePortConfig.java +++ b/media/java/android/media/AudioDevicePortConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An AudioDevicePortConfig describes a possible configuration of an output or input device diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index e55585ada6eb..7ff15df2d65e 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/AudioGain.java b/media/java/android/media/AudioGain.java index dd129a26ee59..cae1b59d46a7 100644 --- a/media/java/android/media/AudioGain.java +++ b/media/java/android/media/AudioGain.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioGain describes a gain controller. Gain controllers are exposed by diff --git a/media/java/android/media/AudioGainConfig.java b/media/java/android/media/AudioGainConfig.java index f5ebef85d302..dfefa8621ef8 100644 --- a/media/java/android/media/AudioGainConfig.java +++ b/media/java/android/media/AudioGainConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioGainConfig is used by APIs setting or getting values on a given gain diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java index 24f81f918af2..8fc834f8d0a9 100644 --- a/media/java/android/media/AudioHandle.java +++ b/media/java/android/media/AudioHandle.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioHandle is used by the audio framework implementation to diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index f797da70e7d1..32eec0054d9b 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -27,12 +27,12 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothCodecConfig; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java index c4a5c4d86a41..33d603f0b9da 100644 --- a/media/java/android/media/AudioMixPort.java +++ b/media/java/android/media/AudioMixPort.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * The AudioMixPort is a specialized type of AudioPort diff --git a/media/java/android/media/AudioMixPortConfig.java b/media/java/android/media/AudioMixPortConfig.java index 315e46b725ad..9d8120624a45 100644 --- a/media/java/android/media/AudioMixPortConfig.java +++ b/media/java/android/media/AudioMixPortConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An AudioMixPortConfig describes a possible configuration of an output or input mixer. diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java index d1f800694f50..e5107d4e3309 100644 --- a/media/java/android/media/AudioPatch.java +++ b/media/java/android/media/AudioPatch.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java index 83eb240be743..7c3ca24e1c9a 100644 --- a/media/java/android/media/AudioPort.java +++ b/media/java/android/media/AudioPort.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An audio port is a node of the audio framework or hardware that can be connected to or diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java index ac19bb167905..16fb5b80eb3e 100644 --- a/media/java/android/media/AudioPortConfig.java +++ b/media/java/android/media/AudioPortConfig.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An AudioPortConfig contains a possible configuration of an audio port chosen diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java index 6d9d6265f5e7..14249cbe8945 100644 --- a/media/java/android/media/AudioPortEventHandler.java +++ b/media/java/android/media/AudioPortEventHandler.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index ce9b07dd0c0e..306999cef7e7 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.media.MediaRecorder.Source; import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java index 874a215e4975..5f32c0f3f4a8 100644 --- a/media/java/android/media/AudioRecordingConfiguration.java +++ b/media/java/android/media/AudioRecordingConfiguration.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.audiofx.AudioEffect; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 1033e56776b9..1ad61983904c 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -19,8 +19,8 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothCodecConfig; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.media.audiofx.AudioEffect; diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 7cd09de41346..0ced68ef8695 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -23,7 +23,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java index 963b1d1504e2..e4bab7466a70 100644 --- a/media/java/android/media/CamcorderProfile.java +++ b/media/java/android/media/CamcorderProfile.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.os.Build; diff --git a/media/java/android/media/DecoderCapabilities.java b/media/java/android/media/DecoderCapabilities.java index df5e918ba8d5..ebfc63bd9bcd 100644 --- a/media/java/android/media/DecoderCapabilities.java +++ b/media/java/android/media/DecoderCapabilities.java @@ -16,9 +16,10 @@ package android.media; -import android.annotation.UnsupportedAppUsage; -import java.util.List; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; +import java.util.List; /** * {@hide} diff --git a/media/java/android/media/EncoderCapabilities.java b/media/java/android/media/EncoderCapabilities.java index c09c5fae1213..67ce0f7cc0b9 100644 --- a/media/java/android/media/EncoderCapabilities.java +++ b/media/java/android/media/EncoderCapabilities.java @@ -16,9 +16,10 @@ package android.media; -import android.annotation.UnsupportedAppUsage; -import java.util.List; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; +import java.util.List; /** * The EncoderCapabilities class is used to retrieve the diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 5645ba5d7dac..b41792710cbf 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -20,7 +20,7 @@ import android.annotation.CurrentTimeMillisLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 70a343f4de01..b5acbd457db0 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -16,14 +16,13 @@ package android.media; -import java.nio.ByteBuffer; -import java.lang.AutoCloseable; - import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.hardware.HardwareBuffer; +import java.nio.ByteBuffer; + /** * <p>A single complete image buffer to use with a media source such as a * {@link MediaCodec} or a diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index e85b3ff99104..84ee09b35b81 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -17,7 +17,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.os.Handler; import android.os.Looper; diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index c9d79784004c..e702f19903d0 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.SurfaceTexture; diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index f304f7cc5981..f3752d56ea0f 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -22,7 +22,7 @@ import static android.media.Utils.sortDistinctRanges; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.SystemProperties; import android.util.Log; diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index a08aec3ed20c..ea9a373a19f2 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -21,17 +21,17 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; -import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; -import android.os.Message; import android.os.Parcel; import android.os.PersistableBundle; import android.util.Log; + import dalvik.system.CloseGuard; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index c4eb0310f292..9908e042c6a4 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -20,7 +20,7 @@ import static android.content.ContentResolver.MIME_TYPE_DEFAULT; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.mtp.MtpConstants; import libcore.content.type.MimeMap; diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 8b667f772867..841799a58aa4 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java index 8ee929e77899..a17ff825e21b 100644 --- a/media/java/android/media/MediaHTTPConnection.java +++ b/media/java/android/media/MediaHTTPConnection.java @@ -18,13 +18,14 @@ package android.media; import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkUtils; 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; diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java index 97a0df799101..3008067daefb 100644 --- a/media/java/android/media/MediaHTTPService.java +++ b/media/java/android/media/MediaHTTPService.java @@ -17,7 +17,7 @@ package android.media; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.IBinder; import android.util.Log; diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java index 0749f58e460d..ca7a01cb990d 100644 --- a/media/java/android/media/MediaInserter.java +++ b/media/java/android/media/MediaInserter.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; import android.content.ContentValues; import android.net.Uri; diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java index 8512dbe8d224..a23191f36efc 100644 --- a/media/java/android/media/MediaMetadata.java +++ b/media/java/android/media/MediaMetadata.java @@ -17,7 +17,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.StringDef; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index c43b78cf4fc7..a21a630e200a 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -19,7 +19,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java index 0fb392bfc0fe..14a48d72f9bb 100644 --- a/media/java/android/media/MediaMuxer.java +++ b/media/java/android/media/MediaMuxer.java @@ -18,8 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; -import android.media.MediaCodec; +import android.compat.annotation.UnsupportedAppUsage; import android.media.MediaCodec.BufferInfo; import dalvik.system.CloseGuard; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 353e58e98efa..6b953ae932f0 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -19,8 +19,8 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 63b22df12953..c957a883be1a 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -23,8 +23,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.Camera; import android.os.Build; import android.os.Handler; diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index d72231f40dcf..9837e1cc62b3 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -22,8 +22,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 771628cf7b1e..317502d760a8 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java index 792a2ba678fd..ef17073654a6 100644 --- a/media/java/android/media/Metadata.java +++ b/media/java/android/media/Metadata.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.util.Log; import android.util.MathUtils; diff --git a/media/java/android/media/MicrophoneInfo.java b/media/java/android/media/MicrophoneInfo.java index f805975d53b0..876628fefff4 100644 --- a/media/java/android/media/MicrophoneInfo.java +++ b/media/java/android/media/MicrophoneInfo.java @@ -18,7 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Pair; import java.lang.annotation.Retention; diff --git a/media/java/android/media/PlaybackParams.java b/media/java/android/media/PlaybackParams.java index b4325b6ea53d..f24f831d0333 100644 --- a/media/java/android/media/PlaybackParams.java +++ b/media/java/android/media/PlaybackParams.java @@ -18,7 +18,7 @@ package android.media; import android.annotation.IntDef; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 325420b06122..c5fd3c30236d 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -16,8 +16,8 @@ package android.media; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.graphics.Bitmap; diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index f70963a982e4..9e48f1e05391 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -16,8 +16,8 @@ package android.media; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.graphics.Bitmap; diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java index 2be206f2f462..e529af9da935 100644 --- a/media/java/android/media/RemoteDisplay.java +++ b/media/java/android/media/RemoteDisplay.java @@ -16,12 +16,12 @@ package android.media; -import dalvik.system.CloseGuard; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.view.Surface; +import dalvik.system.CloseGuard; + /** * Listens for Wifi remote display connections managed by the media server. * diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java index 2f4ace0c8fdd..fed361a960e6 100644 --- a/media/java/android/media/RemoteDisplayState.java +++ b/media/java/android/media/RemoteDisplayState.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index eb680c8377f4..d35bc4176cb3 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -17,7 +17,7 @@ package android.media; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index 435d8d766149..6fd47c42bcba 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -22,9 +22,9 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.app.Activity; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java index 1a241af7345d..48657a6c810f 100644 --- a/media/java/android/media/SubtitleController.java +++ b/media/java/android/media/SubtitleController.java @@ -16,10 +16,7 @@ package android.media; -import java.util.Locale; -import java.util.Vector; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer.TrackInfo; import android.media.SubtitleTrack.RenderingWidget; @@ -28,6 +25,9 @@ import android.os.Looper; import android.os.Message; import android.view.accessibility.CaptioningManager; +import java.util.Locale; +import java.util.Vector; + /** * The subtitle controller provides the architecture to display subtitles for a * media source. It allows specifying which tracks to display, on which anchor diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java index 0705d97a9edf..10669f466fe5 100644 --- a/media/java/android/media/SubtitleTrack.java +++ b/media/java/android/media/SubtitleTrack.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Canvas; import android.media.MediaPlayer.TrackInfo; import android.os.Handler; diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java index 534d63b4cca0..cbdf9adfd0e1 100644 --- a/media/java/android/media/ThumbnailUtils.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -24,7 +24,7 @@ import static android.os.Environment.MEDIA_UNKNOWN; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; diff --git a/media/java/android/media/TimedText.java b/media/java/android/media/TimedText.java index d8cdf9c12e09..120642a8e7cb 100644 --- a/media/java/android/media/TimedText.java +++ b/media/java/android/media/TimedText.java @@ -16,14 +16,15 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Rect; import android.os.Parcel; import android.util.Log; + +import java.util.ArrayList; import java.util.HashMap; -import java.util.Set; import java.util.List; -import java.util.ArrayList; +import java.util.Set; /** * Class to hold the timed text's metadata, including: diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java index c6d5ba3f9953..cc114a9092e1 100644 --- a/media/java/android/media/ToneGenerator.java +++ b/media/java/android/media/ToneGenerator.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java index 34154ce93a8c..e5782642f4eb 100644 --- a/media/java/android/media/TtmlRenderer.java +++ b/media/java/android/media/TtmlRenderer.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; @@ -27,6 +27,10 @@ import android.view.accessibility.CaptioningManager; import android.widget.LinearLayout; import android.widget.TextView; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; @@ -37,10 +41,6 @@ import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - /** @hide */ public class TtmlRenderer extends SubtitleController.Renderer { private final Context mContext; diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java index 663d564af23e..99dfe1e8e32f 100644 --- a/media/java/android/media/VolumeShaper.java +++ b/media/java/android/media/VolumeShaper.java @@ -19,13 +19,12 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.AutoCloseable; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Objects; diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java index 36458d7e1746..bc1429499e70 100644 --- a/media/java/android/media/WebVttRenderer.java +++ b/media/java/android/media/WebVttRenderer.java @@ -16,7 +16,7 @@ package android.media; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.text.Layout.Alignment; import android.text.SpannableStringBuilder; diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 5b4bbce91784..4a40c627ecb0 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -19,8 +19,8 @@ package android.media.audiofx; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Handler; import android.os.Looper; diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 89a509f64a1b..392e8fe7543f 100644 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -16,8 +16,8 @@ package android.media.audiofx; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index a82c78fad271..dd9877a9c706 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioDeviceInfo; import android.media.AudioFormat; import android.media.AudioSystem; diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java index c4afd95be9ac..8c204d222cd4 100644 --- a/media/java/android/media/audiopolicy/AudioMixingRule.java +++ b/media/java/android/media/audiopolicy/AudioMixingRule.java @@ -19,7 +19,7 @@ package android.media.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioAttributes; import android.os.Parcel; import android.util.Log; diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 1fc4f7d59ca5..a856653e8bc9 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -18,8 +18,8 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.media.AudioAttributes; diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index e11715ff7299..5db4e8c1e3f7 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -19,9 +19,9 @@ package android.media.session; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index 123c4f75d5b6..0d506f0eb52c 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -16,9 +16,9 @@ package android.media.session; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -26,7 +26,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; -import android.media.AudioManager; import android.media.MediaMetadata; import android.media.MediaMetadataEditor; import android.media.MediaMetadataRetriever; diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index a89dc5f1d2af..aff725734ee1 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -22,7 +22,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.ParceledListSlice; diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java index 23e2949372aa..d5ff1ee6512a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java @@ -38,7 +38,7 @@ public class DataUsageUtils { final SubscriptionManager subscriptionManager = context.getSystemService( SubscriptionManager.class); final NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( - telephonyManager.getSubscriberId(subId)); + telephonyManager.createForSubscriptionId(subId).getSubscriberId()); if (!subscriptionManager.isActiveSubId(subId)) { Log.i(TAG, "Subscription is not active: " + subId); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index efd31ca6a86e..af2569dcb1f2 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -186,6 +186,9 @@ <uses-permission android:name="android.permission.MANAGE_APPOPS" /> + <!-- Permission required for storage tests - FuseDaemonHostTest --> + <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> + <!-- Permission needed to run network tests in CTS --> <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" /> <!-- Permission needed to test tcp keepalive offload. --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java index 367a7bd4aed7..0ffe05de1357 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java @@ -26,8 +26,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.os.RemoteException; -import android.os.ServiceManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -37,7 +35,6 @@ import android.view.View; import android.view.WindowManager; import android.widget.ImageView; -import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; @@ -254,27 +251,29 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { @Override public void run() { - try { - if (DEBUG) { - Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); - } - final int[] result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPinReportResultForSubscriber(mSubId, mPin); - if (DEBUG) { - Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); - } + if (DEBUG) { + Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); + } + TelephonyManager telephonyManager = + ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) + .createForSubscriptionId(mSubId); + final int[] result = telephonyManager.supplyPinReportResult(mPin); + if (result == null || result.length == 0) { + Log.e(TAG, "Error result for supplyPinReportResult."); post(new Runnable() { @Override public void run() { - onSimCheckResponse(result[0], result[1]); + onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); } }); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException for supplyPinReportResult:", e); + } else { + if (DEBUG) { + Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); + } post(new Runnable() { @Override public void run() { - onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); + onSimCheckResponse(result[0], result[1]); } }); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java index 81f8c67605fe..abadcfd60a38 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java @@ -25,8 +25,6 @@ import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.os.RemoteException; -import android.os.ServiceManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -36,7 +34,6 @@ import android.view.View; import android.view.WindowManager; import android.widget.ImageView; -import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; @@ -314,25 +311,27 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { @Override public void run() { - try { - if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); - final int[] result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPukReportResultForSubscriber(mSubId, mPuk, mPin); - if (DEBUG) { - Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); - } + if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); + TelephonyManager telephonyManager = + ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) + .createForSubscriptionId(mSubId); + final int[] result = telephonyManager.supplyPukReportResult(mPuk, mPin); + if (result == null || result.length == 0) { + Log.e(TAG, "Error result for supplyPukReportResult."); post(new Runnable() { @Override public void run() { - onSimLockChangedResponse(result[0], result[1]); + onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); } }); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException for supplyPukReportResult:", e); + } else { + if (DEBUG) { + Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); + } post(new Runnable() { @Override public void run() { - onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1); + onSimLockChangedResponse(result[0], result[1]); } }); } diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index 87a8c3f5c68a..e99c2c529bd2 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -33,6 +33,7 @@ <uses-permission android:name="android.permission.MANAGE_USB" /> <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> + <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index fe3f51700df9..5692a6fc5c80 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -16,9 +16,12 @@ package com.android.server.connectivity.tethering; +import static android.net.ConnectivityManager.TYPE_BLUETOOTH; +import static android.net.ConnectivityManager.TYPE_ETHERNET; +import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.net.ConnectivityManager.TYPE_NONE; +import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -35,8 +38,10 @@ import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.os.Handler; import android.util.Log; +import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import com.android.internal.util.StateMachine; import java.util.HashMap; @@ -77,11 +82,25 @@ public class UpstreamNetworkMonitor { public static final int EVENT_ON_LINKPROPERTIES = 2; public static final int EVENT_ON_LOST = 3; public static final int NOTIFY_LOCAL_PREFIXES = 10; + // This value is used by deprecated preferredUpstreamIfaceTypes selection which is default + // disabled. + @VisibleForTesting + public static final int TYPE_NONE = -1; private static final int CALLBACK_LISTEN_ALL = 1; private static final int CALLBACK_DEFAULT_INTERNET = 2; private static final int CALLBACK_MOBILE_REQUEST = 3; + private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray(); + static { + sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR); + sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI); + sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH); + sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET); + } + private final Context mContext; private final SharedLog mLog; private final StateMachine mTarget; @@ -202,7 +221,7 @@ public class UpstreamNetworkMonitor { final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI; final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder() - .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType)) + .setCapabilities(networkCapabilitiesForType(legacyType)) .build(); // The existing default network and DUN callbacks will be notified. @@ -354,16 +373,6 @@ public class UpstreamNetworkMonitor { notifyTarget(EVENT_ON_LINKPROPERTIES, network); } - private void handleSuspended(Network network) { - if (!network.equals(mTetheringUpstreamNetwork)) return; - mLog.log("SUSPENDED current upstream: " + network); - } - - private void handleResumed(Network network) { - if (!network.equals(mTetheringUpstreamNetwork)) return; - mLog.log("RESUMED current upstream: " + network); - } - private void handleLost(Network network) { // There are few TODOs within ConnectivityService's rematching code // pertaining to spurious onLost() notifications. @@ -453,20 +462,6 @@ public class UpstreamNetworkMonitor { } @Override - public void onNetworkSuspended(Network network) { - if (mCallbackType == CALLBACK_LISTEN_ALL) { - handleSuspended(network); - } - } - - @Override - public void onNetworkResumed(Network network) { - if (mCallbackType == CALLBACK_LISTEN_ALL) { - handleResumed(network); - } - } - - @Override public void onLost(Network network) { if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { mDefaultInternetNetwork = null; @@ -510,7 +505,7 @@ public class UpstreamNetworkMonitor { for (int type : preferredTypes) { NetworkCapabilities nc; try { - nc = ConnectivityManager.networkCapabilitiesForType(type); + nc = networkCapabilitiesForType(type); } catch (IllegalArgumentException iae) { Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " + type); continue; @@ -572,4 +567,28 @@ public class UpstreamNetworkMonitor { return null; } + + /** + * Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance. + * This function is used for deprecated legacy type and be disabled by default. + */ + @VisibleForTesting + public static NetworkCapabilities networkCapabilitiesForType(int type) { + final NetworkCapabilities nc = new NetworkCapabilities(); + + // Map from type to transports. + final int notFound = -1; + final int transport = sLegacyTypeToTransport.get(type, notFound); + Preconditions.checkArgument(transport != notFound, "unknown legacy type: " + type); + nc.addTransportType(transport); + + if (type == TYPE_MOBILE_DUN) { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); + // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES. + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } else { + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + return nc; + } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java index c90abbbedb5f..5ed75bf26f8b 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java @@ -18,13 +18,14 @@ package com.android.server.connectivity.tethering; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static com.android.server.connectivity.tethering.UpstreamNetworkMonitor.TYPE_NONE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -538,13 +539,15 @@ public class UpstreamNetworkMonitorTest { mUNM.selectPreferredUpstreamType(preferredTypes)); verify(mEntitleMgr, times(1)).maybeRunProvisioning(); } + private void assertSatisfiesLegacyType(int legacyType, UpstreamNetworkState ns) { if (legacyType == TYPE_NONE) { assertTrue(ns == null); return; } - final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType); + final NetworkCapabilities nc = + UpstreamNetworkMonitor.networkCapabilitiesForType(legacyType); assertTrue(nc.satisfiedByNetworkCapabilities(ns.networkCapabilities)); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 877c40f94696..18c6e3a5d4b7 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -222,13 +222,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.RoSystemProperties; -import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -389,6 +387,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_SUBSCRIPTION_OVERRIDE = 16; private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17; private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; + private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -3039,12 +3038,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Verify they're not lying about package name mAppOps.checkPackage(callingUid, callingPackage); + final SubscriptionManager sm; final SubscriptionInfo si; final PersistableBundle config; final long token = Binder.clearCallingIdentity(); try { - si = mContext.getSystemService(SubscriptionManager.class) - .getActiveSubscriptionInfo(subId); + sm = mContext.getSystemService(SubscriptionManager.class); + si = sm.getActiveSubscriptionInfo(subId); config = mCarrierConfigManager.getConfigForSubId(subId); } finally { Binder.restoreCallingIdentity(token); @@ -3052,7 +3052,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // First check: is caller the CarrierService? if (si != null) { - if (si.isEmbedded() && si.canManageSubscription(mContext, callingPackage)) { + if (si.isEmbedded() && sm.canManageSubscription(si, callingPackage)) { return; } } @@ -3092,6 +3092,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG); } + private void enforceSubscriptionPlanValidity(SubscriptionPlan[] plans) { + // nothing to check if no plans + if (plans.length == 0) { + return; + } + + long applicableNetworkTypes = 0; + boolean allNetworks = false; + for (SubscriptionPlan plan : plans) { + if (plan.getNetworkTypes() == null) { + allNetworks = true; + } else { + if ((applicableNetworkTypes & plan.getNetworkTypesBitMask()) != 0) { + throw new IllegalArgumentException( + "Multiple subscription plans defined for a single network type."); + } else { + applicableNetworkTypes |= plan.getNetworkTypesBitMask(); + } + } + } + + // ensure at least one plan applies for every network type + if (!allNetworks) { + throw new IllegalArgumentException( + "No generic subscription plan that applies to all network types."); + } + } + @Override public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); @@ -3256,6 +3284,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); + enforceSubscriptionPlanValidity(plans); for (SubscriptionPlan plan : plans) { Objects.requireNonNull(plan); @@ -3284,6 +3313,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS); + mHandler.sendMessage( + mHandler.obtainMessage(MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans)); } finally { Binder.restoreCallingIdentity(token); } @@ -3310,7 +3341,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, - long networkTypeMask, long timeoutMillis, String callingPackage) { + long timeoutMillis, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); // We can only override when carrier told us about plans @@ -3328,16 +3359,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean overrideEnabled = Settings.Global.getInt(mContext.getContentResolver(), NETPOLICY_OVERRIDE_ENABLED, 1) != 0; if (overrideEnabled || overrideValue == 0) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = subId; - args.arg2 = overrideMask; - args.arg3 = overrideValue; - args.arg4 = networkTypeMask; - mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, + overrideMask, overrideValue, subId)); if (timeoutMillis > 0) { - args.arg3 = 0; - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args), - timeoutMillis); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, + overrideMask, 0, subId), timeoutMillis); } } } @@ -4473,11 +4499,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId, - int overrideMask, int overrideValue, long networkTypeMask) { + int overrideMask, int overrideValue) { if (listener != null) { try { - listener.onSubscriptionOverride(subId, overrideMask, overrideValue, - networkTypeMask); + listener.onSubscriptionOverride(subId, overrideMask, overrideValue); + } catch (RemoteException ignored) { + } + } + } + + private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId, + SubscriptionPlan[] plans) { + if (listener != null) { + try { + listener.onSubscriptionPlansChanged(subId, plans); } catch (RemoteException ignored) { } } @@ -4578,16 +4613,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return true; } case MSG_SUBSCRIPTION_OVERRIDE: { - final SomeArgs args = (SomeArgs) msg.obj; - final int subId = (int) args.arg1; - final int overrideMask = (int) args.arg2; - final int overrideValue = (int) args.arg3; - final long networkTypeMask = (long) args.arg4; + final int overrideMask = msg.arg1; + final int overrideValue = msg.arg2; + final int subId = (int) msg.obj; final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); - dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue, - networkTypeMask); + dispatchSubscriptionOverride(listener, subId, overrideMask, overrideValue); } mListeners.finishBroadcast(); return true; @@ -4604,6 +4636,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setNetworkTemplateEnabledInner(template, enabled); return true; } + case MSG_SUBSCRIPTION_PLANS_CHANGED: { + final SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj; + final int subId = msg.arg1; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + dispatchSubscriptionPlansChanged(listener, subId, plans); + } + mListeners.finishBroadcast(); + return true; + } default: { return false; } diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java index 61cd88aac921..c93e5c5e4759 100644 --- a/services/net/java/android/net/ip/IpClientCallbacks.java +++ b/services/net/java/android/net/ip/IpClientCallbacks.java @@ -17,6 +17,7 @@ package android.net.ip; import android.net.DhcpResults; +import android.net.DhcpResultsParcelable; import android.net.Layer2PacketParcelable; import android.net.LinkProperties; @@ -69,6 +70,18 @@ public class IpClientCallbacks { public void onNewDhcpResults(DhcpResults dhcpResults) {} /** + * Callback called when new DHCP results are available. + * + * <p>This is purely advisory and not an indication of provisioning success or failure. This is + * only here for callers that want to expose DHCPv4 results to other APIs + * (e.g., WifiInfo#setInetAddress). + * + * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not + * the passed-in DhcpResults object is null. + */ + public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {} + + /** * Indicates that provisioning was successful. */ public void onProvisioningSuccess(LinkProperties newLp) {} diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java index 4d60e6239376..7f723b1c232b 100644 --- a/services/net/java/android/net/ip/IpClientUtil.java +++ b/services/net/java/android/net/ip/IpClientUtil.java @@ -119,6 +119,7 @@ public class IpClientUtil { @Override public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) { mCb.onNewDhcpResults(fromStableParcelable(dhcpResults)); + mCb.onNewDhcpResults(dhcpResults); } @Override diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java index 8fd8d0461e75..07b17ebdeb63 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java @@ -29,6 +29,7 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; @@ -57,7 +58,6 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.net.wifi.WifiSsid; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -180,8 +180,8 @@ public class NetworkScoreServiceTest { } private ScanResult createScanResult(String ssid, String bssid) { - ScanResult result = new ScanResult(); - result.wifiSsid = WifiSsid.createFromAsciiEncoded(ssid); + ScanResult result = mock(ScanResult.class); + result.SSID = ssid; result.BSSID = bssid; return result; } @@ -792,7 +792,7 @@ public class NetworkScoreServiceTest { @Test public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception { List<ScanResult> invalidScanResults = Lists.newArrayList( - new ScanResult(), + mock(ScanResult.class), createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid), createScanResult(WifiManager.UNKNOWN_SSID, SCORED_NETWORK.networkKey.wifiKey.bssid), createScanResult(SSID, null), diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java index bd3d9ab2220d..3852b9fec001 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.Context; import android.content.pm.ModuleInfo; +import android.content.pm.PackageManager; import android.test.InstrumentationTestCase; import com.android.frameworks.servicestests.R; @@ -28,7 +29,7 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { public void testSuccessfulParse() { ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); - List<ModuleInfo> mi = provider.getInstalledModules(0); + List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL); assertEquals(2, mi.size()); Collections.sort(mi, (ModuleInfo m1, ModuleInfo m2) -> @@ -49,18 +50,18 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { public void testParseFailure_incorrectTopLevelElement() { ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata1); - assertEquals(0, provider.getInstalledModules(0).size()); + assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size()); } public void testParseFailure_incorrectModuleElement() { ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata2); - assertEquals(0, provider.getInstalledModules(0).size()); + assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size()); } public void testParse_unknownAttributesIgnored() { ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); - List<ModuleInfo> mi = provider.getInstalledModules(0); + List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL); assertEquals(2, mi.size()); ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 2f37c2a3af5a..de99b0da77df 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3018,7 +3018,7 @@ public class CarrierConfigManager { "ping_test_before_data_switch_bool"; /** - * Controls time in milli seconds until DcTracker reevaluates 5G connection state. + * Controls time in milliseconds until DcTracker reevaluates 5G connection state. * @hide */ public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 71ea3a3e7198..4de9e1e4c1c7 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -54,7 +54,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Telephony.SimInfo; -import android.telephony.Annotation.NetworkType; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; import android.util.DisplayMetrics; @@ -2503,6 +2502,8 @@ public class SubscriptionManager { * may not be displayed or used by decision making logic. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. + * @throws IllegalArgumentException if plans don't meet the requirements + * defined in {@link SubscriptionPlan}. */ public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) { try { @@ -2547,51 +2548,10 @@ public class SubscriptionManager { */ public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered, @DurationMillisLong long timeoutMillis) { - setSubscriptionOverrideUnmetered(subId, null, overrideUnmetered, timeoutMillis); - } - - /** - * Temporarily override the billing relationship between a carrier and - * a specific subscriber to be considered unmetered for the given network - * types. This will be reflected to apps via - * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED}. - * This method is only accessible to the following narrow set of apps: - * <ul> - * <li>The carrier app for this subscriberId, as determined by - * {@link TelephonyManager#hasCarrierPrivileges()}. - * <li>The carrier app explicitly delegated access through - * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}. - * </ul> - * - * @param subId the subscriber this override applies to. - * @param networkTypes all network types to set an override for. A null - * network type means to apply the override to all network types. - * Any unspecified network types will default to metered. - * @param overrideUnmetered set if the billing relationship should be - * considered unmetered. - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the - * requested state until explicitly cleared, or the next reboot, - * whichever happens first. - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * {@hide} - */ - public void setSubscriptionOverrideUnmetered(int subId, - @Nullable @NetworkType int[] networkTypes, boolean overrideUnmetered, - @DurationMillisLong long timeoutMillis) { try { - long networkTypeMask = 0; - if (networkTypes != null) { - for (int networkType : networkTypes) { - networkTypeMask |= TelephonyManager.getBitMaskForNetworkType(networkType); - } - } else { - networkTypeMask = ~0; - } final int overrideValue = overrideUnmetered ? OVERRIDE_UNMETERED : 0; getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue, - networkTypeMask, timeoutMillis, mContext.getOpPackageName()); + timeoutMillis, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2623,52 +2583,10 @@ public class SubscriptionManager { */ public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested, @DurationMillisLong long timeoutMillis) { - setSubscriptionOverrideCongested(subId, null, overrideCongested, timeoutMillis); - } - - /** - * Temporarily override the billing relationship plan between a carrier and - * a specific subscriber to be considered congested. This will cause the - * device to delay certain network requests when possible, such as developer - * jobs that are willing to run in a flexible time window. - * <p> - * This method is only accessible to the following narrow set of apps: - * <ul> - * <li>The carrier app for this subscriberId, as determined by - * {@link TelephonyManager#hasCarrierPrivileges()}. - * <li>The carrier app explicitly delegated access through - * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}. - * </ul> - * - * @param subId the subscriber this override applies to. - * @param networkTypes all network types to set an override for. A null - * network type means to apply the override to all network types. - * Any unspecified network types will default to not congested. - * @param overrideCongested set if the subscription should be considered - * congested. - * @param timeoutMillis the timeout after which the requested override will - * be automatically cleared, or {@code 0} to leave in the - * requested state until explicitly cleared, or the next reboot, - * whichever happens first. - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * @hide - */ - public void setSubscriptionOverrideCongested(int subId, - @Nullable @NetworkType int[] networkTypes, boolean overrideCongested, - @DurationMillisLong long timeoutMillis) { try { - long networkTypeMask = 0; - if (networkTypes != null) { - for (int networkType : networkTypes) { - networkTypeMask |= TelephonyManager.getBitMaskForNetworkType(networkType); - } - } else { - networkTypeMask = ~0; - } final int overrideValue = overrideCongested ? OVERRIDE_CONGESTED : 0; getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue, - networkTypeMask, timeoutMillis, mContext.getOpPackageName()); + timeoutMillis, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f2c0aa6158b3..05fa67f9dbc1 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -107,6 +107,7 @@ import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.SmsApplication; +import com.android.telephony.Rlog; import dalvik.system.VMRuntime; @@ -8134,9 +8135,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPin(pin); + return telephony.supplyPinForSubscriber(getSubId(), pin); } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#supplyPin", e); + Log.e(TAG, "Error calling ITelephony#supplyPinForSubscriber", e); } return false; } @@ -8148,9 +8149,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPuk(puk, pin); + return telephony.supplyPukForSubscriber(getSubId(), puk, pin); } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#supplyPuk", e); + Log.e(TAG, "Error calling ITelephony#supplyPukForSubscriber", e); } return false; } @@ -8162,9 +8163,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPinReportResult(pin); + return telephony.supplyPinReportResultForSubscriber(getSubId(), pin); } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#supplyPinReportResult", e); + Log.e(TAG, "Error calling ITelephony#supplyPinReportResultForSubscriber", e); } return new int[0]; } @@ -8176,7 +8177,7 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) - return telephony.supplyPukReportResult(puk, pin); + return telephony.supplyPukReportResultForSubscriber(getSubId(), puk, pin); } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#]", e); } diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 668a6af08145..9e786ce32792 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -111,7 +111,7 @@ public class DctConstants { public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49; public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50; public static final int EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED = BASE + 51; - public static final int EVENT_5G_NETWORK_CHANGED = BASE + 52; + public static final int EVENT_SERVICE_STATE_CHANGED = BASE + 52; public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53; public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54; diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 0baac71ffb68..c0d6369686c4 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -117,13 +117,6 @@ interface ITelephony { */ boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage, String callingFeatureId); - /** - * Supply a pin to unlock the SIM. Blocks until a result is determined. - * @param pin The pin to check. - * @return whether the operation was a success. - */ - @UnsupportedAppUsage - boolean supplyPin(String pin); /** * Supply a pin to unlock the SIM for particular subId. @@ -139,15 +132,6 @@ interface ITelephony { * Blocks until a result is determined. * @param puk The puk to check. * pin The new pin to be set in SIM - * @return whether the operation was a success. - */ - boolean supplyPuk(String puk, String pin); - - /** - * Supply puk to unlock the SIM and set SIM pin to new pin. - * Blocks until a result is determined. - * @param puk The puk to check. - * pin The new pin to be set in SIM * @param subId user preferred subId. * @return whether the operation was a success. */ @@ -160,15 +144,6 @@ interface ITelephony { * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code * retValue[1] = number of attempts remaining if known otherwise -1 */ - int[] supplyPinReportResult(String pin); - - /** - * Supply a pin to unlock the SIM. Blocks until a result is determined. - * Returns a specific success/error code. - * @param pin The pin to check. - * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code - * retValue[1] = number of attempts remaining if known otherwise -1 - */ int[] supplyPinReportResultForSubscriber(int subId, String pin); /** @@ -180,17 +155,6 @@ interface ITelephony { * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code * retValue[1] = number of attempts remaining if known otherwise -1 */ - int[] supplyPukReportResult(String puk, String pin); - - /** - * Supply puk to unlock the SIM and set SIM pin to new pin. - * Blocks until a result is determined. - * Returns a specific success/error code - * @param puk The puk to check - * pin The pin to check. - * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code - * retValue[1] = number of attempts remaining if known otherwise -1 - */ int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin); /** diff --git a/telephony/java/com/android/telephony/Rlog.java b/telephony/java/com/android/telephony/Rlog.java new file mode 100644 index 000000000000..9d6c930de8f5 --- /dev/null +++ b/telephony/java/com/android/telephony/Rlog.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.telephony; + +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import com.android.internal.telephony.util.TelephonyUtils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * A copy of {@link android.telephony.Rlog} to be used within the telephony mainline module. + * + * @hide + */ +public final class Rlog { + + private static final boolean USER_BUILD = TelephonyUtils.IS_USER; + + private Rlog() { + } + + private static int log(int priority, String tag, String msg) { + return Log.logToRadioBuffer(priority, tag, msg); + } + + public static int v(String tag, String msg) { + return log(Log.VERBOSE, tag, msg); + } + + public static int v(String tag, String msg, Throwable tr) { + return log(Log.VERBOSE, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int d(String tag, String msg) { + return log(Log.DEBUG, tag, msg); + } + + public static int d(String tag, String msg, Throwable tr) { + return log(Log.DEBUG, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int i(String tag, String msg) { + return log(Log.INFO, tag, msg); + } + + public static int i(String tag, String msg, Throwable tr) { + return log(Log.INFO, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int w(String tag, String msg) { + return log(Log.WARN, tag, msg); + } + + public static int w(String tag, String msg, Throwable tr) { + return log(Log.WARN, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int w(String tag, Throwable tr) { + return log(Log.WARN, tag, Log.getStackTraceString(tr)); + } + + public static int e(String tag, String msg) { + return log(Log.ERROR, tag, msg); + } + + public static int e(String tag, String msg, Throwable tr) { + return log(Log.ERROR, tag, + msg + '\n' + Log.getStackTraceString(tr)); + } + + public static int println(int priority, String tag, String msg) { + return log(priority, tag, msg); + } + + public static boolean isLoggable(String tag, int level) { + return Log.isLoggable(tag, level); + } + + /** + * Redact personally identifiable information for production users. + * @param tag used to identify the source of a log message + * @param pii the personally identifiable information we want to apply secure hash on. + * @return If tag is loggable in verbose mode or pii is null, return the original input. + * otherwise return a secure Hash of input pii + */ + public static String pii(String tag, Object pii) { + String val = String.valueOf(pii); + if (pii == null || TextUtils.isEmpty(val) || isLoggable(tag, Log.VERBOSE)) { + return val; + } + return "[" + secureHash(val.getBytes()) + "]"; + } + + /** + * Redact personally identifiable information for production users. + * @param enablePiiLogging set when caller explicitly want to enable sensitive logging. + * @param pii the personally identifiable information we want to apply secure hash on. + * @return If enablePiiLogging is set to true or pii is null, return the original input. + * otherwise return a secure Hash of input pii + */ + public static String pii(boolean enablePiiLogging, Object pii) { + String val = String.valueOf(pii); + if (pii == null || TextUtils.isEmpty(val) || enablePiiLogging) { + return val; + } + return "[" + secureHash(val.getBytes()) + "]"; + } + + /** + * Returns a secure hash (using the SHA1 algorithm) of the provided input. + * + * @return "****" if the build type is user, otherwise the hash + * @param input the bytes for which the secure hash should be computed. + */ + private static String secureHash(byte[] input) { + // Refrain from logging user personal information in user build. + if (USER_BUILD) { + return "****"; + } + + MessageDigest messageDigest; + + try { + messageDigest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + return "####"; + } + + byte[] result = messageDigest.digest(input); + return Base64.encodeToString( + result, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP); + } +} diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py index 46105f4d66b0..0b2077d9bba0 100755 --- a/tools/hiddenapi/generate_hiddenapi_lists.py +++ b/tools/hiddenapi/generate_hiddenapi_lists.py @@ -149,7 +149,12 @@ def extract_package(signature): The package name of the class containing the field/method. """ full_class_name = signature.split(";->")[0] - package_name = full_class_name[1:full_class_name.rindex("/")] + # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy + if (full_class_name[0] != "L"): + raise ValueError("Expected to start with 'L': %s" % full_class_name) + full_class_name = full_class_name[1:] + # If full_class_name doesn't contain '/', then package_name will be ''. + package_name = full_class_name.rpartition("/")[0] return package_name.replace('/', '.') class FlagsDict: diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp index 79dce4a8ce09..7b2ca9a65242 100644 --- a/tools/lock_agent/Android.bp +++ b/tools/lock_agent/Android.bp @@ -25,6 +25,7 @@ cc_binary_host { srcs: ["agent.cpp"], static_libs: [ "libbase", + "liblog", "libz", "slicer", ], diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index c08f9b04f0df..d3958a65c704 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -21,9 +21,16 @@ cc_binary_host { name: "stats-log-api-gen", srcs: [ "Collation.cpp", + "atoms_info_writer.cpp", + "java_writer.cpp", + "java_writer_q.cpp", "main.cpp", + "native_writer.cpp", + "native_writer_q.cpp", + "utils.cpp", ], cflags: [ + "-DSTATS_SCHEMA_LEGACY", "-Wall", "-Werror", ], @@ -98,28 +105,23 @@ genrule { cc_library { name: "libstatslog", host_supported: true, - generated_sources: ["statslog.cpp"], - generated_headers: ["statslog.h"], + generated_sources: [ + "statslog.cpp", + ], + generated_headers: [ + "statslog.h" + ], cflags: [ "-Wall", "-Werror", ], - export_generated_headers: ["statslog.h"], + export_generated_headers: [ + "statslog.h" + ], shared_libs: [ "liblog", "libcutils", ], static_libs: ["libstatssocket"], - target: { - android: { - shared_libs: [ - "libutils", - ], - }, - host: { - static_libs: [ - "libutils", - ], - }, - }, } + diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index 373adca994a1..fa556010646c 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -379,6 +379,7 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { int errorCount = 0; const bool dbg = false; + int maxPushedAtomId = 2; for (int i = 0; i < descriptor->field_count(); i++) { const FieldDescriptor *atomField = descriptor->field(i); @@ -447,8 +448,14 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { } atoms->non_chained_decls.insert(nonChainedAtomDecl); } + + if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) { + maxPushedAtomId = atomDecl.code; + } } + atoms->maxPushedAtomId = maxPushedAtomId; + if (dbg) { printf("signatures = [\n"); for (map<vector<java_type_t>, set<string>>::const_iterator it = diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index 44746c96df1b..3efdd520d7f5 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -111,6 +111,7 @@ struct Atoms { set<AtomDecl> decls; set<AtomDecl> non_chained_decls; map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules; + int maxPushedAtomId; }; /** @@ -123,4 +124,4 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, vector<java_type_t> } // namespace android -#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
\ No newline at end of file +#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp new file mode 100644 index 000000000000..54a9982bb5c2 --- /dev/null +++ b/tools/stats_log_api_gen/atoms_info_writer.cpp @@ -0,0 +1,227 @@ +/* + * 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. + */ + +#include "atoms_info_writer.h" +#include "utils.h" + +#include <map> +#include <set> +#include <vector> + +namespace android { +namespace stats_log_api_gen { + +static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) { + 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> " + "kTruncatingTimestampAtomBlackList;\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;\n"); + fprintf(out, + " const static std::set<int> kWhitelistedAtoms;\n"); + fprintf(out, "};\n"); + fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId); + +} + +static void write_atoms_info_cpp_body(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"}; + fprintf(out, + "const std::set<int> " + "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n"); + for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin(); + blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) { + fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str()); + } + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, + "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + string constant = make_constant_name(atom->name); + fprintf(out, " %s,\n", constant.c_str()); + break; + } + } + } + + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, + "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->whitelisted) { + string constant = make_constant_name(atom->name); + fprintf(out, " %s,\n", constant.c_str()); + } + } + + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, "static std::map<int, int> getAtomUidField() {\n"); + fprintf(out, " std::map<int, int> uidField;\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->uidField == 0) { + continue; + } + fprintf(out, + "\n // Adding uid field for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n", + make_constant_name(atom->name).c_str(), atom->uidField); + } + + fprintf(out, " return uidField;\n"); + fprintf(out, "};\n"); + + fprintf(out, + "const std::map<int, int> AtomsInfo::kAtomsWithUidField = " + "getAtomUidField();\n"); + + fprintf(out, + "static std::map<int, StateAtomFieldOptions> " + "getStateAtomFieldOptions() {\n"); + fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n"); + fprintf(out, " StateAtomFieldOptions opt;\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { + continue; + } + fprintf(out, + "\n // Adding primary and exclusive fields for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + fprintf(out, " opt.primaryFields.clear();\n"); + for (const auto& field : atom->primaryFields) { + fprintf(out, " opt.primaryFields.push_back(%d);\n", field); + } + + fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); + fprintf(out, " options[static_cast<int>(%s)] = opt;\n", + make_constant_name(atom->name).c_str()); + } + + fprintf(out, " return options;\n"); + fprintf(out, "}\n"); + + fprintf(out, + "const std::map<int, StateAtomFieldOptions> " + "AtomsInfo::kStateAtomsFieldOptions = " + "getStateAtomFieldOptions();\n"); + + fprintf(out, + "static std::map<int, std::vector<int>> " + "getBinaryFieldAtoms() {\n"); + fprintf(out, " std::map<int, std::vector<int>> options;\n"); + for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->binaryFields.size() == 0) { + continue; + } + fprintf(out, + "\n // Adding binary fields for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + + for (const auto& field : atom->binaryFields) { + fprintf(out, " options[static_cast<int>(%s)].push_back(%d);\n", + make_constant_name(atom->name).c_str(), field); + } + } + + fprintf(out, " return options;\n"); + fprintf(out, "}\n"); + + fprintf(out, + "const std::map<int, std::vector<int>> " + "AtomsInfo::kBytesFieldAtoms = " + "getBinaryFieldAtoms();\n"); + +} + +int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespaceStr) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "#pragma once\n"); + fprintf(out, "\n"); + fprintf(out, "#include <vector>\n"); + fprintf(out, "#include <map>\n"); + fprintf(out, "#include <set>\n"); + fprintf(out, "\n"); + + write_namespace(out, namespaceStr); + + write_atoms_info_header_body(out, atoms); + + fprintf(out, "\n"); + write_closing_namespace(out, namespaceStr); + + return 0; +} + +int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr, + const string& importHeader, const string& statslogHeader) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "#include <%s>\n", importHeader.c_str()); + fprintf(out, "#include <%s>\n", statslogHeader.c_str()); + fprintf(out, "\n"); + + write_namespace(out, namespaceStr); + + write_atoms_info_cpp_body(out, atoms); + + // Print footer + fprintf(out, "\n"); + write_closing_namespace(out, namespaceStr); + + return 0; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h new file mode 100644 index 000000000000..12ac862871ef --- /dev/null +++ b/tools/stats_log_api_gen/atoms_info_writer.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr, + const string& importHeader, const string& statslogHeader); + +int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp new file mode 100644 index 000000000000..fef490c7e5f9 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer.cpp @@ -0,0 +1,298 @@ +/* + * 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. + */ + +#include "java_writer.h" +#include "java_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +static int write_java_q_logger_class( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName + ) { + fprintf(out, "\n"); + fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n"); + fprintf(out, " private static class QLogger {\n"); + + write_java_q_logging_constants(out, " "); + + // Print Q write methods. + fprintf(out, "\n"); + fprintf(out, " // Write methods.\n"); + write_java_methods_q_schema( + out, signatures_to_modules, attributionDecl, moduleName, " "); + + fprintf(out, " }\n"); + return 0; +} + + +static int write_java_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName, + const bool supportQ + ) { + 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; + } + + // Print method signature. + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static void write(int code"); + vector<java_type_t> signature = signature_to_modules_it->first; + int argIndex = 1; + 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", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", SparseArray<Object> valueMap"); + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + // Print method body. + string indent(""); + if (supportQ) { + // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q. + fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n"); + fprintf(out, " Build.VERSION.CODENAME.equals(\"R\")) {\n"); + indent = " "; + } + + // Start StatsEvent.Builder. + fprintf(out, "%s final StatsEvent.Builder builder = StatsEvent.newBuilder();\n", + indent.c_str()); + + // Write atom code. + fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str()); + + // Write the args. + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_BOOLEAN: + fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_FLOAT: + fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_LONG: + fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_STRING: + fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n", + indent.c_str(), argIndex, argIndex); + break; + case JAVA_TYPE_ATTRIBUTION_CHAIN: + { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + + fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str()); + fprintf(out, "%s null == %s ? new int[0] : %s,\n", + indent.c_str(), uidName, uidName); + fprintf(out, "%s null == %s ? new String[0] : %s);\n", + indent.c_str(), tagName, tagName); + break; + } + case JAVA_TYPE_KEY_VALUE_PAIR: + fprintf(out, "\n"); + fprintf(out, + "%s // Write KeyValuePairs.\n", indent.c_str()); + fprintf(out, + "%s final int count = valueMap.size();\n", indent.c_str()); + fprintf(out, + "%s final SparseIntArray intMap = new SparseIntArray();\n", + indent.c_str()); + fprintf(out, + "%s final SparseLongArray longMap = new SparseLongArray();\n", + indent.c_str()); + fprintf(out, + "%s final SparseArray<String> stringMap = new SparseArray<>();\n", + indent.c_str()); + fprintf(out, + "%s final SparseArray<Float> floatMap = new SparseArray<>();\n", + indent.c_str()); + fprintf(out, + "%s for (int i = 0; i < count; i++) {\n", indent.c_str()); + fprintf(out, + "%s final int key = valueMap.keyAt(i);\n", indent.c_str()); + fprintf(out, + "%s final Object value = valueMap.valueAt(i);\n", + indent.c_str()); + fprintf(out, + "%s if (value instanceof Integer) {\n", indent.c_str()); + fprintf(out, + "%s intMap.put(key, (Integer) value);\n", indent.c_str()); + fprintf(out, + "%s } else if (value instanceof Long) {\n", indent.c_str()); + fprintf(out, + "%s longMap.put(key, (Long) value);\n", indent.c_str()); + fprintf(out, + "%s } else if (value instanceof String) {\n", indent.c_str()); + fprintf(out, + "%s stringMap.put(key, (String) value);\n", indent.c_str()); + fprintf(out, + "%s } else if (value instanceof Float) {\n", indent.c_str()); + fprintf(out, + "%s floatMap.put(key, (Float) value);\n", indent.c_str()); + fprintf(out, + "%s }\n", indent.c_str()); + fprintf(out, + "%s }\n", indent.c_str()); + fprintf(out, + "%s builder.writeKeyValuePairs(" + "intMap, longMap, stringMap, floatMap);\n", indent.c_str()); + break; + default: + // Unsupported types: OBJECT, DOUBLE. + fprintf(stderr, "Encountered unsupported type."); + return 1; + } + argIndex++; + } + + fprintf(out, "\n"); + fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str()); + fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str()); + + // Add support for writing using Q schema if this is not the default module. + if (supportQ) { + fprintf(out, " } else {\n"); + fprintf(out, " QLogger.write(code"); + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, ", %s, %s", uidName, tagName); + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + // Module logging does not yet support key value pair. + fprintf(stderr, "Module logging does not yet support key value pair.\n"); + return 1; + } else { + fprintf(out, ", arg%d", argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); // if + } + + fprintf(out, " }\n"); // method + fprintf(out, "\n"); + } + return 0; + +} + +int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& javaClass, + const string& javaPackage, const bool supportQ) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "package %s;\n", javaPackage.c_str()); + fprintf(out, "\n"); + fprintf(out, "\n"); + if (supportQ) { + fprintf(out, "import android.os.Build;\n"); + fprintf(out, "import android.os.SystemClock;\n"); + } + + if (DEFAULT_MODULE_NAME == moduleName) { + // Mainline modules don't use WorkSource logging. + fprintf(out, "import android.os.WorkSource;\n"); + + // SparseArray is used for writing KeyValuePairs; not supported for Mainline modules. + fprintf(out, "import android.util.SparseArray;\n"); + fprintf(out, "import android.util.SparseIntArray;\n"); + fprintf(out, "import android.util.SparseLongArray;\n"); + } + + fprintf(out, "import android.util.StatsEvent;\n"); + fprintf(out, "import android.util.StatsLog;\n"); + + if (DEFAULT_MODULE_NAME == moduleName) { + // List is used for WorkSource writing. Only needed for default module. + fprintf(out, "\n"); + fprintf(out, "import java.util.ArrayList;\n"); + } + + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "/**\n"); + fprintf(out, " * Utility class for logging statistics events.\n"); + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " * @hide\n"); + } + fprintf(out, " */\n"); + fprintf(out, "public class %s {\n", javaClass.c_str()); + + write_java_atom_codes(out, atoms, moduleName); + write_java_enum_values(out, atoms, moduleName); + + int errors = 0; + + // Print write methods. + fprintf(out, " // Write methods\n"); + errors += write_java_methods( + out, atoms.signatures_to_modules, attributionDecl, moduleName, supportQ); + errors += write_java_non_chained_methods( + out, atoms.non_chained_signatures_to_modules, moduleName); + if (DEFAULT_MODULE_NAME == moduleName) { + errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName); + } + + if (supportQ) { + errors += write_java_q_logger_class( + out, atoms.signatures_to_modules, attributionDecl, moduleName); + } + + fprintf(out, "}\n"); + + return errors; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h new file mode 100644 index 000000000000..9324b23e4025 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <map> +#include <set> +#include <vector> + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& javaClass, + const string& javaPackage, const bool supportQ); + +} // namespace stats_log_api_gen +} // namespace android + diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp new file mode 100644 index 000000000000..d6899f6131c6 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer_q.cpp @@ -0,0 +1,470 @@ +/* + * 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. + */ + +#include "java_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +void write_java_q_logging_constants(FILE* out, const string& indent) { + fprintf(out, "%s// Payload limits.\n", indent.c_str()); + fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str()); + fprintf(out, + "%sprivate static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n", + indent.c_str()); + + // Value types. Must match with EventLog.java and log.h. + fprintf(out, "\n"); + fprintf(out, "%s// Value types.\n", indent.c_str()); + fprintf(out, "%sprivate static final byte INT_TYPE = 0;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte LONG_TYPE = 1;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte STRING_TYPE = 2;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte LIST_TYPE = 3;\n", indent.c_str()); + fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str()); + + // Size of each value type. + // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value. + fprintf(out, "\n"); + fprintf(out, "%s// Size of each value type.\n", indent.c_str()); + fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str()); + fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str()); + // Longs take 9 bytes, 1 for the type and 8 for the value. + fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str()); + // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length. + fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str()); + fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str()); +} + +int write_java_methods_q_schema( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName, + const string& indent) { + int requiredHelpers = 0; + 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; + } + + // Print method signature. + vector<java_type_t> signature = signature_to_modules_it->first; + fprintf(out, "%spublic static void write(int code", indent.c_str()); + int argIndex = 1; + 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", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + // Module logging does not yet support key value pair. + fprintf(stderr, "Module logging does not yet support key value pair.\n"); + continue; + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + // Calculate the size of the buffer. + fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n", + indent.c_str()); + fprintf(out, + "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n", + indent.c_str()); + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_BOOLEAN: + case JAVA_TYPE_INT: + case JAVA_TYPE_FLOAT: + case JAVA_TYPE_ENUM: + fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_LONG: + // Longs take 9 bytes, 1 for the type and 8 for the value. + fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_STRING: + // Strings take 5 metadata bytes + length of byte encoded string. + fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); + fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, + "%s byte[] arg%dBytes = " + "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + // Byte arrays take 5 metadata bytes + length of byte array. + fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); + fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_ATTRIBUTION_CHAIN: + { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + // Null checks on the params. + fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName); + fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName, + java_type_name(attributionDecl.fields.front().javaType)); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName); + fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName, + java_type_name(attributionDecl.fields.back().javaType)); + fprintf(out, "%s }\n", indent.c_str()); + + // First check that the lengths of the uid and tag arrays are the same. + fprintf(out, "%s if (%s.length != %s.length) {\n", + indent.c_str(), uidName, tagName); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str()); + fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", + indent.c_str(), tagName); + fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n", + indent.c_str(), argIndex, tagName, tagName); + fprintf(out, + "%s int str%dlen = " + "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, + "%s attrSize += " + "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n", + indent.c_str(), argIndex); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s needed += attrSize;\n", indent.c_str()); + break; + } + default: + // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. + fprintf(stderr, "Module logging does not yet support key value pair.\n"); + return 1; + } + argIndex++; + } + + // Now we have the size that is needed. Check for overflow and return if needed. + fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s }\n", indent.c_str()); + + // Create new buffer, and associated data types. + fprintf(out, "%s byte[] buff = new byte[needed];\n", indent.c_str()); + fprintf(out, "%s int pos = 0;\n", indent.c_str()); + + // Initialize the buffer with list data type. + fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = %zu;\n", indent.c_str(), signature.size() + 2); + fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); + + // Write timestamp. + fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n", indent.c_str()); + fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str()); + fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); + + // Write atom code. + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, code);\n", indent.c_str()); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + + // Write the args. + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_BOOLEAN: + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", + indent.c_str(), argIndex); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_FLOAT: + requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; + fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); + fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_LONG: + fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); + fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); + break; + case JAVA_TYPE_STRING: + fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n", + indent.c_str(), argIndex); + fprintf(out, "%s System.arraycopy(" + "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", + indent.c_str(), argIndex); + fprintf(out, "%s System.arraycopy(" + "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n", + indent.c_str(), argIndex, argIndex); + fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", + indent.c_str(), argIndex); + break; + case JAVA_TYPE_ATTRIBUTION_CHAIN: + { + requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION; + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + + fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n", indent.c_str(), + uidName, tagName); + fprintf(out, "%s pos += attrSize;\n", indent.c_str()); + break; + } + default: + // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. + fprintf(stderr, + "Object, Double, and KeyValuePairs are not supported in module logging"); + return 1; + } + argIndex++; + } + + fprintf(out, "%s StatsLog.writeRaw(buff, pos);\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + } + + write_java_helpers_for_q_schema_methods(out, attributionDecl, requiredHelpers, indent); + + return 0; +} + +void write_java_helpers_for_q_schema_methods( + FILE* out, + const AtomDecl &attributionDecl, + const int requiredHelpers, + const string& indent) { + fprintf(out, "\n"); + fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str()); + fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n", + indent.c_str()); + fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + + fprintf(out, "%sprivate static void copyLong(byte[] buff, int pos, long val) {\n", + indent.c_str()); + fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 4] = (byte) (val >> 32);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 5] = (byte) (val >> 40);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 6] = (byte) (val >> 48);\n", indent.c_str()); + fprintf(out, "%s buff[pos + 7] = (byte) (val >> 56);\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + + if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) { + fprintf(out, "%sprivate static void copyFloat(byte[] buff, int pos, float val) {\n", + indent.c_str()); + fprintf(out, "%s copyInt(buff, pos, Float.floatToIntBits(val));\n", indent.c_str()); + fprintf(out, "%s return;\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + } + + if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) { + fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos", + indent.c_str()); + for (auto chainField : attributionDecl.fields) { + fprintf(out, ", %s[] %s", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + fprintf(out, ") {\n"); + + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + + // Write the first list begin. + fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = (byte) (%s.length);\n", indent.c_str(), tagName); + fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); + + // Iterate through the attribution chain and write the nodes. + fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName); + // Write the list begin. + fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); + fprintf(out, "%s buff[pos + 1] = %lu;\n", + indent.c_str(), attributionDecl.fields.size()); + fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); + + // Write the uid. + fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, %s[i]);\n", indent.c_str(), uidName); + fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); + + // Write the tag. + fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", + indent.c_str(), tagName, tagName, tagName); + fprintf(out, "%s byte[] %sByte = " + "%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", + indent.c_str(), tagName, tagName); + fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); + fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName); + fprintf(out, "%s System.arraycopy(" + "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n", + indent.c_str(), tagName, tagName); + fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", + indent.c_str(), tagName); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "\n"); + } +} + +#if defined(STATS_SCHEMA_LEGACY) +static void write_java_method( + 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++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + fprintf(out, ", %s[] %s", + java_type_name(chainField.javaType), chainField.name.c_str()); + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", SparseArray<Object> value_map"); + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); + fprintf(out, "\n"); + } +} + +int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "package android.util;\n"); + fprintf(out, "\n"); + fprintf(out, "import android.os.WorkSource;\n"); + fprintf(out, "import android.util.SparseArray;\n"); + fprintf(out, "import java.util.ArrayList;\n"); + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "/**\n"); + fprintf(out, " * API For logging statistics events.\n"); + fprintf(out, " * @hide\n"); + fprintf(out, " */\n"); + fprintf(out, "public class StatsLogInternal {\n"); + write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME); + + write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME); + + // Print write methods + fprintf(out, " // Write methods\n"); + 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_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME); + + fprintf(out, "}\n"); + + return 0; +} + +int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& javaClass, + const string& javaPackage) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + fprintf(out, "package %s;\n", javaPackage.c_str()); + fprintf(out, "\n"); + fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n"); + fprintf(out, "\n"); + fprintf(out, "import android.util.StatsLog;\n"); + fprintf(out, "import android.os.SystemClock;\n"); + fprintf(out, "\n"); + fprintf(out, "import java.util.ArrayList;\n"); + fprintf(out, "\n"); + fprintf(out, "\n"); + fprintf(out, "/**\n"); + fprintf(out, " * Utility class for logging statistics events.\n"); + fprintf(out, " */\n"); + fprintf(out, "public class %s {\n", javaClass.c_str()); + + write_java_q_logging_constants(out, " "); + + write_java_atom_codes(out, atoms, moduleName); + + write_java_enum_values(out, atoms, moduleName); + + int errors = 0; + // Print write methods + fprintf(out, " // Write methods\n"); + errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl, + moduleName, " "); + errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules, + moduleName); + + fprintf(out, "}\n"); + + return errors; +} +#endif + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h new file mode 100644 index 000000000000..96ac745beef8 --- /dev/null +++ b/tools/stats_log_api_gen/java_writer_q.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <map> +#include <set> +#include <vector> + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +void write_java_q_logging_constants(FILE* out, const string& indent); + +int write_java_methods_q_schema( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const AtomDecl &attributionDecl, + const string& moduleName, + const string& indent); + +void write_java_helpers_for_q_schema_methods( + FILE * out, + const AtomDecl &attributionDecl, + const int requiredHelpers, + const string& indent); + +#if defined(STATS_SCHEMA_LEGACY) +int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl); + +int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, + const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass, + const string& javaPackage); +#endif +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index f62fef076f48..00a370484823 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -1,9 +1,17 @@ #include "Collation.h" +#include "atoms_info_writer.h" +#if !defined(STATS_SCHEMA_LEGACY) +#include "java_writer.h" +#endif +#include "java_writer_q.h" +#include "native_writer.h" +#include "utils.h" #include "frameworks/base/cmds/statsd/src/atoms.pb.h" +#include <map> #include <set> #include <vector> @@ -12,1490 +20,19 @@ #include <stdlib.h> #include <string.h> -#include "android-base/strings.h" - using namespace google::protobuf; using namespace std; namespace android { namespace stats_log_api_gen { -int maxPushedAtomId = 2; - -const string DEFAULT_MODULE_NAME = "DEFAULT"; -const string DEFAULT_CPP_NAMESPACE = "android,util"; -const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; -const string DEFAULT_JAVA_PACKAGE = "android.util"; -const string DEFAULT_JAVA_CLASS = "StatsLogInternal"; - -const int JAVA_MODULE_REQUIRES_FLOAT = 0x01; -const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02; - using android::os::statsd::Atom; -/** - * Turn lower and camel case into upper case with underscores. - */ -static string -make_constant_name(const string& str) -{ - string result; - const int N = str.size(); - bool underscore_next = false; - for (int i=0; i<N; i++) { - char c = str[i]; - if (c >= 'A' && c <= 'Z') { - if (underscore_next) { - result += '_'; - underscore_next = false; - } - } else if (c >= 'a' && c <= 'z') { - c = 'A' + c - 'a'; - underscore_next = true; - } else if (c == '_') { - underscore_next = false; - } - result += c; - } - return result; -} - -static const char* -cpp_type_name(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "bool"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "int32_t"; - case JAVA_TYPE_LONG: - return "int64_t"; - case JAVA_TYPE_FLOAT: - return "float"; - case JAVA_TYPE_DOUBLE: - return "double"; - case JAVA_TYPE_STRING: - return "char const*"; - case JAVA_TYPE_BYTE_ARRAY: - return "const BytesField&"; - default: - return "UNKNOWN"; - } -} - -static const char* -java_type_name(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "boolean"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "int"; - case JAVA_TYPE_LONG: - return "long"; - case JAVA_TYPE_FLOAT: - return "float"; - case JAVA_TYPE_DOUBLE: - return "double"; - case JAVA_TYPE_STRING: - return "java.lang.String"; - case JAVA_TYPE_BYTE_ARRAY: - return "byte[]"; - default: - return "UNKNOWN"; - } -} - -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); -} - -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"}; - fprintf(out, - "const std::set<int> " - "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n"); - for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin(); - blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) { - fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str()); - } - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, - "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - break; - } - } - } - - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, - "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->whitelisted) { - string constant = make_constant_name(atom->name); - fprintf(out, " %s,\n", constant.c_str()); - } - } - - fprintf(out, "};\n"); - fprintf(out, "\n"); - - fprintf(out, "static std::map<int, int> getAtomUidField() {\n"); - fprintf(out, " std::map<int, int> uidField;\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->uidField == 0) { - continue; - } - fprintf(out, - "\n // Adding uid field for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n", - make_constant_name(atom->name).c_str(), atom->uidField); - } - - fprintf(out, " return uidField;\n"); - fprintf(out, "};\n"); - - fprintf(out, - "const std::map<int, int> AtomsInfo::kAtomsWithUidField = " - "getAtomUidField();\n"); - - fprintf(out, - "static std::map<int, StateAtomFieldOptions> " - "getStateAtomFieldOptions() {\n"); - fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n"); - fprintf(out, " StateAtomFieldOptions opt;\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { - continue; - } - fprintf(out, - "\n // Adding primary and exclusive fields for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - fprintf(out, " opt.primaryFields.clear();\n"); - for (const auto& field : atom->primaryFields) { - fprintf(out, " opt.primaryFields.push_back(%d);\n", field); - } - - fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField); - fprintf(out, " options[static_cast<int>(%s)] = opt;\n", - make_constant_name(atom->name).c_str()); - } - - fprintf(out, " return options;\n"); - fprintf(out, "}\n"); - - fprintf(out, - "const std::map<int, StateAtomFieldOptions> " - "AtomsInfo::kStateAtomsFieldOptions = " - "getStateAtomFieldOptions();\n"); - - fprintf(out, - "static std::map<int, std::vector<int>> " - "getBinaryFieldAtoms() {\n"); - fprintf(out, " std::map<int, std::vector<int>> options;\n"); - for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); - atom != atoms.decls.end(); atom++) { - if (atom->binaryFields.size() == 0) { - continue; - } - fprintf(out, - "\n // Adding binary fields for atom " - "(%d)%s\n", - atom->code, atom->name.c_str()); - - for (const auto& field : atom->binaryFields) { - fprintf(out, " options[static_cast<int>(%s)].push_back(%d);\n", - make_constant_name(atom->name).c_str(), field); - } - } - - fprintf(out, " return options;\n"); - fprintf(out, "}\n"); - - fprintf(out, - "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"); - fprintf(out, "static std::mutex mLogdRetryMutex;\n"); - - // Print write methods - fprintf(out, "\n"); - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - argIndex = 1; - fprintf(out, " if (kStatsdEnabled) {\n"); - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (const auto &chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " if (%s_length != %s.size()) {\n", - attributionDecl.fields.front().name.c_str(), chainField.name.c_str()); - fprintf(out, " return -EINVAL;\n"); - fprintf(out, " }\n"); - } - } - fprintf(out, "\n event.begin();\n"); - fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n", - attributionDecl.fields.front().name.c_str()); - fprintf(out, " event.begin();\n"); - for (const auto &chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str()); - fprintf(out, " event << %s[i];\n", chainField.name.c_str()); - fprintf(out, " } else {\n"); - fprintf(out, " event << \"\";\n"); - fprintf(out, " }\n"); - } else { - fprintf(out, " event << %s[i];\n", chainField.name.c_str()); - } - } - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - fprintf(out, " event.end();\n\n"); - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, " event.begin();\n\n"); - fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " event.end();\n\n"); - } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, - " event.AppendCharArray(arg%d.arg, " - "arg%d.arg_length);\n", - argIndex, argIndex); - } else { - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (arg%d == NULL) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - } - fprintf(out, " event << arg%d;\n", argIndex); - } - argIndex++; - } - - fprintf(out, " return event.write(LOG_ID_STATS);\n"); - fprintf(out, " } else {\n"); - fprintf(out, " return 1;\n"); - fprintf(out, " }\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, - ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - fprintf(out, " int ret = 0;\n"); - - fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n"); - fprintf(out, " ret = try_stats_write(code"); - - argIndex = 1; - 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) { - fprintf(out, ", %s", - chainField.name.c_str()); - } else { - fprintf(out, ", %s, %s_length", - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, - argIndex, argIndex, argIndex); - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " if (ret >= 0) { break; }\n"); - - fprintf(out, " {\n"); - fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n"); - fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= " - "kMinRetryIntervalNs) break;\n"); - fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n"); - fprintf(out, " }\n"); - fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n"); - fprintf(out, " }\n"); - fprintf(out, " if (ret < 0) {\n"); - fprintf(out, " note_log_drop(ret, code);\n"); - fprintf(out, " }\n"); - fprintf(out, " return ret;\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - 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++) { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - argIndex = 1; - fprintf(out, " if (kStatsdEnabled) {\n"); - 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++) { - if (argIndex == 1) { - fprintf(out, " event.begin();\n\n"); - fprintf(out, " event.begin();\n"); - } - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (arg%d == NULL) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - } - if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, - " event.AppendCharArray(arg%d.arg, " - "arg%d.arg_length);", - argIndex, argIndex); - } else { - fprintf(out, " event << arg%d;\n", argIndex); - } - if (argIndex == 2) { - fprintf(out, " event.end();\n\n"); - fprintf(out, " event.end();\n\n"); - } - argIndex++; - } - - fprintf(out, " return event.write(LOG_ID_STATS);\n"); - fprintf(out, " } else {\n"); - fprintf(out, " return 1;\n"); - fprintf(out, " }\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - 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++) { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - - fprintf(out, " int ret = 0;\n"); - fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n"); - 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++) { - fprintf(out, ", arg%d", argIndex); - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " if (ret >= 0) { break; }\n"); - - fprintf(out, " {\n"); - fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n"); - fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= " - "kMinRetryIntervalNs) break;\n"); - fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n"); - fprintf(out, " }\n"); - - fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n"); - fprintf(out, " }\n"); - fprintf(out, " if (ret < 0) {\n"); - fprintf(out, " note_log_drop(ret, code);\n"); - fprintf(out, " }\n"); - fprintf(out, " return ret;\n\n"); - fprintf(out, "}\n"); - - fprintf(out, "\n"); - } - - - // Print footer - fprintf(out, "\n"); - write_closing_namespace(out, cppNamespace); - - return 0; -} - -void build_non_chained_decl_map(const Atoms& atoms, - std::map<int, set<AtomDecl>::const_iterator>* decl_map){ - for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin(); - atom != atoms.non_chained_decls.end(); atom++) { - decl_map->insert(std::make_pair(atom->code, atom)); - } -} - -static void write_cpp_usage( - FILE* out, const string& method_name, const string& atom_code_name, - const AtomDecl& atom, const AtomDecl &attributionDecl) { - fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), - atom_code_name.c_str()); - - for (vector<AtomField>::const_iterator field = atom.fields.begin(); - field != atom.fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), - chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int32_t>& %s_int" - ", const std::map<int, int64_t>& %s_long" - ", const std::map<int, char const*>& %s_str" - ", const std::map<int, float>& %s_float", - field->name.c_str(), - field->name.c_str(), - field->name.c_str(), - field->name.c_str()); - } else { - fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); - } - } - fprintf(out, ");\n"); -} - -static void write_cpp_method_header( - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", const std::vector<%s>& %s", - cpp_type_name(chainField.javaType), chainField.name.c_str()); - } else { - fprintf(out, ", const %s* %s, size_t %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " - "const std::map<int, int64_t>& arg%d_2, " - "const std::map<int, char const*>& arg%d_3, " - "const std::map<int, float>& arg%d_4", - argIndex, argIndex, argIndex, argIndex); - } else { - fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - - } -} - -static int -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"); - fprintf(out, "\n"); - fprintf(out, "#pragma once\n"); - fprintf(out, "\n"); - fprintf(out, "#include <stdint.h>\n"); - fprintf(out, "#include <vector>\n"); - fprintf(out, "#include <map>\n"); - fprintf(out, "#include <set>\n"); - fprintf(out, "\n"); - - write_namespace(out, cppNamespace); - fprintf(out, "\n"); - fprintf(out, "/*\n"); - fprintf(out, " * API For logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * Constants for atom codes.\n"); - fprintf(out, " */\n"); - fprintf(out, "enum {\n"); - - std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; - build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); - - size_t i = 0; - // Print atom 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"); - fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str()); - write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl); - - auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); - if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { - write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second, - attributionDecl); - } - fprintf(out, " */\n"); - char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; - fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma); - if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) { - maxPushedAtomId = atom->code; - } - i++; - } - fprintf(out, "\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); - - // Print constants for the enum values. - fprintf(out, "//\n"); - fprintf(out, "// Constants for enum values\n"); - fprintf(out, "//\n\n"); - 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; - } - - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ENUM) { - fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), - field->name.c_str()); - for (map<int, string>::const_iterator value = field->enumValues.begin(); - value != field->enumValues.end(); value++) { - fprintf(out, "const int32_t %s__%s__%s = %d;\n", - make_constant_name(atom->message).c_str(), - make_constant_name(field->name).c_str(), - make_constant_name(value->second).c_str(), - value->first); - } - fprintf(out, "\n"); - } - } - } - - fprintf(out, "struct BytesField {\n"); - fprintf(out, - " BytesField(char const* array, size_t len) : arg(array), " - "arg_length(len) {}\n"); - fprintf(out, " char const* arg;\n"); - fprintf(out, " size_t arg_length;\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 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> " - "kTruncatingTimestampAtomBlackList;\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, - " const static std::set<int> kWhitelistedAtoms;\n"); - fprintf(out, "};\n"); - - 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_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_to_modules, - attributionDecl, moduleName); - - fprintf(out, "\n"); - write_closing_namespace(out, cppNamespace); - - return 0; -} - -static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, - const AtomDecl& atom) { - fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", - method_name.c_str(), atom_code_name.c_str()); - for (vector<AtomField>::const_iterator field = atom.fields.begin(); - field != atom.fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(out, ", android.os.WorkSource workSource"); - } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", SparseArray<Object> value_map"); - } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, ", byte[] %s", field->name.c_str()); - } else { - fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str()); - } - } - fprintf(out, ");<br>\n"); -} - -static void write_java_method( - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", SparseArray<Object> value_map"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - } -} - -static void write_java_helpers_for_module( - FILE * out, - const AtomDecl &attributionDecl, - const int requiredHelpers) { - fprintf(out, " private static void copyInt(byte[] buff, int pos, int val) {\n"); - fprintf(out, " buff[pos] = (byte) (val);\n"); - fprintf(out, " buff[pos + 1] = (byte) (val >> 8);\n"); - fprintf(out, " buff[pos + 2] = (byte) (val >> 16);\n"); - fprintf(out, " buff[pos + 3] = (byte) (val >> 24);\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - - fprintf(out, " private static void copyLong(byte[] buff, int pos, long val) {\n"); - fprintf(out, " buff[pos] = (byte) (val);\n"); - fprintf(out, " buff[pos + 1] = (byte) (val >> 8);\n"); - fprintf(out, " buff[pos + 2] = (byte) (val >> 16);\n"); - fprintf(out, " buff[pos + 3] = (byte) (val >> 24);\n"); - fprintf(out, " buff[pos + 4] = (byte) (val >> 32);\n"); - fprintf(out, " buff[pos + 5] = (byte) (val >> 40);\n"); - fprintf(out, " buff[pos + 6] = (byte) (val >> 48);\n"); - fprintf(out, " buff[pos + 7] = (byte) (val >> 56);\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - - if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) { - fprintf(out, " private static void copyFloat(byte[] buff, int pos, float val) {\n"); - fprintf(out, " copyInt(buff, pos, Float.floatToIntBits(val));\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - - if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) { - fprintf(out, " private static void writeAttributionChain(byte[] buff, int pos"); - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - fprintf(out, ") {\n"); - - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - // Write the first list begin. - fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = (byte) (%s.length);\n", tagName); - fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); - - // Iterate through the attribution chain and write the nodes. - fprintf(out, " for (int i = 0; i < %s.length; i++) {\n", tagName); - // Write the list begin. - fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = %lu;\n", attributionDecl.fields.size()); - fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); - - // Write the uid. - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, %s[i]);\n", uidName); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - - // Write the tag. - fprintf(out, " String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", - tagName, tagName, tagName); - fprintf(out, " byte[] %sByte = %sStr.getBytes(UTF_8);\n", tagName, tagName); - fprintf(out, " buff[pos] = STRING_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, %sByte.length);\n", tagName); - fprintf(out, " System.arraycopy(" - "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n", - tagName, tagName); - fprintf(out, " pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", tagName); - fprintf(out, " }\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } -} - - -static int write_java_non_chained_method_for_module( - FILE* out, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - 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; - } - - // Print method signature. - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, " public static void write_non_chained(int code"); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - // Non chained signatures should not have attribution chains. - return 1; - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - // Module logging does not yet support key value pair. - return 1; - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - fprintf(out, " write(code"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - // First two args are uid and tag of attribution chain. - if (argIndex == 1) { - fprintf(out, ", new int[] {arg%d}", argIndex); - } else if (argIndex == 2) { - fprintf(out, ", new java.lang.String[] {arg%d}", argIndex); - } else { - fprintf(out, ", arg%d", argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - return 0; -} - -static int write_java_method_for_module( - FILE* out, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl, - const string& moduleName, - int* requiredHelpers - ) { - - 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; - } - - // Print method signature. - vector<java_type_t> signature = signature_to_modules_it->first; - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - // Module logging does not yet support key value pair. - return 1; - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // Calculate the size of the buffer. - fprintf(out, " // Initial overhead of the list, timestamp, and atom tag.\n"); - fprintf(out, " int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n"); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - case JAVA_TYPE_INT: - case JAVA_TYPE_FLOAT: - case JAVA_TYPE_ENUM: - fprintf(out, " needed += INT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_LONG: - // Longs take 9 bytes, 1 for the type and 8 for the value. - fprintf(out, " needed += LONG_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_STRING: - // Strings take 5 metadata bytes + length of byte encoded string. - fprintf(out, " if (arg%d == null) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - fprintf(out, " byte[] arg%dBytes= arg%d.getBytes(UTF_8);\n", - argIndex, argIndex); - fprintf(out, " needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", - argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - // Byte arrays take 5 metadata bytes + length of byte array. - fprintf(out, " if (arg%d == null) {\n", argIndex); - fprintf(out, " arg%d = new byte[0];\n", argIndex); - fprintf(out, " }\n"); - fprintf(out, " needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: - { - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - // Null checks on the params. - fprintf(out, " if (%s == null) {\n", uidName); - fprintf(out, " %s = new %s[0];\n", uidName, - java_type_name(attributionDecl.fields.front().javaType)); - fprintf(out, " }\n"); - fprintf(out, " if (%s == null) {\n", tagName); - fprintf(out, " %s = new %s[0];\n", tagName, - java_type_name(attributionDecl.fields.back().javaType)); - fprintf(out, " }\n"); - - // First check that the lengths of the uid and tag arrays are the same. - fprintf(out, " if (%s.length != %s.length) {\n", uidName, tagName); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - fprintf(out, " int attrSize = LIST_TYPE_OVERHEAD;\n"); - fprintf(out, " for (int i = 0; i < %s.length; i++) {\n", tagName); - fprintf(out, " String str%d = (%s[i] == null) ? \"\" : %s[i];\n", - argIndex, tagName, tagName); - fprintf(out, " int str%dlen = str%d.getBytes(UTF_8).length;\n", - argIndex, argIndex); - fprintf(out, - " attrSize += " - "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n", - argIndex); - fprintf(out, " }\n"); - fprintf(out, " needed += attrSize;\n"); - break; - } - default: - // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. - return 1; - } - argIndex++; - } - - // Now we have the size that is needed. Check for overflow and return if needed. - fprintf(out, " if (needed > MAX_EVENT_PAYLOAD) {\n"); - fprintf(out, " return;\n"); - fprintf(out, " }\n"); - - // Create new buffer, and associated data types. - fprintf(out, " byte[] buff = new byte[needed];\n"); - fprintf(out, " int pos = 0;\n"); - - // Initialize the buffer with list data type. - fprintf(out, " buff[pos] = LIST_TYPE;\n"); - fprintf(out, " buff[pos + 1] = %zu;\n", signature.size() + 2); - fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n"); - - // Write timestamp. - fprintf(out, " long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n"); - fprintf(out, " buff[pos] = LONG_TYPE;\n"); - fprintf(out, " copyLong(buff, pos + 1, elapsedRealtime);\n"); - fprintf(out, " pos += LONG_TYPE_SIZE;\n"); - - // Write atom code. - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, code);\n"); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - - // Write the args. - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%d? 1 : 0);\n", argIndex); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - fprintf(out, " buff[pos] = INT_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%d);\n", argIndex); - fprintf(out, " pos += INT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_FLOAT: - *requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; - fprintf(out, " buff[pos] = FLOAT_TYPE;\n"); - fprintf(out, " copyFloat(buff, pos + 1, arg%d);\n", argIndex); - fprintf(out, " pos += FLOAT_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_LONG: - fprintf(out, " buff[pos] = LONG_TYPE;\n"); - fprintf(out, " copyLong(buff, pos + 1, arg%d);\n", argIndex); - fprintf(out, " pos += LONG_TYPE_SIZE;\n"); - break; - case JAVA_TYPE_STRING: - fprintf(out, " buff[pos] = STRING_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%dBytes.length);\n", argIndex); - fprintf(out, " System.arraycopy(" - "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n", - argIndex, argIndex); - fprintf(out, " pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", - argIndex); - break; - case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, " buff[pos] = STRING_TYPE;\n"); - fprintf(out, " copyInt(buff, pos + 1, arg%d.length);\n", argIndex); - fprintf(out, " System.arraycopy(" - "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n", - argIndex, argIndex); - fprintf(out, " pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex); - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: - { - *requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION; - const char* uidName = attributionDecl.fields.front().name.c_str(); - const char* tagName = attributionDecl.fields.back().name.c_str(); - - fprintf(out, " writeAttributionChain(buff, pos, %s, %s);\n", - uidName, tagName); - fprintf(out, " pos += attrSize;\n"); - break; - } - default: - // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR. - return 1; - } - argIndex++; - } - - fprintf(out, " StatsLog.writeRaw(buff, pos);\n"); - fprintf(out, " }\n"); - fprintf(out, "\n"); - } - return 0; -} - -static void write_java_work_source_method(FILE* out, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const string& moduleName) { - fprintf(out, "\n // WorkSource methods.\n"); - 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; - // 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++) { - argIndexMax++; - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - if (attributionArg > -1) { - fprintf(stderr, "An atom contains multiple AttributionNode fields.\n"); - fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n"); - fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n"); - return; - } - attributionArg = argIndexMax; - } - } - if (attributionArg < 0) { - continue; - } - - // Method header (signature) - if (moduleName == DEFAULT_MODULE_NAME) { - 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++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - fprintf(out, ", WorkSource ws"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ") {\n"); - - // write_non_chained() component. TODO: Remove when flat uids are no longer needed. - fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n"); - fprintf(out, " write_non_chained(code"); - for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { - if (argIndex == attributionArg) { - fprintf(out, ", ws.get(i), ws.getName(i)"); - } else { - fprintf(out, ", arg%d", argIndex); - } - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // close for-loop - - // write() component. - fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n"); - fprintf(out, " if (workChains != null) {\n"); - fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n"); - fprintf(out, " write(code"); - for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { - if (argIndex == attributionArg) { - fprintf(out, ", wc.getUids(), wc.getTags()"); - } else { - fprintf(out, ", arg%d", argIndex); - } - } - fprintf(out, ");\n"); - fprintf(out, " }\n"); // close for-loop - fprintf(out, " }\n"); // close if - fprintf(out, " }\n"); // close method - } -} - -static void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) { - fprintf(out, " // Constants for atom codes.\n"); - - std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; - build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); - - // Print constants for the atom codes. - 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"); - fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str()); - write_java_usage(out, "write", constant, *atom); - auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); - if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { - write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second); - } - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " * @hide\n"); - } - fprintf(out, " */\n"); - fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code); - } - fprintf(out, "\n"); -} - -static void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) { - fprintf(out, " // Constants for enum values.\n\n"); - 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; - } - for (vector<AtomField>::const_iterator field = atom->fields.begin(); - field != atom->fields.end(); field++) { - if (field->javaType == JAVA_TYPE_ENUM) { - fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), - field->name.c_str()); - for (map<int, string>::const_iterator value = field->enumValues.begin(); - value != field->enumValues.end(); value++) { - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " /** @hide */\n"); - } - fprintf(out, " public static final int %s__%s__%s = %d;\n", - make_constant_name(atom->message).c_str(), - make_constant_name(field->name).c_str(), - make_constant_name(value->second).c_str(), - value->first); - } - fprintf(out, "\n"); - } - } - } -} - -static int -write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) -{ - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package android.util;\n"); - fprintf(out, "\n"); - fprintf(out, "import android.os.WorkSource;\n"); - fprintf(out, "import android.util.SparseArray;\n"); - fprintf(out, "import java.util.ArrayList;\n"); - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * API For logging statistics events.\n"); - fprintf(out, " * @hide\n"); - fprintf(out, " */\n"); - fprintf(out, "public class StatsLogInternal {\n"); - write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME); - - write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME); - - // Print write methods - fprintf(out, " // Write methods\n"); - 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, DEFAULT_MODULE_NAME); - - fprintf(out, "}\n"); - - return 0; -} - -// TODO: Merge this with write_stats_log_java so that we can get rid of StatsLogInternal JNI. -static int -write_stats_log_java_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, - const string& moduleName, const string& javaClass, const string& javaPackage) -{ - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package %s;\n", javaPackage.c_str()); - fprintf(out, "\n"); - fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n"); - fprintf(out, "\n"); - fprintf(out, "import android.util.StatsLog;\n"); - fprintf(out, "import android.os.SystemClock;\n"); - fprintf(out, "\n"); - fprintf(out, "import java.util.ArrayList;\n"); - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * Utility class for logging statistics events.\n"); - fprintf(out, " */\n"); - fprintf(out, "public class %s {\n", javaClass.c_str()); - - // TODO: ideally these match with the native values (and automatically change if they change). - fprintf(out, " private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n"); - fprintf(out, - " private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n"); - // Value types. Must match with EventLog.java and log.h. - fprintf(out, " private static final byte INT_TYPE = 0;\n"); - fprintf(out, " private static final byte LONG_TYPE = 1;\n"); - fprintf(out, " private static final byte STRING_TYPE = 2;\n"); - fprintf(out, " private static final byte LIST_TYPE = 3;\n"); - fprintf(out, " private static final byte FLOAT_TYPE = 4;\n"); - - // Size of each value type. - // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value. - fprintf(out, " private static final int INT_TYPE_SIZE = 5;\n"); - fprintf(out, " private static final int FLOAT_TYPE_SIZE = 5;\n"); - // Longs take 9 bytes, 1 for the type and 8 for the value. - fprintf(out, " private static final int LONG_TYPE_SIZE = 9;\n"); - // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length. - fprintf(out, " private static final int STRING_TYPE_OVERHEAD = 5;\n"); - fprintf(out, " private static final int LIST_TYPE_OVERHEAD = 2;\n"); - - write_java_atom_codes(out, atoms, moduleName); - - write_java_enum_values(out, atoms, moduleName); - - int errors = 0; - int requiredHelpers = 0; - // Print write methods - fprintf(out, " // Write methods\n"); - errors += write_java_method_for_module(out, atoms.signatures_to_modules, attributionDecl, - moduleName, &requiredHelpers); - errors += write_java_non_chained_method_for_module(out, atoms.non_chained_signatures_to_modules, - moduleName); - - fprintf(out, " // Helper methods for copying primitives\n"); - write_java_helpers_for_module(out, attributionDecl, requiredHelpers); - - fprintf(out, "}\n"); - - return errors; -} - +// Hide the JNI write helpers that are not used in the new schema. +// TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is +// complete. +#if defined(STATS_SCHEMA_LEGACY) +// JNI helpers. static const char* jni_type_name(java_type_t type) { @@ -1666,7 +203,7 @@ static void write_key_value_map_jni(FILE* out) { } static int -write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name, +write_stats_log_jni_method(FILE* out, const string& java_method_name, const string& cpp_method_name, const map<vector<java_type_t>, set<string>>& signatures_to_modules, const AtomDecl &attributionDecl) { // Print write methods @@ -1882,40 +419,56 @@ void write_jni_registration(FILE* out, const string& java_method_name, jni_function_name(java_method_name, signature).c_str()); } } +#endif // JNI helpers. static int +#if defined(STATS_SCHEMA_LEGACY) write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) +#else +// Write empty JNI file that doesn't contain any JNI methods. +// TODO(b/145100015): remove this function and all JNI autogen code once StatsEvent migration is +// complete. +write_stats_log_jni(FILE* out) +#endif { // Print prelude fprintf(out, "// This file is autogenerated\n"); fprintf(out, "\n"); +#if defined(STATS_SCHEMA_LEGACY) fprintf(out, "#include <statslog.h>\n"); fprintf(out, "\n"); fprintf(out, "#include <nativehelper/JNIHelp.h>\n"); fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n"); fprintf(out, "#include <utils/Vector.h>\n"); +#endif fprintf(out, "#include \"core_jni_helpers.h\"\n"); fprintf(out, "#include \"jni.h\"\n"); fprintf(out, "\n"); +#if defined(STATS_SCHEMA_LEGACY) fprintf(out, "#define UNUSED __attribute__((__unused__))\n"); fprintf(out, "\n"); +#endif fprintf(out, "namespace android {\n"); fprintf(out, "\n"); - 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", +#if defined(STATS_SCHEMA_LEGACY) + write_stats_log_jni_method(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl); + write_stats_log_jni_method(out, "write_non_chained", "stats_write_non_chained", atoms.non_chained_signatures_to_modules, attributionDecl); +#endif // Print registration function table fprintf(out, "/*\n"); fprintf(out, " * JNI registration.\n"); fprintf(out, " */\n"); fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n"); +#if defined(STATS_SCHEMA_LEGACY) write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl); write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules, attributionDecl); +#endif fprintf(out, "};\n"); fprintf(out, "\n"); @@ -1938,20 +491,28 @@ print_usage() fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n"); fprintf(stderr, "\n"); fprintf(stderr, "OPTIONS\n"); - fprintf(stderr, " --cpp FILENAME the header file to output\n"); - fprintf(stderr, " --header FILENAME the cpp file to output\n"); + fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n"); + fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n"); + fprintf(stderr, + " --atomsInfoCpp FILENAME the header file to output for statsd metadata\n"); + fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n"); 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"); + fprintf(stderr," --importHeader NAME required for cpp/jni to say which header to import " + "for write helpers\n"); + fprintf(stderr," --atomsInfoImportHeader NAME required for cpp to say which header to import " + "for statsd metadata\n"); fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n"); fprintf(stderr, " required for java with module\n"); fprintf(stderr, " --javaClass CLASS the class name of the java class.\n"); fprintf(stderr, " Optional for Java with module.\n"); - fprintf(stderr, " Default is \"StatsLogInternal\"\n");} + fprintf(stderr, " Default is \"StatsLogInternal\"\n"); + fprintf(stderr, " --supportQ Include support for Android Q.\n"); +} /** * Do the argument parsing and execute the tasks. @@ -1963,12 +524,16 @@ run(int argc, char const*const* argv) string headerFilename; string javaFilename; string jniFilename; + string atomsInfoCppFilename; + string atomsInfoHeaderFilename; string moduleName = DEFAULT_MODULE_NAME; string cppNamespace = DEFAULT_CPP_NAMESPACE; string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT; + string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT; string javaPackage = DEFAULT_JAVA_PACKAGE; string javaClass = DEFAULT_JAVA_CLASS; + bool supportQ = false; int index = 1; while (index < argc) { @@ -2038,18 +603,50 @@ run(int argc, char const*const* argv) return 1; } javaClass = argv[index]; + } else if (0 == strcmp("--atomsInfoHeader", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + atomsInfoHeaderFilename = argv[index]; + } else if (0 == strcmp("--atomsInfoCpp", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + atomsInfoCppFilename = argv[index]; + } else if (0 == strcmp("--atomsInfoImportHeader", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + atomsInfoCppHeaderImport = argv[index]; + } else if (0 == strcmp("--supportQ", argv[index])) { + supportQ = true; } + index++; } if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0 - && jniFilename.size() == 0) { + && jniFilename.size() == 0 + && atomsInfoHeaderFilename.size() == 0 + && atomsInfoCppFilename.size() == 0) { print_usage(); return 1; } + if (DEFAULT_MODULE_NAME == moduleName && supportQ) { + // Support for Q schema is not needed for default module. + fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str()); + return 1; + } + // Collate the parameters Atoms atoms; int errorCount = collate_atoms(Atom::descriptor(), &atoms); @@ -2062,6 +659,30 @@ run(int argc, char const*const* argv) collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl, &attributionSignature); + // Write the atoms info .cpp file + if (atomsInfoCppFilename.size() != 0) { + FILE* out = fopen(atomsInfoCppFilename.c_str(), "w"); + if (out == NULL) { + fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str()); + return 1; + } + errorCount = android::stats_log_api_gen::write_atoms_info_cpp( + out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport); + fclose(out); + } + + // Write the atoms info .h file + if (atomsInfoHeaderFilename.size() != 0) { + FILE* out = fopen(atomsInfoHeaderFilename.c_str(), "w"); + if (out == NULL) { + fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoHeaderFilename.c_str()); + return 1; + } + errorCount = android::stats_log_api_gen::write_atoms_info_header(out, atoms, cppNamespace); + fclose(out); + } + + // Write the .cpp file if (cppFilename.size() != 0) { FILE* out = fopen(cppFilename.c_str(), "w"); @@ -2080,7 +701,7 @@ run(int argc, char const*const* argv) return 1; } errorCount = android::stats_log_api_gen::write_stats_log_cpp( - out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport); + out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport, supportQ); fclose(out); } @@ -2112,13 +733,25 @@ run(int argc, char const*const* argv) fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n"); return 1; } + +#if defined(STATS_SCHEMA_LEGACY) if (moduleName == DEFAULT_MODULE_NAME) { - errorCount = android::stats_log_api_gen::write_stats_log_java( + errorCount = android::stats_log_api_gen::write_stats_log_java_q( out, atoms, attributionDecl); } else { - errorCount = android::stats_log_api_gen::write_stats_log_java_for_module( + errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module( out, atoms, attributionDecl, moduleName, javaClass, javaPackage); + + } +#else + if (moduleName == DEFAULT_MODULE_NAME) { + javaClass = "StatsLogInternal"; + javaPackage = "android.util"; } + errorCount = android::stats_log_api_gen::write_stats_log_java( + out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ); +#endif + fclose(out); } @@ -2129,16 +762,22 @@ run(int argc, char const*const* argv) fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str()); return 1; } + +#if defined(STATS_SCHEMA_LEGACY) errorCount = android::stats_log_api_gen::write_stats_log_jni( out, atoms, attributionDecl); +#else + errorCount = android::stats_log_api_gen::write_stats_log_jni(out); +#endif + fclose(out); } return errorCount; } -} -} +} // namespace stats_log_api_gen +} // namespace android /** * Main. diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp new file mode 100644 index 000000000000..c7a34feff94b --- /dev/null +++ b/tools/stats_log_api_gen/native_writer.cpp @@ -0,0 +1,342 @@ +/* + * 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. + */ + +#include "native_writer.h" +#include "native_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +#if !defined(STATS_SCHEMA_LEGACY) +static void write_native_key_value_pairs_for_type(FILE* out, const int argIndex, + const int typeIndex, const string& type, const string& valueFieldName) { + fprintf(out, " for (const auto& it : arg%d_%d) {\n", argIndex, typeIndex); + fprintf(out, " pairs.push_back(" + "{ .key = it.first, .valueType = %s, .%s = it.second });\n", + type.c_str(), valueFieldName.c_str()); + fprintf(out, " }\n"); + +} + +static int write_native_stats_write_methods(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) { + fprintf(out, "\n"); + 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; + + write_native_method_signature(out, "int stats_write", signature, + attributionDecl, " {"); + + int argIndex = 1; + if (supportQ) { + fprintf(out, " StatsEventCompat event;\n"); + fprintf(out, " event.setAtomId(code);\n"); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_ATTRIBUTION_CHAIN: { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n", + uidName, uidName, tagName); + break; + } + case JAVA_TYPE_KEY_VALUE_PAIR: + fprintf(out, " event.writeKeyValuePairs(" + "arg%d_1, arg%d_2, arg%d_3, arg%d_4);\n", + argIndex, argIndex, argIndex, argIndex); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n", + argIndex, argIndex); + break; + case JAVA_TYPE_BOOLEAN: + fprintf(out, " event.writeBool(arg%d);\n", argIndex); + break; + case JAVA_TYPE_INT: // Fall through. + case JAVA_TYPE_ENUM: + fprintf(out, " event.writeInt32(arg%d);\n", argIndex); + break; + case JAVA_TYPE_FLOAT: + fprintf(out, " event.writeFloat(arg%d);\n", argIndex); + break; + case JAVA_TYPE_LONG: + fprintf(out, " event.writeInt64(arg%d);\n", argIndex); + break; + case JAVA_TYPE_STRING: + fprintf(out, " event.writeString(arg%d);\n", argIndex); + break; + default: + // Unsupported types: OBJECT, DOUBLE. + fprintf(stderr, "Encountered unsupported type."); + return 1; + } + argIndex++; + } + fprintf(out, " return event.writeToSocket();\n"); + } else { + fprintf(out, " struct stats_event* event = stats_event_obtain();\n"); + fprintf(out, " stats_event_set_atom_id(event, code);\n"); + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + switch (*arg) { + case JAVA_TYPE_ATTRIBUTION_CHAIN: { + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, + " stats_event_write_attribution_chain(event, " + "reinterpret_cast<const uint32_t*>(%s), %s.data(), " + "static_cast<uint8_t>(%s_length));\n", + uidName, tagName, uidName); + break; + } + case JAVA_TYPE_KEY_VALUE_PAIR: + fprintf(out, " std::vector<key_value_pair> pairs;\n"); + write_native_key_value_pairs_for_type( + out, argIndex, 1, "INT32_TYPE", "int32Value"); + write_native_key_value_pairs_for_type( + out, argIndex, 2, "INT64_TYPE", "int64Value"); + write_native_key_value_pairs_for_type( + out, argIndex, 3, "STRING_TYPE", "stringValue"); + write_native_key_value_pairs_for_type( + out, argIndex, 4, "FLOAT_TYPE", "floatValue"); + fprintf(out, + " stats_event_write_key_value_pairs(event, pairs.data(), " + "static_cast<uint8_t>(pairs.size()));\n"); + break; + case JAVA_TYPE_BYTE_ARRAY: + fprintf(out, + " stats_event_write_byte_array(event, " + "reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n", + argIndex, argIndex); + break; + case JAVA_TYPE_BOOLEAN: + fprintf(out, " stats_event_write_bool(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_INT: // Fall through. + case JAVA_TYPE_ENUM: + fprintf(out, " stats_event_write_int32(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_FLOAT: + fprintf(out, " stats_event_write_float(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_LONG: + fprintf(out, " stats_event_write_int64(event, arg%d);\n", argIndex); + break; + case JAVA_TYPE_STRING: + fprintf(out, " stats_event_write_string8(event, arg%d);\n", argIndex); + break; + default: + // Unsupported types: OBJECT, DOUBLE. + fprintf(stderr, "Encountered unsupported type."); + return 1; + } + argIndex++; + } + fprintf(out, " const int ret = stats_event_write(event);\n"); + fprintf(out, " stats_event_release(event);\n"); + fprintf(out, " return ret;\n"); + } + fprintf(out, "}\n\n"); + } + return 0; +} + +static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName) { + fprintf(out, "\n"); + 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; + + write_native_method_signature(out, "int stats_write_non_chained", signature, + attributionDecl, " {"); + + vector<java_type_t> newSignature; + + // First two args form the attribution node so size goes down by 1. + newSignature.reserve(signature.size() - 1); + + // First arg is Attribution Chain. + newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN); + + // Followed by the originial signature except the first 2 args. + newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end()); + + const char* uidName = attributionDecl.fields.front().name.c_str(); + const char* tagName = attributionDecl.fields.back().name.c_str(); + fprintf(out, " const int32_t* %s = &arg1;\n", uidName); + fprintf(out, " const size_t %s_length = 1;\n", uidName); + fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName); + fprintf(out, " return "); + write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2); + + fprintf(out, "}\n\n"); + } + +} +#endif + +static void write_native_method_header( + FILE* out, + const string& methodName, + 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; + write_native_method_signature(out, methodName, signature, attributionDecl, ";"); + } +} + +int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace, + const string& importHeader, const bool supportQ) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + + fprintf(out, "#include <%s>\n", importHeader.c_str()); +#if defined(STATS_SCHEMA_LEGACY) + (void)supportQ; // Workaround for unused parameter error. + write_native_cpp_includes_q(out); +#else + if (supportQ) { + fprintf(out, "#include <StatsEventCompat.h>\n"); + } else { + fprintf(out, "#include <stats_event.h>\n"); + } +#endif + + fprintf(out, "\n"); + write_namespace(out, cppNamespace); + +#if defined(STATS_SCHEMA_LEGACY) + write_native_stats_log_cpp_globals_q(out); + write_native_get_timestamp_ns_q(out); + write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName); + write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName, + "try_stats_write"); + write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName); + write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms, + attributionDecl, moduleName, "try_stats_write_non_chained"); +#else + write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ); + write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName); +#endif + + // Print footer + fprintf(out, "\n"); + write_closing_namespace(out, cppNamespace); + + return 0; +} + +int 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"); + fprintf(out, "\n"); + fprintf(out, "#pragma once\n"); + fprintf(out, "\n"); + fprintf(out, "#include <stdint.h>\n"); + fprintf(out, "#include <vector>\n"); + fprintf(out, "#include <map>\n"); + fprintf(out, "#include <set>\n"); + fprintf(out, "\n"); + + write_namespace(out, cppNamespace); + fprintf(out, "\n"); + fprintf(out, "/*\n"); + fprintf(out, " * API For logging statistics events.\n"); + fprintf(out, " */\n"); + fprintf(out, "\n"); + + write_native_atom_constants(out, atoms, attributionDecl, moduleName); + + // Print constants for the enum values. + fprintf(out, "//\n"); + fprintf(out, "// Constants for enum values\n"); + fprintf(out, "//\n\n"); + 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; + } + + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ENUM) { + fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), + field->name.c_str()); + for (map<int, string>::const_iterator value = field->enumValues.begin(); + value != field->enumValues.end(); value++) { + fprintf(out, "const int32_t %s__%s__%s = %d;\n", + make_constant_name(atom->message).c_str(), + make_constant_name(field->name).c_str(), + make_constant_name(value->second).c_str(), + value->first); + } + fprintf(out, "\n"); + } + } + } + + fprintf(out, "struct BytesField {\n"); + fprintf(out, + " BytesField(char const* array, size_t len) : arg(array), " + "arg_length(len) {}\n"); + fprintf(out, " char const* arg;\n"); + fprintf(out, " size_t arg_length;\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); + + // Print write methods + fprintf(out, "//\n"); + fprintf(out, "// Write methods\n"); + fprintf(out, "//\n"); + write_native_method_header(out, "int stats_write", atoms.signatures_to_modules, attributionDecl, + moduleName); + + fprintf(out, "//\n"); + fprintf(out, "// Write flattened methods\n"); + fprintf(out, "//\n"); + write_native_method_header(out, "int stats_write_non_chained", + atoms.non_chained_signatures_to_modules, attributionDecl, moduleName); + + fprintf(out, "\n"); + write_closing_namespace(out, cppNamespace); + + return 0; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h new file mode 100644 index 000000000000..aafa96ece2d0 --- /dev/null +++ b/tools/stats_log_api_gen/native_writer.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace, const string& importHeader, + const bool supportQ); + +int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/native_writer_q.cpp b/tools/stats_log_api_gen/native_writer_q.cpp new file mode 100644 index 000000000000..299873dad975 --- /dev/null +++ b/tools/stats_log_api_gen/native_writer_q.cpp @@ -0,0 +1,276 @@ +/* + * 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. + */ + +#include "native_writer_q.h" +#include "utils.h" + +namespace android { +namespace stats_log_api_gen { + +static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature, + const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) { + fprintf(out, "%sint ret = 0;\n", indent.c_str()); + + fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str()); + fprintf(out, "%s ret = ", indent.c_str()); + write_native_method_call(out, tryMethodName, signature, attributionDecl); + fprintf(out, "%s if (ret >= 0) { break; }\n", indent.c_str()); + + fprintf(out, "%s {\n", indent.c_str()); + fprintf(out, "%s std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str()); + fprintf(out, "%s if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= " + "kMinRetryIntervalNs) break;\n", indent.c_str()); + fprintf(out, "%s lastRetryTimestampNs = get_elapsed_realtime_ns();\n", + indent.c_str()); + fprintf(out, "%s }\n", indent.c_str()); + fprintf(out, "%s std::this_thread::sleep_for(std::chrono::milliseconds(10));\n", + indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "%sif (ret < 0) {\n", indent.c_str()); + fprintf(out, "%s note_log_drop(ret, code);\n", indent.c_str()); + fprintf(out, "%s}\n", indent.c_str()); + fprintf(out, "%sreturn ret;\n", indent.c_str()); +} + +void write_native_cpp_includes_q(FILE* out) { + 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 <time.h>\n"); +} + +void write_native_get_timestamp_ns_q(FILE* out) { + fprintf(out, "\n"); + fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n"); + fprintf(out, " struct timespec t;\n"); + fprintf(out, " t.tv_sec = t.tv_nsec = 0;\n"); + fprintf(out, " clock_gettime(CLOCK_BOOTTIME, &t);\n"); + fprintf(out, " return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n"); + fprintf(out, "}\n"); +} + +void write_native_stats_log_cpp_globals_q(FILE* out) { + 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"); + + fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); + fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); + fprintf(out, "static std::mutex mLogdRetryMutex;\n"); +} + +void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName) { + fprintf(out, "\n"); + 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; + + write_native_method_signature(out, "static int try_stats_write", signature, + attributionDecl, " {"); + + int argIndex = 1; + fprintf(out, " if (kStatsdEnabled) {\n"); + fprintf(out, " stats_event_list event(kStatsEventTag);\n"); + fprintf(out, " event << get_elapsed_realtime_ns();\n\n"); + fprintf(out, " event << code;\n\n"); + 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) { + fprintf(out, " if (%s_length != %s.size()) {\n", + attributionDecl.fields.front().name.c_str(), chainField.name.c_str()); + fprintf(out, " return -EINVAL;\n"); + fprintf(out, " }\n"); + } + } + fprintf(out, "\n event.begin();\n"); + fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n", + attributionDecl.fields.front().name.c_str()); + fprintf(out, " event.begin();\n"); + for (const auto &chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str()); + fprintf(out, " event << %s[i];\n", chainField.name.c_str()); + fprintf(out, " } else {\n"); + fprintf(out, " event << \"\";\n"); + fprintf(out, " }\n"); + } else { + fprintf(out, " event << %s[i];\n", chainField.name.c_str()); + } + } + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + fprintf(out, " event.end();\n\n"); + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, " event.begin();\n\n"); + fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + + fprintf(out, " event.end();\n\n"); + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, + " event.AppendCharArray(arg%d.arg, " + "arg%d.arg_length);\n", + argIndex, argIndex); + } else { + if (*arg == JAVA_TYPE_STRING) { + fprintf(out, " if (arg%d == NULL) {\n", argIndex); + fprintf(out, " arg%d = \"\";\n", argIndex); + fprintf(out, " }\n"); + } + fprintf(out, " event << arg%d;\n", argIndex); + } + argIndex++; + } + + fprintf(out, " return event.write(LOG_ID_STATS);\n"); + fprintf(out, " } else {\n"); + fprintf(out, " return 1;\n"); + fprintf(out, " }\n"); + fprintf(out, "}\n"); + fprintf(out, "\n"); + } + +} + +void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) { + 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; + + write_native_method_signature(out, methodName, signature, attributionDecl, " {"); + + write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName); + fprintf(out, "}\n\n"); + } +} + +void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName, + const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, + const string& tryMethodName) { + 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; + + write_native_method_signature(out, methodName, signature, attributionDecl, " {"); + + write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName); + fprintf(out, "}\n\n"); + } +} + +void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName) { + 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; + + write_native_method_signature(out, "static int try_stats_write_non_chained", signature, + attributionDecl, " {"); + + int argIndex = 1; + fprintf(out, " if (kStatsdEnabled) {\n"); + fprintf(out, " stats_event_list event(kStatsEventTag);\n"); + fprintf(out, " event << get_elapsed_realtime_ns();\n\n"); + fprintf(out, " event << code;\n\n"); + 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"); + } + if (*arg == JAVA_TYPE_STRING) { + fprintf(out, " if (arg%d == NULL) {\n", argIndex); + fprintf(out, " arg%d = \"\";\n", argIndex); + fprintf(out, " }\n"); + } + if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, + " event.AppendCharArray(arg%d.arg, " + "arg%d.arg_length);\n", + argIndex, argIndex); + } else { + fprintf(out, " event << arg%d;\n", argIndex); + } + if (argIndex == 2) { + fprintf(out, " event.end();\n\n"); + fprintf(out, " event.end();\n\n"); + } + argIndex++; + } + + fprintf(out, " return event.write(LOG_ID_STATS);\n"); + fprintf(out, " } else {\n"); + fprintf(out, " return 1;\n"); + fprintf(out, " }\n"); + fprintf(out, "}\n"); + fprintf(out, "\n"); + } +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/native_writer_q.h b/tools/stats_log_api_gen/native_writer_q.h new file mode 100644 index 000000000000..a2ab1ae5d5e2 --- /dev/null +++ b/tools/stats_log_api_gen/native_writer_q.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +void write_native_cpp_includes_q(FILE* out); + +void write_native_stats_log_cpp_globals_q(FILE* out); + +void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName); + +void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName); + +void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms, + const AtomDecl& attributionDecl, const string& moduleName); + +void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName, + const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, + const string& tryMethodName); + +void write_native_get_timestamp_ns_q(FILE* out); + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp new file mode 100644 index 000000000000..5b830eef0603 --- /dev/null +++ b/tools/stats_log_api_gen/utils.cpp @@ -0,0 +1,487 @@ +/* + * 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. + */ + +#include "utils.h" + +#include "android-base/strings.h" + +namespace android { +namespace stats_log_api_gen { + +static void build_non_chained_decl_map(const Atoms& atoms, + std::map<int, set<AtomDecl>::const_iterator>* decl_map) { + for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin(); + atom != atoms.non_chained_decls.end(); atom++) { + decl_map->insert(std::make_pair(atom->code, atom)); + } +} + +/** + * Turn lower and camel case into upper case with underscores. + */ +string make_constant_name(const string& str) { + string result; + const int N = str.size(); + bool underscore_next = false; + for (int i=0; i<N; i++) { + char c = str[i]; + if (c >= 'A' && c <= 'Z') { + if (underscore_next) { + result += '_'; + underscore_next = false; + } + } else if (c >= 'a' && c <= 'z') { + c = 'A' + c - 'a'; + underscore_next = true; + } else if (c == '_') { + underscore_next = false; + } + result += c; + } + return result; +} + +const char* cpp_type_name(java_type_t type) { + switch (type) { + case JAVA_TYPE_BOOLEAN: + return "bool"; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + return "int32_t"; + case JAVA_TYPE_LONG: + return "int64_t"; + case JAVA_TYPE_FLOAT: + return "float"; + case JAVA_TYPE_DOUBLE: + return "double"; + case JAVA_TYPE_STRING: + return "char const*"; + case JAVA_TYPE_BYTE_ARRAY: + return "const BytesField&"; + default: + return "UNKNOWN"; + } +} + +const char* java_type_name(java_type_t type) { + switch (type) { + case JAVA_TYPE_BOOLEAN: + return "boolean"; + case JAVA_TYPE_INT: + case JAVA_TYPE_ENUM: + return "int"; + case JAVA_TYPE_LONG: + return "long"; + case JAVA_TYPE_FLOAT: + return "float"; + case JAVA_TYPE_DOUBLE: + return "double"; + case JAVA_TYPE_STRING: + return "java.lang.String"; + case JAVA_TYPE_BYTE_ARRAY: + return "byte[]"; + default: + return "UNKNOWN"; + } +} + +bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return atomDecl.hasModule && (moduleName == atomDecl.moduleName); +} + +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(); +} + +// Native +// 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 void write_cpp_usage( + FILE* out, const string& method_name, const string& atom_code_name, + const AtomDecl& atom, const AtomDecl &attributionDecl) { + fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), + atom_code_name.c_str()); + + for (vector<AtomField>::const_iterator field = atom.fields.begin(); + field != atom.fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + for (auto chainField : attributionDecl.fields) { + if (chainField.javaType == JAVA_TYPE_STRING) { + fprintf(out, ", const std::vector<%s>& %s", + cpp_type_name(chainField.javaType), + chainField.name.c_str()); + } else { + fprintf(out, ", const %s* %s, size_t %s_length", + cpp_type_name(chainField.javaType), + chainField.name.c_str(), chainField.name.c_str()); + } + } + } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", const std::map<int, int32_t>& %s_int" + ", const std::map<int, int64_t>& %s_long" + ", const std::map<int, char const*>& %s_str" + ", const std::map<int, float>& %s_float", + field->name.c_str(), + field->name.c_str(), + field->name.c_str(), + field->name.c_str()); + } else { + fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); + } + } + fprintf(out, ");\n"); +} + +void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, + const string& moduleName) { + fprintf(out, "/**\n"); + fprintf(out, " * Constants for atom codes.\n"); + fprintf(out, " */\n"); + fprintf(out, "enum {\n"); + + std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; + build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); + + size_t i = 0; + // Print atom 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"); + fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str()); + write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl); + + auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); + if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { + write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second, + attributionDecl); + } + fprintf(out, " */\n"); + char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; + fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma); + i++; + } + fprintf(out, "\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); +} + +void write_native_method_signature(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, + const string& closer) { + fprintf(out, "%s(int32_t code", methodName.c_str()); + int argIndex = 1; + 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) { + fprintf(out, ", const std::vector<%s>& %s", + cpp_type_name(chainField.javaType), + chainField.name.c_str()); + } else { + fprintf(out, ", const %s* %s, size_t %s_length", + cpp_type_name(chainField.javaType), + chainField.name.c_str(), chainField.name.c_str()); + } + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " + "const std::map<int, int64_t>& arg%d_2, " + "const std::map<int, char const*>& arg%d_3, " + "const std::map<int, float>& arg%d_4", + argIndex, argIndex, argIndex, argIndex); + } else { + fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ")%s\n", closer.c_str()); +} + +void write_native_method_call(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex) { + fprintf(out, "%s(code", methodName.c_str()); + 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) { + fprintf(out, ", %s", + chainField.name.c_str()); + } else { + fprintf(out, ", %s, %s_length", + chainField.name.c_str(), chainField.name.c_str()); + } + } + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, + argIndex, argIndex, argIndex); + } else { + fprintf(out, ", arg%d", argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); +} + +// Java +void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) { + fprintf(out, " // Constants for atom codes.\n"); + + std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map; + build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); + + // Print constants for the atom codes. + 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"); + fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str()); + write_java_usage(out, "write", constant, *atom); + auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); + if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { + write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second); + } + if (moduleName == DEFAULT_MODULE_NAME) { + fprintf(out, " * @hide\n"); + } + fprintf(out, " */\n"); + fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code); + } + fprintf(out, "\n"); +} + +void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) { + fprintf(out, " // Constants for enum values.\n\n"); + 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; + } + for (vector<AtomField>::const_iterator field = atom->fields.begin(); + field != atom->fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ENUM) { + fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), + field->name.c_str()); + for (map<int, string>::const_iterator value = field->enumValues.begin(); + value != field->enumValues.end(); value++) { + if (moduleName == DEFAULT_MODULE_NAME) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static final int %s__%s__%s = %d;\n", + make_constant_name(atom->message).c_str(), + make_constant_name(field->name).c_str(), + make_constant_name(value->second).c_str(), + value->first); + } + fprintf(out, "\n"); + } + } + } +} + +void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, + const AtomDecl& atom) { + fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", + method_name.c_str(), atom_code_name.c_str()); + for (vector<AtomField>::const_iterator field = atom.fields.begin(); + field != atom.fields.end(); field++) { + if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { + fprintf(out, ", android.os.WorkSource workSource"); + } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { + fprintf(out, ", SparseArray<Object> value_map"); + } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", byte[] %s", field->name.c_str()); + } else { + fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str()); + } + } + fprintf(out, ");<br>\n"); +} + +int write_java_non_chained_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + 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; + } + + // Print method signature. + if (DEFAULT_MODULE_NAME == moduleName) { + fprintf(out, " /** @hide */\n"); + } + fprintf(out, " public static void write_non_chained(int code"); + vector<java_type_t> signature = signature_to_modules_it->first; + int argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + // Non chained signatures should not have attribution chains. + return 1; + } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { + // Module logging does not yet support key value pair. + return 1; + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + fprintf(out, " write(code"); + argIndex = 1; + for (vector<java_type_t>::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { + // First two args are uid and tag of attribution chain. + if (argIndex == 1) { + fprintf(out, ", new int[] {arg%d}", argIndex); + } else if (argIndex == 2) { + fprintf(out, ", new java.lang.String[] {arg%d}", argIndex); + } else { + fprintf(out, ", arg%d", argIndex); + } + argIndex++; + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); + fprintf(out, "\n"); + } + return 0; +} + +int write_java_work_source_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const string& moduleName + ) { + fprintf(out, " // WorkSource methods.\n"); + 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; + // 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++) { + argIndexMax++; + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + if (attributionArg > -1) { + fprintf(stderr, "An atom contains multiple AttributionNode fields.\n"); + fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n"); + fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n"); + return 1; + } + attributionArg = argIndexMax; + } + } + if (attributionArg < 0) { + continue; + } + + fprintf(out, "\n"); + // Method header (signature) + if (DEFAULT_MODULE_NAME == moduleName) { + 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++) { + if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { + fprintf(out, ", WorkSource ws"); + } else { + fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); + } + argIndex++; + } + fprintf(out, ") {\n"); + + // write_non_chained() component. TODO: Remove when flat uids are no longer needed. + fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n"); + fprintf(out, " write_non_chained(code"); + for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { + if (argIndex == attributionArg) { + fprintf(out, ", ws.get(i), ws.getName(i)"); + } else { + fprintf(out, ", arg%d", argIndex); + } + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); // close for-loop + + // write() component. + fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n"); + fprintf(out, " if (workChains != null) {\n"); + fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n"); + fprintf(out, " write(code"); + for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { + if (argIndex == attributionArg) { + fprintf(out, ", wc.getUids(), wc.getTags()"); + } else { + fprintf(out, ", arg%d", argIndex); + } + } + fprintf(out, ");\n"); + fprintf(out, " }\n"); // close for-loop + fprintf(out, " }\n"); // close if + fprintf(out, " }\n"); // close method + } + return 0; +} + +} // namespace stats_log_api_gen +} // namespace android diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h new file mode 100644 index 000000000000..50737a68bf89 --- /dev/null +++ b/tools/stats_log_api_gen/utils.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#pragma once + +#include "Collation.h" + +#include <map> +#include <set> +#include <vector> + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace stats_log_api_gen { + +using namespace std; + +const string DEFAULT_MODULE_NAME = "DEFAULT"; +const string DEFAULT_CPP_NAMESPACE = "android,util"; +const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; +const string DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT = "atoms_info.h"; +const string DEFAULT_JAVA_PACKAGE = "android.util"; +const string DEFAULT_JAVA_CLASS = "StatsLogInternal"; + +const int JAVA_MODULE_REQUIRES_FLOAT = 0x01; +const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02; + +string make_constant_name(const string& str); + +const char* cpp_type_name(java_type_t type); + +const char* java_type_name(java_type_t type); + +bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName); + +bool signature_needed_for_module(const set<string>& modules, const string& moduleName); + +// Common Native helpers +void write_namespace(FILE* out, const string& cppNamespaces); + +void write_closing_namespace(FILE* out, const string& cppNamespaces); + +void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, + const string& moduleName); + +void write_native_method_signature(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, + const string& closer); + +void write_native_method_call(FILE* out, const string& methodName, + const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex = 1); + +// Common Java helpers. +void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName); + +void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName); + +void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, + const AtomDecl& atom); + +int write_java_non_chained_methods(FILE* out, const map<vector<java_type_t>, + set<string>>& signatures_to_modules, + const string& moduleName); + +int write_java_work_source_methods( + FILE* out, + const map<vector<java_type_t>, set<string>>& signatures_to_modules, + const string& moduleName); + +} // namespace stats_log_api_gen +} // namespace android |